Reformat codebase v4 (#2872)

Reformat code base to PSR12

Co-authored-by: rssbridge <noreply@github.com>
This commit is contained in:
Dag 2022-07-01 15:10:30 +02:00 committed by GitHub
parent 66568e3a39
commit 4f75591060
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
398 changed files with 58607 additions and 56442 deletions

View file

@ -1,4 +1,5 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
@ -25,8 +26,8 @@ class ConnectivityAction implements ActionInterface
{
public $userData = [];
public function execute() {
public function execute()
{
if (!Debug::isEnabled()) {
returnError('This action is only available in debug mode!', 400);
}
@ -39,7 +40,6 @@ class ConnectivityAction implements ActionInterface
$bridgeName = $this->userData['bridge'];
$this->reportBridgeConnectivity($bridgeName);
}
/**
@ -55,8 +55,8 @@ class ConnectivityAction implements ActionInterface
* @param string $bridgeName Name of the bridge to generate the report for
* @return void
*/
private function reportBridgeConnectivity($bridgeName) {
private function reportBridgeConnectivity($bridgeName)
{
$bridgeFac = new \BridgeFactory();
if (!$bridgeFac->isWhitelisted($bridgeName)) {
@ -66,11 +66,11 @@ class ConnectivityAction implements ActionInterface
header('Content-Type: text/json');
$retVal = array(
$retVal = [
'bridge' => $bridgeName,
'successful' => false,
'http_code' => 200,
);
];
$bridge = $bridgeFac->create($bridgeName);
@ -79,12 +79,12 @@ class ConnectivityAction implements ActionInterface
return;
}
$curl_opts = array(
$curl_opts = [
CURLOPT_CONNECTTIMEOUT => 5
);
];
try {
$reply = getContents($bridge::URI, array(), $curl_opts, true);
$reply = getContents($bridge::URI, [], $curl_opts, true);
if ($reply['code'] === 200) {
$retVal['successful'] = true;
@ -97,10 +97,10 @@ class ConnectivityAction implements ActionInterface
}
echo json_encode($retVal);
}
private function returnEntryPage() {
private function returnEntryPage()
{
echo <<<EOD
<!DOCTYPE html>

View file

@ -1,4 +1,5 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
@ -15,7 +16,8 @@ class DetectAction implements ActionInterface
{
public $userData = [];
public function execute() {
public function execute()
{
$targetURL = $this->userData['url']
or returnClientError('You must specify a url!');
@ -25,7 +27,6 @@ class DetectAction implements ActionInterface
$bridgeFac = new \BridgeFactory();
foreach ($bridgeFac->getBridgeNames() as $bridgeName) {
if (!$bridgeFac->isWhitelisted($bridgeName)) {
continue;
}
@ -47,7 +48,6 @@ class DetectAction implements ActionInterface
header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301);
die();
}
returnClientError('No bridge found for given URL: ' . $targetURL);

View file

@ -1,4 +1,5 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
@ -15,7 +16,8 @@ class DisplayAction implements ActionInterface
{
public $userData = [];
private function getReturnCode($error) {
private function getReturnCode($error)
{
$returnCode = $error->getCode();
if ($returnCode === 301 || $returnCode === 302) {
# Don't pass redirect codes to the exterior
@ -24,7 +26,8 @@ class DisplayAction implements ActionInterface
return $returnCode;
}
public function execute() {
public function execute()
{
$bridge = array_key_exists('bridge', $this->userData) ? $this->userData['bridge'] : null;
$format = $this->userData['format']
@ -52,7 +55,6 @@ class DisplayAction implements ActionInterface
// Cache timeout
$cache_timeout = -1;
if (array_key_exists('_cache_timeout', $this->userData)) {
if (!CUSTOM_CACHE_TIMEOUT) {
unset($this->userData['_cache_timeout']);
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) . '?' . http_build_query($this->userData);
@ -61,7 +63,6 @@ class DisplayAction implements ActionInterface
}
$cache_timeout = filter_var($this->userData['_cache_timeout'], FILTER_VALIDATE_INT);
} else {
$cache_timeout = $bridge->getCacheTimeout();
}
@ -70,27 +71,31 @@ class DisplayAction implements ActionInterface
$bridge_params = array_diff_key(
$this->userData,
array_fill_keys(
array(
[
'action',
'bridge',
'format',
'_noproxy',
'_cache_timeout',
'_error_time'
), '')
],
''
)
);
// Remove parameters that don't concern caches
$cache_params = array_diff_key(
$this->userData,
array_fill_keys(
array(
[
'action',
'format',
'_noproxy',
'_cache_timeout',
'_error_time'
), '')
],
''
)
);
// Initialize cache
@ -101,14 +106,15 @@ class DisplayAction implements ActionInterface
$cache->purgeCache(86400); // 24 hours
$cache->setKey($cache_params);
$items = array();
$infos = array();
$items = [];
$infos = [];
$mtime = $cache->getTime();
if($mtime !== false
if (
$mtime !== false
&& (time() - $cache_timeout < $mtime)
&& !Debug::isEnabled()) { // Load cached data
&& !Debug::isEnabled()
) { // Load cached data
// Send "Not Modified" response if client supports it
// Implementation based on https://stackoverflow.com/a/10847262
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
@ -129,9 +135,7 @@ class DisplayAction implements ActionInterface
$infos = $cached['extraInfos'];
}
} else { // Collect new data
try {
$bridge->setDatas($bridge_params);
$bridge->collectData();
@ -141,7 +145,7 @@ class DisplayAction implements ActionInterface
// Transform "legacy" items to FeedItems if necessary.
// Remove this code when support for "legacy" items ends!
if (isset($items[0]) && is_array($items[0])) {
$feedItems = array();
$feedItems = [];
foreach ($items as $item) {
$feedItems[] = new \FeedItem($item);
@ -150,12 +154,12 @@ class DisplayAction implements ActionInterface
$items = $feedItems;
}
$infos = array(
$infos = [
'name' => $bridge->getName(),
'uri' => $bridge->getURI(),
'donationUri' => $bridge->getDonationURI(),
'icon' => $bridge->getIcon()
);
];
} catch (\Throwable $e) {
error_log($e);
@ -191,11 +195,12 @@ class DisplayAction implements ActionInterface
}
// Store data in cache
$cache->saveData(array(
'items' => array_map(function($i){ return $i->toArray(); }, $items),
$cache->saveData([
'items' => array_map(function ($i) {
return $i->toArray();
}, $items),
'extraInfos' => $infos
));
]);
}
// Data transformation

View file

@ -1,4 +1,5 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
@ -13,30 +14,28 @@
class ListAction implements ActionInterface
{
public function execute() {
public function execute()
{
$list = new StdClass();
$list->bridges = array();
$list->bridges = [];
$list->total = 0;
$bridgeFac = new \BridgeFactory();
foreach ($bridgeFac->getBridgeNames() as $bridgeName) {
$bridge = $bridgeFac->create($bridgeName);
if ($bridge === false) { // Broken bridge, show as inactive
$list->bridges[$bridgeName] = array(
$list->bridges[$bridgeName] = [
'status' => 'inactive'
);
];
continue;
}
$status = $bridgeFac->isWhitelisted($bridgeName) ? 'active' : 'inactive';
$list->bridges[$bridgeName] = array(
$list->bridges[$bridgeName] = [
'status' => $status,
'uri' => $bridge->getURI(),
'donationUri' => $bridge->getDonationURI(),
@ -45,8 +44,7 @@ class ListAction implements ActionInterface
'parameters' => $bridge->getParameters(),
'maintainer' => $bridge->getMaintainer(),
'description' => $bridge->getDescription()
);
];
}
$list->total = count($list->bridges);

View file

@ -1,17 +1,19 @@
<?php
class ABCNewsBridge extends BridgeAbstract {
class ABCNewsBridge extends BridgeAbstract
{
const NAME = 'ABC News Bridge';
const URI = 'https://www.abc.net.au';
const DESCRIPTION = 'Topics of the Australian Broadcasting Corporation';
const MAINTAINER = 'yue-dongchen';
const PARAMETERS = array(
array(
'topic' => array(
const PARAMETERS = [
[
'topic' => [
'type' => 'list',
'name' => 'Region',
'title' => 'Choose state',
'values' => array(
'values' => [
'ACT' => 'act',
'NSW' => 'nsw',
'NT' => 'nt',
@ -20,18 +22,19 @@ class ABCNewsBridge extends BridgeAbstract {
'TAS' => 'tas',
'VIC' => 'vic',
'WA' => 'wa'
),
)
)
);
],
]
]
];
public function collectData() {
public function collectData()
{
$url = 'https://www.abc.net.au/news/' . $this->getInput('topic');
$html = getSimpleHTMLDOM($url)->find('.YAJzu._2FvRw.ZWhbj._3BZxh', 0);
$html = defaultLinkTo($html, $this->getURI());
foreach ($html->find('._2H7Su') as $article) {
$item = array();
$item = [];
$title = $article->find('._3T9Id.fmhNa.nsZdE._2c2Zy._1tOey._3EOTW', 0);
$item['title'] = $title->plaintext;

View file

@ -1,49 +1,53 @@
<?php
class AO3Bridge extends BridgeAbstract {
class AO3Bridge extends BridgeAbstract
{
const NAME = 'AO3';
const URI = 'https://archiveofourown.org/';
const CACHE_TIMEOUT = 1800;
const DESCRIPTION = 'Returns works or chapters from Archive of Our Own';
const MAINTAINER = 'Obsidienne';
const PARAMETERS = array(
'List' => array(
'url' => array(
const PARAMETERS = [
'List' => [
'url' => [
'name' => 'url',
'required' => true,
// Example: F/F tag, complete works only
'exampleValue' => 'https://archiveofourown.org/works?work_search[complete]=T&tag_id=F*s*F',
),
),
'Bookmarks' => array(
'user' => array(
],
],
'Bookmarks' => [
'user' => [
'name' => 'user',
'required' => true,
// Example: Nyaaru's bookmarks
'exampleValue' => 'Nyaaru',
),
),
'Work' => array(
'id' => array(
],
],
'Work' => [
'id' => [
'name' => 'id',
'required' => true,
// Example: latest chapters from A Better Past by LysSerris
'exampleValue' => '18181853',
),
)
);
],
]
];
// Feed for lists of works (e.g. recent works, search results, filtered tags,
// bookmarks, series, collections).
private function collectList($url) {
private function collectList($url)
{
$html = getSimpleHTMLDOM($url);
$html = defaultLinkTo($html, self::URI);
foreach ($html->find('.index.group > li') as $element) {
$item = array();
$item = [];
$title = $element->find('div h4 a', 0);
if (!isset($title)) continue; // discard deleted works
if (!isset($title)) {
continue; // discard deleted works
}
$item['title'] = $title->plaintext;
$item['content'] = $element;
$item['uri'] = $title->href;
@ -61,7 +65,8 @@ class AO3Bridge extends BridgeAbstract {
}
// Feed for recent chapters of a specific work.
private function collectWork($id) {
private function collectWork($id)
{
$url = self::URI . "/works/$id/navigate";
$html = getSimpleHTMLDOM($url);
$html = defaultLinkTo($html, self::URI);
@ -69,7 +74,7 @@ class AO3Bridge extends BridgeAbstract {
$this->title = $html->find('h2 a', 0)->plaintext;
foreach ($html->find('ol.index.group > li') as $element) {
$item = array();
$item = [];
$item['title'] = $element->find('a', 0)->plaintext;
$item['content'] = $element;
@ -88,7 +93,8 @@ class AO3Bridge extends BridgeAbstract {
$this->items = array_reverse($this->items);
}
public function collectData() {
public function collectData()
{
switch ($this->queriedContext) {
case 'Bookmarks':
$user = $this->getInput('user');
@ -97,22 +103,28 @@ class AO3Bridge extends BridgeAbstract {
. '/users/' . $user
. '/bookmarks?bookmark_search[sort_column]=bookmarkable_date';
return $this->collectList($url);
case 'List': return $this->collectList(
case 'List':
return $this->collectList(
$this->getInput('url')
);
case 'Work': return $this->collectWork(
case 'Work':
return $this->collectWork(
$this->getInput('id')
);
}
}
public function getName() {
public function getName()
{
$name = parent::getName() . " $this->queriedContext";
if (isset($this->title)) $name .= " - $this->title";
if (isset($this->title)) {
$name .= " - $this->title";
}
return $name;
}
public function getIcon() {
public function getIcon()
{
return self::URI . '/favicon.ico';
}
}

View file

@ -1,5 +1,7 @@
<?php
class ARDMediathekBridge extends BridgeAbstract {
class ARDMediathekBridge extends BridgeAbstract
{
const NAME = 'ARD-Mediathek Bridge';
const URI = 'https://www.ardmediathek.de';
const DESCRIPTION = 'Feed of any series in the ARD-Mediathek, specified by its path';
@ -39,18 +41,19 @@ class ARDMediathekBridge extends BridgeAbstract {
*/
const IMAGEWIDTHPLACEHOLDER = '{width}';
const PARAMETERS = array(
array(
'path' => array(
const PARAMETERS = [
[
'path' => [
'name' => 'Show Link or ID',
'required' => true,
'title' => 'Link to the show page or just its alphanumeric suffix',
'defaultValue' => 'https://www.ardmediathek.de/sendung/45-min/Y3JpZDovL25kci5kZS8xMzkx/'
)
)
);
]
]
];
public function collectData() {
public function collectData()
{
$oldTz = date_default_timezone_get();
date_default_timezone_set('Europe/Berlin');
@ -69,20 +72,20 @@ class ARDMediathekBridge extends BridgeAbstract {
}
}
$url = SELF::APIENDPOINT . $showID . '/?pageSize=' . SELF::PAGESIZE;
$url = self::APIENDPOINT . $showID . '/?pageSize=' . self::PAGESIZE;
$rawJSON = getContents($url);
$processedJSON = json_decode($rawJSON);
foreach ($processedJSON->teasers as $video) {
$item = array();
$item = [];
// there is also ->links->self->id, ->links->self->urlId, ->links->target->id, ->links->target->urlId
$item['uri'] = SELF::VIDEOLINKPREFIX . $video->id . '/';
$item['uri'] = self::VIDEOLINKPREFIX . $video->id . '/';
// there is also ->mediumTitle and ->shortTitle
$item['title'] = $video->longTitle;
// in the test, aspect16x9 was the only child of images, not sure whether that is always true
$item['enclosures'] = array(
str_replace(SELF::IMAGEWIDTHPLACEHOLDER, SELF::IMAGEWIDTH, $video->images->aspect16x9->src)
);
$item['enclosures'] = [
str_replace(self::IMAGEWIDTHPLACEHOLDER, self::IMAGEWIDTH, $video->images->aspect16x9->src)
];
$item['content'] = '<img src="' . $item['enclosures'][0] . '" /><p>';
$item['timestamp'] = $video->broadcastedOn;
$item['uid'] = $video->id;

View file

@ -1,21 +1,23 @@
<?php
class ASRockNewsBridge extends BridgeAbstract {
class ASRockNewsBridge extends BridgeAbstract
{
const NAME = 'ASRock News Bridge';
const URI = 'https://www.asrock.com';
const DESCRIPTION = 'Returns latest news articles';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array();
const PARAMETERS = [];
const CACHE_TIMEOUT = 3600; // 1 hour
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI . '/news/index.asp');
$html = defaultLinkTo($html, self::URI . '/news/');
foreach ($html->find('div.inner > a') as $index => $a) {
$item = array();
$item = [];
$articlePath = $a->href;
@ -41,7 +43,8 @@ class ASRockNewsBridge extends BridgeAbstract {
}
}
private function extractDate($text) {
private function extractDate($text)
{
$dateRegex = '/^([0-9]{4}\/[0-9]{1,2}\/[0-9]{1,2})/';
$text = trim($text);

View file

@ -1,6 +1,7 @@
<?php
class AcrimedBridge extends FeedExpander {
class AcrimedBridge extends FeedExpander
{
const MAINTAINER = 'qwertygc';
const NAME = 'Acrimed Bridge';
const URI = 'https://www.acrimed.org/';
@ -17,14 +18,16 @@ class AcrimedBridge extends FeedExpander {
]
];
public function collectData(){
public function collectData()
{
$this->collectExpandableDatas(
static::URI . 'spip.php?page=backend',
$this->getInput('limit')
);
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
$item = parent::parseItem($newsItem);
$articlePage = getSimpleHTMLDOM($newsItem->link);

View file

@ -1,16 +1,17 @@
<?php
class AirBreizhBridge extends BridgeAbstract {
class AirBreizhBridge extends BridgeAbstract
{
const MAINTAINER = 'fanch317';
const NAME = 'Air Breizh';
const URI = 'https://www.airbreizh.asso.fr/';
const DESCRIPTION = 'Returns newests publications on Air Breizh';
const PARAMETERS = array(
'Publications' => array(
'theme' => array(
const PARAMETERS = [
'Publications' => [
'theme' => [
'name' => 'Thematique',
'type' => 'list',
'values' => array(
'values' => [
'Tout' => '',
'Rapport d\'activite' => 'rapport-dactivite',
'Etude' => 'etudes',
@ -18,22 +19,24 @@ class AirBreizhBridge extends BridgeAbstract {
'Autres documents' => 'autres-documents',
'Plan Régional de Surveillance de la qualité de lair' => 'prsqa',
'Transport' => 'transport'
)
)
)
);
]
]
]
];
public function getIcon() {
public function getIcon()
{
return 'https://www.airbreizh.asso.fr/voy_content/uploads/2017/11/favicon.png';
}
public function collectData(){
public function collectData()
{
$html = '';
$html = getSimpleHTMLDOM(static::URI . 'publications/?fwp_publications_thematiques=' . $this->getInput('theme'))
or returnClientError('No results for this query.');
foreach ($html->find('article') as $article) {
$item = array();
$item = [];
// Title
$item['title'] = $article->find('h2', 0)->plaintext;
// Author

View file

@ -1,24 +1,25 @@
<?php
class AlbionOnlineBridge extends BridgeAbstract {
class AlbionOnlineBridge extends BridgeAbstract
{
const NAME = 'Albion Online Changelog';
const MAINTAINER = 'otakuf';
const URI = 'https://albiononline.com';
const DESCRIPTION = 'Returns the changes made to the Albion Online';
const CACHE_TIMEOUT = 3600; // 60min
const PARAMETERS = array( array(
'postcount' => array(
const PARAMETERS = [ [
'postcount' => [
'name' => 'Limit',
'type' => 'number',
'required' => true,
'title' => 'Maximum number of items to return',
'defaultValue' => 5,
),
'language' => array(
],
'language' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'English' => 'en',
'Deutsch' => 'de',
'Polski' => 'pl',
@ -26,19 +27,20 @@ class AlbionOnlineBridge extends BridgeAbstract {
'Русский' => 'ru',
'Português' => 'pt',
'Español' => 'es',
),
],
'title' => 'Language of changelog posts',
'defaultValue' => 'en',
),
'full' => array(
],
'full' => [
'name' => 'Full changelog',
'type' => 'checkbox',
'required' => false,
'title' => 'Enable to receive the full changelog post for each item'
),
));
],
]];
public function collectData() {
public function collectData()
{
$api = 'https://albiononline.com/';
// Example: https://albiononline.com/en/changelog/1/5
$url = $api . $this->getInput('language') . '/changelog/1/' . $this->getInput('postcount');
@ -46,7 +48,7 @@ class AlbionOnlineBridge extends BridgeAbstract {
$html = getSimpleHTMLDOM($url);
foreach ($html->find('li') as $data) {
$item = array();
$item = [];
$item['uri'] = self::URI . $data->find('a', 0)->getAttribute('href');
$item['title'] = trim(explode('|', $data->find('span', 0)->plaintext)[0]);
// Time below work only with en lang. Need to think about solution. May be separate request like getFullChangelog, but to english list for all language
@ -65,7 +67,8 @@ class AlbionOnlineBridge extends BridgeAbstract {
}
}
private function getFullChangelog($url) {
private function getFullChangelog($url)
{
$html = getSimpleHTMLDOMCached($url);
$html = defaultLinkTo($html, self::URI);
return $html->find('div.small-12.columns', 1)->innertext;

View file

@ -1,33 +1,35 @@
<?php
class AlfaBankByBridge extends BridgeAbstract {
class AlfaBankByBridge extends BridgeAbstract
{
const MAINTAINER = 'lassana';
const NAME = 'AlfaBank.by Новости';
const URI = 'https://www.alfabank.by';
const DESCRIPTION = 'Уведомления Alfa-Now — новости от Альфа-Банка';
const CACHE_TIMEOUT = 3600; // 1 hour
const PARAMETERS = array(
'News' => array(
'business' => array(
const PARAMETERS = [
'News' => [
'business' => [
'name' => 'Альфа Бизнес',
'type' => 'list',
'title' => 'В зависимости от выбора, возращает уведомления для" .
" клиентов физ. лиц либо для клиентов-юридических лиц и ИП',
'values' => array(
'values' => [
'Новости' => 'news',
'Новости бизнеса' => 'newsBusiness'
),
],
'defaultValue' => 'news'
),
'fullContent' => array(
],
'fullContent' => [
'name' => 'Включать содержимое',
'type' => 'checkbox',
'title' => 'Если выбрано, содержимое уведомлений вставляется в поток (работает медленно)'
)
)
);
]
]
];
public function collectData() {
public function collectData()
{
$business = $this->getInput('business') == 'newsBusiness';
$fullContent = $this->getInput('fullContent') == 'on';
@ -40,7 +42,7 @@ class AlfaBankByBridge extends BridgeAbstract {
foreach ($html->find('a.notifications__item') as $element) {
if ($limit < 10) {
$item = array();
$item = [];
$item['uid'] = 'urn:sha1:' . hash('sha1', $element->getAttribute('data-notification-id'));
$item['title'] = $element->find('div.item-title', 0)->innertext;
$item['timestamp'] = DateTime::createFromFormat(
@ -67,17 +69,19 @@ class AlfaBankByBridge extends BridgeAbstract {
}
}
public function getIcon() {
public function getIcon()
{
return static::URI . '/local/images/favicon.ico';
}
private function ruMonthsToEn($date) {
$ruMonths = array(
private function ruMonthsToEn($date)
{
$ruMonths = [
'Января', 'Февраля', 'Марта', 'Апреля', 'Мая', 'Июня',
'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря' );
$enMonths = array(
'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря' ];
$enMonths = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December' );
'July', 'August', 'September', 'October', 'November', 'December' ];
return str_replace($ruMonths, $enMonths, $date);
}
}

View file

@ -1,17 +1,18 @@
<?php
class AllocineFRBridge extends BridgeAbstract {
class AllocineFRBridge extends BridgeAbstract
{
const MAINTAINER = 'superbaillot.net';
const NAME = 'Allo Cine Bridge';
const CACHE_TIMEOUT = 25200; // 7h
const URI = 'https://www.allocine.fr';
const DESCRIPTION = 'Bridge for allocine.fr';
const PARAMETERS = array( array(
'category' => array(
const PARAMETERS = [ [
'category' => [
'name' => 'Emission',
'type' => 'list',
'title' => 'Sélectionner l\'emission',
'values' => array(
'values' => [
'Faux Raccord' => 'faux-raccord',
'Fanzone' => 'fanzone',
'Game In Ciné' => 'game-in-cine',
@ -27,14 +28,14 @@ class AllocineFRBridge extends BridgeAbstract {
'Complètement...' => 'completement',
'#Fun Facts' => 'fun-facts',
'Origin Story' => 'origin-story',
)
)
));
]
]
]];
public function getURI(){
public function getURI()
{
if (!is_null($this->getInput('category'))) {
$categories = array(
$categories = [
'faux-raccord' => '/video/programme-12284/',
'fanzone' => '/video/programme-12298/',
'game-in-cine' => '/video/programme-12288/',
@ -50,7 +51,7 @@ class AllocineFRBridge extends BridgeAbstract {
'completement' => '/video/programme-23859/',
'fun-facts' => '/video/programme-23040/',
'origin-story' => '/video/programme-25667/'
);
];
$category = $this->getInput('category');
if (array_key_exists($category, $categories)) {
@ -71,7 +72,8 @@ class AllocineFRBridge extends BridgeAbstract {
return $URI;
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('category'))) {
return self::NAME . ' : '
. array_search(
@ -83,8 +85,8 @@ class AllocineFRBridge extends BridgeAbstract {
return parent::getName();
}
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI());
$category = array_search(
@ -92,7 +94,7 @@ class AllocineFRBridge extends BridgeAbstract {
self::PARAMETERS[$this->queriedContext]['category']['values']
);
foreach ($html->find('div[class=gd-col-left]', 0)->find('div[class*=video-card]') as $element) {
$item = array();
$item = [];
$title = $element->find('a[class*=meta-title-link]', 0);
$content = trim(defaultLinkTo($element->outertext, static::URI));

View file

@ -1,35 +1,35 @@
<?php
class AmazonBridge extends BridgeAbstract {
class AmazonBridge extends BridgeAbstract
{
const MAINTAINER = 'Alexis CHEMEL';
const NAME = 'Amazon';
const URI = 'https://www.amazon.com/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Returns products from Amazon search';
const PARAMETERS = array(array(
'q' => array(
const PARAMETERS = [[
'q' => [
'name' => 'Keyword',
'required' => true,
'exampleValue' => 'watch',
),
'sort' => array(
],
'sort' => [
'name' => 'Sort by',
'type' => 'list',
'values' => array(
'values' => [
'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(
],
'tld' => [
'name' => 'Country',
'type' => 'list',
'values' => array(
'values' => [
'Australia' => 'com.au',
'Brazil' => 'com.br',
'Canada' => 'ca',
@ -46,13 +46,13 @@ class AmazonBridge extends BridgeAbstract {
'Turkey' => 'com.tr',
'United Kingdom' => 'co.uk',
'United States' => 'com',
),
],
'defaultValue' => 'com',
),
));
public function collectData() {
],
]];
public function collectData()
{
$baseUrl = sprintf('https://www.amazon.%s', $this->getInput('tld'));
$url = sprintf(
@ -93,7 +93,8 @@ class AmazonBridge extends BridgeAbstract {
}
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('tld')) && !is_null($this->getInput('q'))) {
return 'Amazon.' . $this->getInput('tld') . ': ' . $this->getInput('q');
}

View file

@ -1,25 +1,26 @@
<?php
class AmazonPriceTrackerBridge extends BridgeAbstract {
class AmazonPriceTrackerBridge extends BridgeAbstract
{
const MAINTAINER = 'captn3m0, sal0max';
const NAME = 'Amazon Price Tracker';
const URI = 'https://www.amazon.com/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Tracks price for a single product on Amazon';
const PARAMETERS = array(
array(
'asin' => array(
const PARAMETERS = [
[
'asin' => [
'name' => 'ASIN',
'required' => true,
'exampleValue' => 'B071GB1VMQ',
// https://stackoverflow.com/a/12827734
'pattern' => 'B[\dA-Z]{9}|\d{9}(X|\d)',
),
'tld' => array(
],
'tld' => [
'name' => 'Country',
'type' => 'list',
'values' => array(
'values' => [
'Australia' => 'com.au',
'Brazil' => 'com.br',
'Canada' => 'ca',
@ -36,19 +37,19 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
'Turkey' => 'com.tr',
'United Kingdom' => 'co.uk',
'United States' => 'com',
),
],
'defaultValue' => 'com',
),
));
],
]];
const PRICE_SELECTORS = array(
const PRICE_SELECTORS = [
'#priceblock_ourprice',
'.priceBlockBuyingPriceString',
'#newBuyBoxPrice',
'#tp_price_block_total_price_ww',
'span.offer-price',
'.a-color-price',
);
];
const WHITESPACE = " \t\n\r\0\x0B\xC2\xA0";
@ -57,14 +58,16 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
/**
* Generates domain name given a amazon TLD
*/
private function getDomainName() {
private function getDomainName()
{
return 'https://www.amazon.' . $this->getInput('tld');
}
/**
* Generates URI for a Amazon product page
*/
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('asin'))) {
return $this->getDomainName() . '/dp/' . $this->getInput('asin');
}
@ -75,7 +78,8 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
* Scrapes the product title from the html page
* returns the default title if scraping fails
*/
private function getTitle($html) {
private function getTitle($html)
{
$titleTag = $html->find('#productTitle', 0);
if (!$titleTag) {
@ -88,7 +92,8 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
/**
* Title used by the feed if none could be found
*/
private function getDefaultTitle() {
private function getDefaultTitle()
{
return 'Amazon.' . $this->getInput('tld') . ': ' . $this->getInput('asin');
}
@ -96,7 +101,8 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
* Returns name for the feed
* Uses title (already scraped) if it has one
*/
public function getName() {
public function getName()
{
if (isset($this->title)) {
return $this->title;
} else {
@ -104,7 +110,8 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
}
}
private function parseDynamicImage($attribute) {
private function parseDynamicImage($attribute)
{
$json = json_decode(html_entity_decode($attribute), true);
if ($json and count($json) > 0) {
@ -115,7 +122,8 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
/**
* Returns a generated image tag for the product
*/
private function getImage($html) {
private function getImage($html)
{
$imageSrc = $html->find('#main-image-container img', 0);
if ($imageSrc) {
@ -134,46 +142,50 @@ EOT;
* Return \simple_html_dom object
* for the entire html of the product page
*/
private function getHtml() {
private function getHtml()
{
$uri = $this->getURI();
return getSimpleHTMLDOM($uri) ?: returnServerError('Could not request Amazon.');
}
private function scrapePriceFromMetrics($html) {
private function scrapePriceFromMetrics($html)
{
$asinData = $html->find('#cerberus-data-metrics', 0);
// <div id="cerberus-data-metrics" style="display: none;"
// data-asin="B00WTHJ5SU" data-asin-price="14.99" data-asin-shipping="0"
// data-asin-currency-code="USD" data-substitute-count="-1" ... />
if ($asinData) {
return array(
return [
'price' => $asinData->getAttribute('data-asin-price'),
'currency' => $asinData->getAttribute('data-asin-currency-code'),
'shipping' => $asinData->getAttribute('data-asin-shipping')
);
];
}
return false;
}
private function scrapePriceTwister($html) {
private function scrapePriceTwister($html)
{
$str = $html->find('.twister-plus-buying-options-price-data', 0);
$data = json_decode($str->innertext, true);
if (count($data) === 1) {
$data = $data[0];
return array(
return [
'displayPrice' => $data['displayPrice'],
'currency' => $data['currency'],
'shipping' => '0',
);
];
}
return false;
}
private function scrapePriceGeneric($html) {
private function scrapePriceGeneric($html)
{
$priceDiv = null;
foreach (self::PRICE_SELECTORS as $sel) {
@ -194,17 +206,18 @@ EOT;
$currency = str_replace($price, '', $priceString);
if ($price != null && $currency != null) {
return array(
return [
'price' => $price,
'currency' => $currency,
'shipping' => '0'
);
];
}
return false;
}
private function renderContent($image, $data) {
private function renderContent($image, $data)
{
$price = $data['displayPrice'];
if (!$price) {
$price = "{$data['price']} {$data['currency']}";
@ -223,20 +236,21 @@ EOT;
* Scrape method for Amazon product page
* @return [type] [description]
*/
public function collectData() {
public function collectData()
{
$html = $this->getHtml();
$this->title = $this->getTitle($html);
$imageTag = $this->getImage($html);
$data = $this->scrapePriceGeneric($html);
$item = array(
$item = [
'title' => $this->title,
'uri' => $this->getURI(),
'content' => $this->renderContent($imageTag, $data),
// This is to ensure that feed readers notice the price change
'uid' => md5($data['price'])
);
];
$this->items[] = $item;
}

View file

@ -1,18 +1,19 @@
<?php
class AnidexBridge extends BridgeAbstract {
class AnidexBridge extends BridgeAbstract
{
const MAINTAINER = 'ORelio';
const NAME = 'Anidex';
const URI = 'http://anidex.info/'; // anidex.info has ddos-guard so we need to use anidex.moe
const ALTERNATE_URI = 'https://anidex.moe/'; // anidex.moe returns 301 unless Host is set to anidex.info
const ALTERNATE_HOST = 'anidex.info'; // Correct host for requesting anidex.moe without 301 redirect
const DESCRIPTION = 'Returns the newest torrents, with optional search criteria.';
const PARAMETERS = array(
array(
'id' => array(
const PARAMETERS = [
[
'id' => [
'name' => 'Category',
'type' => 'list',
'values' => array(
'values' => [
'All categories' => '0',
'Anime' => '1,2,3',
'Anime - Sub' => '1',
@ -34,12 +35,12 @@ class AnidexBridge extends BridgeAbstract {
'Pictures' => '14',
'Adult Video' => '15',
'Other' => '16'
)
),
'lang_id' => array(
]
],
'lang_id' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'All languages' => '0',
'English' => '1',
'Japanese' => '2',
@ -72,52 +73,52 @@ class AnidexBridge extends BridgeAbstract {
'Spanish (LATAM)' => '29',
'Persian' => '30',
'Malaysian' => '31'
)
),
'group_id' => array(
]
],
'group_id' => [
'name' => 'Group ID',
'type' => 'number'
),
'r' => array(
],
'r' => [
'name' => 'Hide Remakes',
'type' => 'checkbox'
),
'b' => array(
],
'b' => [
'name' => 'Only Batches',
'type' => 'checkbox'
),
'a' => array(
],
'a' => [
'name' => 'Only Authorized',
'type' => 'checkbox'
),
'q' => array(
],
'q' => [
'name' => 'Keyword',
'description' => 'Keyword(s)',
'type' => 'text'
),
'h' => array(
],
'h' => [
'name' => 'Adult content',
'type' => 'list',
'values' => array(
'values' => [
'No filter' => '0',
'Hide +18' => '1',
'Only +18' => '2'
)
)
)
);
public function collectData() {
]
]
]
];
public function collectData()
{
// Build Search URL from user-provided parameters
$search_url = self::ALTERNATE_URI . '?s=upload_timestamp&o=desc';
foreach (array('id', 'lang_id', 'group_id') as $param_name) {
foreach (['id', 'lang_id', 'group_id'] as $param_name) {
$param = $this->getInput($param_name);
if (!empty($param) && intval($param) != 0 && ctype_digit(str_replace(',', '', $param))) {
$search_url .= '&' . $param_name . '=' . $param;
}
}
foreach (array('r', 'b', 'a') as $param_name) {
foreach (['r', 'b', 'a'] as $param_name) {
$param = $this->getInput($param_name);
if (!empty($param) && boolval($param)) {
$search_url .= '&' . $param_name . '=1';
@ -127,14 +128,14 @@ class AnidexBridge extends BridgeAbstract {
if (!empty($query)) {
$search_url .= '&q=' . urlencode($query);
}
$opt = array();
$opt = [];
$h = $this->getInput('h');
if (!empty($h) && intval($h) != 0 && ctype_digit($h)) {
$opt[CURLOPT_COOKIE] = 'anidex_h_toggle=' . $h;
}
// We need to use a different Host HTTP header to reach the correct page on ALTERNATE_URI
$headers = array('Host: ' . self::ALTERNATE_HOST);
$headers = ['Host: ' . self::ALTERNATE_HOST];
// The HTTPS certificate presented by anidex.moe is for anidex.info. We need to ignore this.
// As a consequence, the bridge is intentionally marked as insecure by setting self::URI to http://
@ -144,16 +145,18 @@ class AnidexBridge extends BridgeAbstract {
// Retrieve torrent listing from search results, which does not contain torrent description
$html = getSimpleHTMLDOM($search_url, $headers, $opt);
$links = $html->find('a');
$results = array();
foreach ($links as $link)
if (strpos($link->href, '/torrent/') === 0 && !in_array($link->href, $results))
$results = [];
foreach ($links as $link) {
if (strpos($link->href, '/torrent/') === 0 && !in_array($link->href, $results)) {
$results[] = $link->href;
if (empty($results) && empty($this->getInput('q')))
}
}
if (empty($results) && empty($this->getInput('q'))) {
returnServerError('No results from Anidex: ' . $search_url);
}
//Process each item individually
foreach ($results as $element) {
//Limit total amount of requests
if (count($this->items) >= 20) {
break;
@ -163,14 +166,12 @@ class AnidexBridge extends BridgeAbstract {
//Ignore entries without valid torrent ID
if ($torrent_id != 0 && ctype_digit($torrent_id)) {
//Retrieve data for this torrent ID
$item_browse_uri = self::URI . 'torrent/' . $torrent_id;
$item_fetch_uri = self::ALTERNATE_URI . 'torrent/' . $torrent_id;
//Retrieve full description from torrent page (cached for 24 hours: 86400 seconds)
if ($item_html = getSimpleHTMLDOMCached($item_fetch_uri, 86400, $headers, $opt)) {
//Retrieve data from page contents
$item_title = str_replace(' (Torrent) - AniDex ', '', $item_html->find('title', 0)->plaintext);
$item_desc = $item_html->find('div.panel-body', 0);
@ -200,12 +201,12 @@ class AnidexBridge extends BridgeAbstract {
}
//Build and add final item
$item = array();
$item = [];
$item['uri'] = $item_browse_uri;
$item['title'] = $item_title;
$item['author'] = $item_author;
$item['timestamp'] = $item_date;
$item['enclosures'] = array($item_image);
$item['enclosures'] = [$item_image];
$item['content'] = $item_desc;
$this->items[] = $item;
}

View file

@ -1,28 +1,29 @@
<?php
class AnimeUltimeBridge extends BridgeAbstract {
class AnimeUltimeBridge extends BridgeAbstract
{
const MAINTAINER = 'ORelio';
const NAME = 'Anime-Ultime';
const URI = 'http://www.anime-ultime.net/';
const CACHE_TIMEOUT = 10800; // 3h
const DESCRIPTION = 'Returns the newest releases posted on Anime-Ultime.';
const PARAMETERS = array( array(
'type' => array(
const PARAMETERS = [ [
'type' => [
'name' => 'Type',
'type' => 'list',
'values' => array(
'values' => [
'Everything' => '',
'Anime' => 'A',
'Drama' => 'D',
'Tokusatsu' => 'T'
)
)
));
]
]
]];
private $filter = 'Releases';
public function collectData(){
public function collectData()
{
//Add type filter if provided
$typeFilter = array_search(
$this->getInput('type'),
@ -35,8 +36,7 @@ class AnimeUltimeBridge extends BridgeAbstract {
//Process each HTML page until having 10 releases
$processedOK = 0;
foreach (array($thismonth, $lastmonth) as $requestFilter) {
foreach ([$thismonth, $lastmonth] as $requestFilter) {
$url = self::URI . 'history-0-1/' . $requestFilter;
$html = getContents($url);
// Convert html from iso-8859-1 => utf8
@ -45,7 +45,6 @@ class AnimeUltimeBridge extends BridgeAbstract {
//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));
@ -61,7 +60,6 @@ class AnimeUltimeBridge extends BridgeAbstract {
//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;
@ -86,7 +84,6 @@ class AnimeUltimeBridge extends BridgeAbstract {
$item_type = $release->find('td', 4)->plaintext;
if (!empty($item_uri)) {
// Retrieve description from description page
$html_item = getContents($item_uri);
// Convert html from iso-8859-1 => utf8
@ -95,7 +92,8 @@ class AnimeUltimeBridge extends BridgeAbstract {
$html_item,
strpos($html_item, 'class="principal_contain" align="center">') + 41
);
$item_description = substr($item_description,
$item_description = substr(
$item_description,
0,
strpos($item_description, '<div id="table">')
);
@ -106,18 +104,18 @@ class AnimeUltimeBridge extends BridgeAbstract {
$item_description = str_replace("\n", '', $item_description);
//Build and add final item
$item = array();
$item = [];
$item['uri'] = $item_uri;
$item['title'] = $item_name . ' ' . $item_type . ' ' . $item_episode;
$item['author'] = $item_fansub;
$item['timestamp'] = $item_date;
$item['enclosures'] = array($item_image);
$item['enclosures'] = [$item_image];
$item['content'] = $item_description;
$this->items[] = $item;
$processedOK++;
//Stop processing once limit is reached
if ($processedOK >= 10)
if ($processedOK >= 10) {
return;
}
}
@ -125,8 +123,10 @@ class AnimeUltimeBridge extends BridgeAbstract {
}
}
}
}
public function getName() {
public function getName()
{
if (!is_null($this->getInput('type'))) {
$typeFilter = array_search(
$this->getInput('type'),

View file

@ -1,23 +1,23 @@
<?php
class AppleAppStoreBridge extends BridgeAbstract {
class AppleAppStoreBridge extends BridgeAbstract
{
const MAINTAINER = 'captn3m0';
const NAME = 'Apple App Store';
const URI = 'https://apps.apple.com/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Returns version updates for a specific application';
const PARAMETERS = array(array(
'id' => array(
const PARAMETERS = [[
'id' => [
'name' => 'Application ID',
'required' => true,
'exampleValue' => '310633997'
),
'p' => array(
],
'p' => [
'name' => 'Platform',
'type' => 'list',
'values' => array(
'values' => [
'iPad' => 'ipad',
'iPhone' => 'iphone',
'Mac' => 'mac',
@ -26,36 +26,39 @@ class AppleAppStoreBridge extends BridgeAbstract {
// but not yet tested
'Web' => 'web',
'Apple TV' => 'appletv',
),
],
'defaultValue' => 'iphone',
),
'country' => array(
],
'country' => [
'name' => 'Store Country',
'type' => 'list',
'values' => array(
'values' => [
'US' => 'US',
'India' => 'IN',
'Canada' => 'CA',
'Germany' => 'DE',
),
],
'defaultValue' => 'US',
),
));
],
]];
const PLATFORM_MAPPING = array(
const PLATFORM_MAPPING = [
'iphone' => 'ios',
'ipad' => 'ios',
);
];
private function makeHtmlUrl($id, $country){
private function makeHtmlUrl($id, $country)
{
return 'https://apps.apple.com/' . $country . '/app/id' . $id;
}
private function makeJsonUrl($id, $platform, $country){
private function makeJsonUrl($id, $platform, $country)
{
return "https://amp-api.apps.apple.com/v1/catalog/$country/apps/$id?platform=$platform&extend=versionHistory";
}
public function getName(){
public function getName()
{
if (isset($this->name)) {
return $this->name . ' - AppStore Updates';
}
@ -66,7 +69,8 @@ class AppleAppStoreBridge extends BridgeAbstract {
/**
* In case of some platforms, the data is present in the initial response
*/
private function getDataFromShoebox($id, $platform, $country){
private function getDataFromShoebox($id, $platform, $country)
{
$uri = $this->makeHtmlUrl($id, $country);
$html = getSimpleHTMLDOMCached($uri, 3600);
$script = $html->find('script[id="shoebox-ember-data-store"]', 0);
@ -75,7 +79,8 @@ class AppleAppStoreBridge extends BridgeAbstract {
return $json['data'];
}
private function getJWTToken($id, $platform, $country){
private function getJWTToken($id, $platform, $country)
{
$uri = $this->makeHtmlUrl($id, $country);
$html = getSimpleHTMLDOMCached($uri, 3600);
@ -89,13 +94,14 @@ class AppleAppStoreBridge extends BridgeAbstract {
return $json->MEDIA_API->token;
}
private function getAppData($id, $platform, $country, $token){
private function getAppData($id, $platform, $country, $token)
{
$uri = $this->makeJsonUrl($id, $platform, $country);
$headers = array(
$headers = [
"Authorization: Bearer $token",
'Origin: https://apps.apple.com',
);
];
$json = json_decode(getContents($uri, $headers), true);
@ -106,7 +112,8 @@ class AppleAppStoreBridge extends BridgeAbstract {
* Parses the version history from the data received
* @return array list of versions with details on each element
*/
private function getVersionHistory($data, $platform){
private function getVersionHistory($data, $platform)
{
switch ($platform) {
case 'mac':
return $data['relationships']['platforms']['data'][0]['attributes']['versionHistory'];
@ -116,7 +123,8 @@ class AppleAppStoreBridge extends BridgeAbstract {
}
}
public function collectData() {
public function collectData()
{
$id = $this->getInput('id');
$country = $this->getInput('country');
$platform = $this->getInput('p');
@ -136,7 +144,7 @@ class AppleAppStoreBridge extends BridgeAbstract {
$author = $data['attributes']['artistName'];
foreach ($versionHistory as $row) {
$item = array();
$item = [];
$item['content'] = nl2br($row['releaseNotes']);
$item['title'] = $name . ' - ' . $row['versionDisplay'];

View file

@ -1,25 +1,27 @@
<?php
class AppleMusicBridge extends BridgeAbstract {
class AppleMusicBridge extends BridgeAbstract
{
const NAME = 'Apple Music';
const URI = 'https://www.apple.com';
const DESCRIPTION = 'Fetches the latest releases from an artist';
const MAINTAINER = 'bockiii';
const PARAMETERS = array(array(
'artist' => array(
const PARAMETERS = [[
'artist' => [
'name' => 'Artist ID',
'exampleValue' => '909253',
'required' => true,
),
'limit' => array(
],
'limit' => [
'name' => 'Latest X Releases (max 50)',
'defaultValue' => '10',
'required' => true,
),
));
],
]];
const CACHE_TIMEOUT = 21600; // 6 hours
public function collectData() {
public function collectData()
{
# Limit the amount of releases to 50
if ($this->getInput('limit') > 50) {
$limit = 50;
@ -38,7 +40,7 @@ class AppleMusicBridge extends BridgeAbstract {
foreach ($json->results as $obj) {
if ($obj->wrapperType === 'collection') {
$this->items[] = array(
$this->items[] = [
'title' => $obj->artistName . ' - ' . $obj->collectionName,
'uri' => $obj->collectionViewUrl,
'timestamp' => $obj->releaseDate,
@ -48,7 +50,7 @@ class AppleMusicBridge extends BridgeAbstract {
. $obj->artistName . ' - ' . $obj->collectionName
. '<br>'
. $obj->copyright,
);
];
}
}
}

View file

@ -1,56 +1,63 @@
<?php
class ArtStationBridge extends BridgeAbstract {
class ArtStationBridge extends BridgeAbstract
{
const NAME = 'ArtStation';
const URI = 'https://www.artstation.com';
const DESCRIPTION = 'Fetches the latest ten artworks from a search query on ArtStation.';
const MAINTAINER = 'thefranke';
const CACHE_TIMEOUT = 3600; // 1h
const PARAMETERS = array(
'Search Query' => array(
'q' => array(
const PARAMETERS = [
'Search Query' => [
'q' => [
'name' => 'Search term',
'required' => true,
'exampleValue' => 'bird'
)
)
);
]
]
];
public function getIcon() {
public function getIcon()
{
return 'https://www.artstation.com/assets/favicon-58653022bc38c1905ac7aa1b10bffa6b.ico';
}
public function getName() {
public function getName()
{
return self::NAME . ': ' . $this->getInput('q');
}
private function fetchSearch($searchQuery) {
private function fetchSearch($searchQuery)
{
$data = '{"query":"' . $searchQuery . '","page":1,"per_page":50,"sorting":"date",';
$data .= '"pro_first":"1","filters":[],"additional_fields":[]}';
$header = array(
$header = [
'Content-Type: application/json',
'Accept: application/json'
);
];
$opts = array(
$opts = [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
CURLOPT_RETURNTRANSFER => true
);
];
$jsonSearchURL = self::URI . '/api/v2/search/projects.json';
$jsonSearchStr = getContents($jsonSearchURL, $header, $opts);
return json_decode($jsonSearchStr);
}
private function fetchProject($hashID) {
private function fetchProject($hashID)
{
$jsonProjectURL = self::URI . '/projects/' . $hashID . '.json';
$jsonProjectStr = getContents($jsonProjectURL);
return json_decode($jsonProjectStr);
}
public function collectData() {
public function collectData()
{
$searchTerm = $this->getInput('q');
$jsonQuery = $this->fetchSearch($searchTerm);
@ -59,7 +66,7 @@ class ArtStationBridge extends BridgeAbstract {
$jsonProject = $this->fetchProject($media->hash_id);
// create item
$item = array();
$item = [];
$item['title'] = $media->title;
$item['uri'] = $media->url;
$item['timestamp'] = strtotime($jsonProject->published_at);
@ -76,17 +83,19 @@ class ArtStationBridge extends BridgeAbstract {
$numAssets = count($jsonProject->assets);
if ($numAssets > 1)
if ($numAssets > 1) {
$item['content'] .= '<p><a href="'
. $media->url
. '">Project contains '
. ($numAssets - 1)
. ' more item(s).</a></p>';
}
$this->items[] = $item;
if (count($this->items) >= 10)
if (count($this->items) >= 10) {
break;
}
}
}
}

View file

@ -1,6 +1,7 @@
<?php
class Arte7Bridge extends BridgeAbstract {
class Arte7Bridge extends BridgeAbstract
{
const NAME = 'Arte +7';
const URI = 'https://www.arte.tv/';
const MAINTAINER = 'imagoiq';
@ -9,14 +10,14 @@ class Arte7Bridge extends BridgeAbstract {
const API_TOKEN = 'Nzc1Yjc1ZjJkYjk1NWFhN2I2MWEwMmRlMzAzNjI5NmU3NWU3ODg4ODJjOWMxNTMxYzEzZGRjYjg2ZGE4MmIwOA';
const PARAMETERS = array(
const PARAMETERS = [
'global' => [
'sort_by' => array(
'sort_by' => [
'type' => 'list',
'name' => 'Sort by',
'required' => false,
'defaultValue' => null,
'values' => array(
'values' => [
'Default' => null,
'Video rights start date' => 'videoRightsBegin',
'Video rights end date' => 'videoRightsEnd',
@ -27,18 +28,18 @@ class Arte7Bridge extends BridgeAbstract {
'Number of views per period' => 'viewsPeriod',
'Available screens' => 'availableScreens',
'Episode' => 'episode'
),
),
'sort_direction' => array(
],
],
'sort_direction' => [
'type' => 'list',
'name' => 'Sort direction',
'required' => false,
'defaultValue' => 'DESC',
'values' => array(
'values' => [
'Ascending' => 'ASC',
'Descending' => 'DESC'
),
),
],
],
'exclude_trailers' => [
'name' => 'Exclude trailers',
'type' => 'checkbox',
@ -46,23 +47,23 @@ class Arte7Bridge extends BridgeAbstract {
'defaultValue' => false
],
],
'Category' => array(
'lang' => array(
'Category' => [
'lang' => [
'type' => 'list',
'name' => 'Language',
'values' => array(
'values' => [
'Français' => 'fr',
'Deutsch' => 'de',
'English' => 'en',
'Español' => 'es',
'Polski' => 'pl',
'Italiano' => 'it'
),
),
'cat' => array(
],
],
'cat' => [
'type' => 'list',
'name' => 'Category',
'values' => array(
'values' => [
'All videos' => null,
'News & society' => 'ACT',
'Series & fiction' => 'SER',
@ -73,32 +74,33 @@ class Arte7Bridge extends BridgeAbstract {
'History' => 'HIST',
'Science' => 'SCI',
'Other' => 'AUT'
)
),
),
'Collection' => array(
'lang' => array(
]
],
],
'Collection' => [
'lang' => [
'type' => 'list',
'name' => 'Language',
'values' => array(
'values' => [
'Français' => 'fr',
'Deutsch' => 'de',
'English' => 'en',
'Español' => 'es',
'Polski' => 'pl',
'Italiano' => 'it'
)
),
'col' => array(
]
],
'col' => [
'name' => 'Collection id',
'required' => true,
'title' => 'ex. RC-014095 pour https://www.arte.tv/de/videos/RC-014095/blow-up/',
'exampleValue' => 'RC-014095'
)
)
);
]
]
];
public function collectData(){
public function collectData()
{
switch ($this->queriedContext) {
case 'Category':
$category = $this->getInput('cat');
@ -120,9 +122,9 @@ class Arte7Bridge extends BridgeAbstract {
. ($category != null ? '&category.code=' . $category : '')
. ($collectionId != null ? '&collections.collectionId=' . $collectionId : '');
$header = array(
$header = [
'Authorization: Bearer ' . self::API_TOKEN
);
];
$input = getContents($url, $header);
$input_json = json_decode($input, true);
@ -134,15 +136,16 @@ class Arte7Bridge extends BridgeAbstract {
$durationSeconds = $element['durationSeconds'];
$item = array();
$item = [];
$item['uri'] = $element['url'];
$item['id'] = $element['id'];
$item['timestamp'] = strtotime($element['videoRightsBegin']);
$item['title'] = $element['title'];
if(!empty($element['subtitle']))
if (!empty($element['subtitle'])) {
$item['title'] = $element['title'] . ' | ' . $element['subtitle'];
}
$durationMinutes = round((int)$durationSeconds / 60);
$item['content'] = $element['teaserText']

View file

@ -1,16 +1,18 @@
<?php
class AsahiShimbunAJWBridge extends BridgeAbstract {
class AsahiShimbunAJWBridge extends BridgeAbstract
{
const NAME = 'Asahi Shimbun AJW';
const BASE_URI = 'http://www.asahi.com';
const URI = self::BASE_URI . '/ajw/';
const DESCRIPTION = 'Asahi Shimbun - Asia & Japan Watch';
const MAINTAINER = 'somini';
const PARAMETERS = array(
array(
'section' => array(
const PARAMETERS = [
[
'section' => [
'type' => 'list',
'name' => 'Section',
'values' => array(
'values' => [
'Japan » Social Affairs' => 'japan/social',
'Japan » People' => 'japan/people',
'Japan » 3/11 Disaster' => 'japan/0311disaster',
@ -26,17 +28,19 @@ class AsahiShimbunAJWBridge extends BridgeAbstract {
'Asia » World' => 'asia_world/world',
'Opinion » Editorial' => 'opinion/editorial',
'Opinion » Vox Populi' => 'opinion/vox',
),
],
'defaultValue' => 'politics',
)
)
);
]
]
];
private function getSectionURI($section) {
private function getSectionURI($section)
{
return self::getURI() . $section . '/';
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getSectionURI($this->getInput('section')));
foreach ($html->find('#MainInner li a') as $element) {
@ -44,7 +48,7 @@ class AsahiShimbunAJWBridge extends BridgeAbstract {
Debug::log('Skip Headline, it is repeated below');
continue;
}
$item = array();
$item = [];
$item['uri'] = self::BASE_URI . $element->href;
$e_lead = $element->find('span.Lead', 0);

View file

@ -1,33 +1,36 @@
<?php
class AskfmBridge extends BridgeAbstract {
class AskfmBridge extends BridgeAbstract
{
const MAINTAINER = 'az5he6ch, logmanoriginal';
const NAME = 'Ask.fm Answers';
const URI = 'https://ask.fm/';
const CACHE_TIMEOUT = 300; //5 min
const DESCRIPTION = 'Returns answers from an Ask.fm user';
const PARAMETERS = array(
'Ask.fm username' => array(
'u' => array(
const PARAMETERS = [
'Ask.fm username' => [
'u' => [
'name' => 'Username',
'required' => true,
'exampleValue' => 'ApprovedAndReal'
)
)
);
]
]
];
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI());
$html = defaultLinkTo($html, self::URI);
foreach ($html->find('article.streamItem-answer') as $element) {
$item = array();
$item = [];
$item['uri'] = $element->find('a.streamItem_meta', 0)->href;
$question = trim($element->find('header.streamItem_header', 0)->innertext);
$item['title'] = trim(
htmlspecialchars_decode($element->find('header.streamItem_header', 0)->plaintext,
htmlspecialchars_decode(
$element->find('header.streamItem_header', 0)->plaintext,
ENT_QUOTES
)
);
@ -56,7 +59,8 @@ class AskfmBridge extends BridgeAbstract {
}
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('u'))) {
return self::NAME . ' : ' . $this->getInput('u');
}
@ -64,7 +68,8 @@ class AskfmBridge extends BridgeAbstract {
return parent::getName();
}
public function getURI(){
public function getURI()
{
if (!is_null($this->getInput('u'))) {
return self::URI . urlencode($this->getInput('u'));
}

View file

@ -1,15 +1,17 @@
<?php
class AssociatedPressNewsBridge extends BridgeAbstract {
class AssociatedPressNewsBridge extends BridgeAbstract
{
const NAME = 'Associated Press News Bridge';
const URI = 'https://apnews.com/';
const DESCRIPTION = 'Returns newest articles by topic';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(
'Standard Topics' => array(
'topic' => array(
const PARAMETERS = [
'Standard Topics' => [
'topic' => [
'name' => 'Topic',
'type' => 'list',
'values' => array(
'values' => [
'AP Top News' => 'apf-topnews',
'Sports' => 'apf-sports',
'Entertainment' => 'apf-entertainment',
@ -27,19 +29,19 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
'Photo Galleries' => 'PhotoGalleries',
'Fact Checks' => 'APFactCheck',
'Videos' => 'apf-videos',
),
],
'defaultValue' => 'apf-topnews',
),
),
'Custom Topic' => array(
'topic' => array(
],
],
'Custom Topic' => [
'topic' => [
'name' => 'Topic',
'type' => 'text',
'required' => true,
'exampleValue' => 'europe'
),
)
);
],
]
];
const CACHE_TIMEOUT = 900; // 15 mins
@ -47,8 +49,9 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
private $tagEndpoint = 'https://afs-prod.appspot.com/api/v2/feed/tag?tags=';
private $feedName = '';
public function detectParameters($url) {
$params = array();
public function detectParameters($url)
{
$params = [];
if (preg_match($this->detectParamRegex, $url, $matches) > 0) {
$params['topic'] = $matches[1];
@ -59,7 +62,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
return null;
}
public function collectData() {
public function collectData()
{
switch ($this->getInput('topic')) {
case 'Podcasts':
returnClientError('Podcasts topic feed is not supported');
@ -72,7 +76,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('topic'))) {
return self::URI . $this->getInput('topic');
}
@ -80,7 +85,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName() {
public function getName()
{
if (!empty($this->feedName)) {
return $this->feedName . ' - Associated Press';
}
@ -88,7 +94,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
return parent::getName();
}
private function getTagURI() {
private function getTagURI()
{
if (!is_null($this->getInput('topic'))) {
return $this->tagEndpoint . $this->getInput('topic');
}
@ -96,7 +103,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
return parent::getURI();
}
private function collectCardData() {
private function collectCardData()
{
$json = getContents($this->getTagURI())
or returnServerError('Could not request: ' . $this->getTagURI());
@ -109,7 +117,7 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
$this->feedName = $tagContents['tagObjs'][0]['name'];
foreach ($tagContents['cards'] as $card) {
$item = array();
$item = [];
// skip hub peeks & Notifications
if ($card['cardType'] == 'Hub Peek' || $card['cardType'] == 'Notification') {
@ -178,8 +186,8 @@ class AssociatedPressNewsBridge extends BridgeAbstract {
}
}
private function processMediaPlaceholders($html, $id) {
private function processMediaPlaceholders($html, $id)
{
if ($html->find('div.media-placeholder', 0)) {
// Fetch page content
$json = getContents('https://afs-prod.appspot.com/api/v2/content/' . $id);
@ -216,11 +224,10 @@ EOD;
/*
Create full coverage links (HubLinks)
*/
private function processHubLinks($html, $storyContent) {
private function processHubLinks($html, $storyContent)
{
if (!empty($storyContent['richEmbeds'])) {
foreach ($storyContent['richEmbeds'] as $embed) {
if ($embed['type'] === 'Hub Link') {
$url = self::URI . $embed['tag']['id'];
$div = $html->find('div[id=' . $embed['id'] . ']', 0);
@ -235,7 +242,8 @@ EOD;
}
}
private function processVideo($storyContent) {
private function processVideo($storyContent)
{
$video = $storyContent['media'][0];
if ($video['type'] === 'YouTube') {
@ -255,8 +263,8 @@ EOD;
}
// Remove datawrapper.dwcdn.net iframes and related javaScript
private function processIframes($html) {
private function processIframes($html)
{
foreach ($html->find('iframe') as $index => $iframe) {
if (preg_match('/datawrapper\.dwcdn\.net/', $iframe->src)) {
$iframe->outertext = '';

View file

@ -1,42 +1,47 @@
<?php
class AstrophysicsDataSystemBridge extends BridgeAbstract {
class AstrophysicsDataSystemBridge extends BridgeAbstract
{
const NAME = 'SAO/NASA Astrophysics Data System';
const DESCRIPTION = 'Returns the latest publications from a query';
const URI = 'https://ui.adsabs.harvard.edu';
const PARAMETERS = array(
'Publications' => array(
'query' => array(
const PARAMETERS = [
'Publications' => [
'query' => [
'name' => 'query',
'title' => 'Same format as the search bar on the website',
'exampleValue' => 'author:"huchra, john"',
'required' => true
)
));
]
]];
private $feedTitle;
public function getName() {
public function getName()
{
if ($this->queriedContext === 'Publications') {
return $this->feedTitle;
}
return parent::getName();
}
public function getURI() {
public function getURI()
{
if ($this->queriedContext === 'Publications') {
return self::URI . '/search/?q=' . urlencode($this->getInput('query'));
}
return parent::getURI();
}
public function collectData() {
$headers = array (
public function collectData()
{
$headers = [
'Cookie: core=always;'
);
];
$html = str_get_html(defaultLinkTo(getContents($this->getURI(), $headers), self::URI));
$this->feedTitle = html_entity_decode($html->find('title', 0)->plaintext);
foreach ($html->find('div.row > ul > li') as $pub) {
$item = array();
$item = [];
$item['title'] = $pub->find('h3.s-results-title', 0)->plaintext;
$item['content'] = $pub->find('div.s-results-links', 0);
$item['uri'] = $pub->find('a.abs-redirect-link', 0)->href;

View file

@ -1,22 +1,24 @@
<?php
class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
class AtmoNouvelleAquitaineBridge extends BridgeAbstract
{
const NAME = '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(
const PARAMETERS = [[
'cities' => [
'name' => 'Choisir une ville',
'type' => 'list',
'values' => self::CITIES
)
));
]
]];
const CACHE_TIMEOUT = 7200;
private $dom;
private function getClosest($search, $arr) {
private function getClosest($search, $arr)
{
$closest = null;
foreach ($arr as $key => $value) {
if ($closest === null || abs((int)$search - $closest) > abs((int)$key - (int)$search)) {
@ -26,7 +28,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $arr[$closest];
}
public function collectData() {
public function collectData()
{
$uri = self::URI . '/monair/commune/' . $this->getInput('cities');
$html = getSimpleHTMLDOM($uri);
@ -47,7 +50,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
$this->items[] = $item;
}
private function getIndex() {
private function getIndex()
{
$index = $this->dom->find('.indice', 0)->innertext;
if ($index == 'XX') {
@ -57,12 +61,14 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $index;
}
private function getMaxIndexText() {
private function getMaxIndexText()
{
// will return '/100'
return $this->dom->find('.pourcent', 0)->innertext;
}
private function getQualityText($index, $indexes) {
private function getQualityText($index, $indexes)
{
if ($index == -1) {
if (array_key_exists('no-available', $indexes)) {
return $indexes['no-available'];
@ -74,9 +80,10 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $this->getClosest($index, $indexes);
}
private function getLegendIndexes() {
private function getLegendIndexes()
{
$rawIndexes = $this->dom->find('.prevision-legend .prevision-legend-label');
$indexes = array();
$indexes = [];
for ($i = 0; $i < count($rawIndexes); $i++) {
if ($rawIndexes[$i]->hasAttribute('data-color')) {
$indexes[$rawIndexes[$i]->getAttribute('data-color')] = $rawIndexes[$i]->innertext;
@ -86,7 +93,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $indexes;
}
private function getTomorrowTrendIndex() {
private function getTomorrowTrendIndex()
{
$tomorrowTrendDomNode = $this->dom
->find('.day-controls.raster-controls .list-raster-controls .raster-control', 2);
$tomorrowTrendIndexNode = null;
@ -104,7 +112,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $tomorrowTrendIndex;
}
private function getTomorrowTrendQualityText($trendIndex, $indexes) {
private function getTomorrowTrendQualityText($trendIndex, $indexes)
{
if ($trendIndex == -1) {
if (array_key_exists('no-available', $indexes)) {
return $indexes['no-available'];
@ -116,7 +125,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return $this->getClosest($trendIndex, $indexes);
}
private function getIndexMessage() {
private function getIndexMessage()
{
$index = $this->getIndex();
$maxIndexText = $this->getMaxIndexText();
@ -127,7 +137,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return "L'indice d'aujourd'hui est $index$maxIndexText.";
}
private function getQualityMessage() {
private function getQualityMessage()
{
$index = $index = $this->getIndex();
$indexes = $this->getLegendIndexes();
$quality = $this->getQualityText($index, $indexes);
@ -139,7 +150,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return "La qualité de l'air est $quality.";
}
private function getTomorrowTrendIndexMessage() {
private function getTomorrowTrendIndexMessage()
{
$trendIndex = $this->getTomorrowTrendIndex();
$maxIndexText = $this->getMaxIndexText();
@ -150,7 +162,8 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return "L'indice prévu pour demain est $trendIndex$maxIndexText.";
}
private function getTomorrowTrendQualityMessage() {
private function getTomorrowTrendQualityMessage()
{
$trendIndex = $this->getTomorrowTrendIndex();
$indexes = $this->getLegendIndexes();
$trendQuality = $this->getTomorrowTrendQualityText($trendIndex, $indexes);
@ -161,7 +174,7 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
return "La qualite de l'air pour demain sera $trendQuality.";
}
const CITIES = array(
const CITIES = [
'Aast (64460)' => '64001',
'Abère (64160)' => '64002',
'Abidos (64150)' => '64003',
@ -4633,5 +4646,5 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
'Yvrac (33370)' => '33554',
'Yvrac-et-Malleyrand (16110)' => '16425',
'Yzosse (40180)' => '40334'
);
];
}

View file

@ -1,20 +1,22 @@
<?php
class AtmoOccitanieBridge extends BridgeAbstract {
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(
const PARAMETERS = [[
'city' => [
'name' => 'Ville',
'required' => true,
'exampleValue' => 'cahors'
)
));
]
]];
const CACHE_TIMEOUT = 7200;
public function collectData() {
public function collectData()
{
$uri = self::URI . $this->getInput('city');
$html = getSimpleHTMLDOM($uri);

View file

@ -1,29 +1,31 @@
<?php
class AutoJMBridge extends BridgeAbstract {
class AutoJMBridge extends BridgeAbstract
{
const NAME = 'AutoJM';
const URI = 'https://www.autojm.fr/';
const DESCRIPTION = 'Suivre les offres de véhicules proposés par AutoJM en fonction des critères de filtrages';
const MAINTAINER = 'sysadminstory';
const PARAMETERS = array(
'Afficher les offres de véhicules disponible sur la recheche AutoJM' => array(
'url' => array(
const PARAMETERS = [
'Afficher les offres de véhicules disponible sur la recheche AutoJM' => [
'url' => [
'name' => 'URL de la page de recherche',
'type' => 'text',
'required' => true,
'title' => 'URL d\'une recherche avec filtre de véhicules sans le http://www.autojm.fr/',
'exampleValue' => 'recherche?brands[]=peugeot&ranges[]=peugeot-nouvelle-308-2021-5p'
),
)
);
],
]
];
const CACHE_TIMEOUT = 3600;
public function getIcon() {
public function getIcon()
{
return self::URI . 'favicon.ico';
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'Afficher les offres de véhicules disponible sur la recheche AutoJM':
return 'AutoJM | Recherche de véhicules';
@ -31,18 +33,17 @@ class AutoJMBridge extends BridgeAbstract {
default:
return parent::getName();
}
}
public function collectData() {
public function collectData()
{
// Get the number of result for this search
$search_url = self::URI . $this->getInput('url') . '&open=energy&onlyFilters=false';
// Set the header 'X-Requested-With' like the website does it
$header = array(
$header = [
'X-Requested-With: XMLHttpRequest'
);
];
// Get the JSON content of the form
$json = getContents($search_url, $header);
@ -61,7 +62,6 @@ class AutoJMBridge extends BridgeAbstract {
// Go through every car of the search
$list = $html->find('div[class*=card-car card-car--listing]');
foreach ($list as $car) {
// Get the info about the car offer
$image = $car->find('div[class=card-car__header__img]', 0)->find('img', 0)->src;
// Decode HTML attribute JSON data
@ -97,7 +97,7 @@ class AutoJMBridge extends BridgeAbstract {
}
// Construct the new item
$item = array();
$item = [];
$item['title'] = $car_model;
$item['content'] = '<p><img style="vertical-align:middle ; padding: 10px" src="' . $image . '" />'
. $car_model . '</p>';

View file

@ -1,5 +1,7 @@
<?php
class AwwwardsBridge extends BridgeAbstract {
class AwwwardsBridge extends BridgeAbstract
{
const NAME = 'Awwwards';
const URI = 'https://www.awwwards.com/';
const DESCRIPTION = 'Fetches the latest ten sites of the day from Awwwards';
@ -10,31 +12,37 @@ class AwwwardsBridge extends BridgeAbstract {
const SITEURI = 'https://www.awwwards.com/sites/';
const ASSETSURI = 'https://assets.awwwards.com/awards/media/cache/thumb_417_299/';
private $sites = array();
private $sites = [];
public function getIcon() {
public function getIcon()
{
return 'https://www.awwwards.com/favicon.ico';
}
private function fetchSites() {
private function fetchSites()
{
Debug::log('Fetching all sites');
$sites = getSimpleHTMLDOM(self::SITESURI);
Debug::log('Parsing all JSON data');
foreach ($sites->find('li[data-model]') as $site) {
$decode = html_entity_decode($site->attr['data-model'],
ENT_QUOTES, 'utf-8');
$decode = html_entity_decode(
$site->attr['data-model'],
ENT_QUOTES,
'utf-8'
);
$decode = json_decode($decode, true);
$this->sites[] = $decode;
}
}
public function collectData() {
public function collectData()
{
$this->fetchSites();
Debug::log('Building RSS feed');
foreach ($this->sites as $site) {
$item = array();
$item = [];
$item['title'] = $site['title'];
$item['timestamp'] = $site['createdAt'];
$item['categories'] = $site['tags'];
@ -47,8 +55,9 @@ class AwwwardsBridge extends BridgeAbstract {
$this->items[] = $item;
if(count($this->items) >= 10)
if (count($this->items) >= 10) {
break;
}
}
}
}

View file

@ -1,30 +1,33 @@
<?php
class BAEBridge extends BridgeAbstract {
class BAEBridge extends BridgeAbstract
{
const MAINTAINER = 'couraudt';
const NAME = 'Bourse Aux Equipiers Bridge';
const URI = 'https://www.bourse-aux-equipiers.com';
const DESCRIPTION = 'Returns the newest sailing offers.';
const PARAMETERS = array(
array(
'keyword' => array(
const PARAMETERS = [
[
'keyword' => [
'name' => 'Filtrer par mots clés',
'title' => 'Entrez le mot clé à filtrer ici'
),
'type' => array(
],
'type' => [
'name' => 'Type de recherche',
'title' => 'Afficher seuleument un certain type d\'annonce',
'type' => 'list',
'values' => array(
'values' => [
'Toutes les annonces' => false,
'Les embarquements' => 'boat',
'Les skippers' => 'skipper',
'Les équipiers' => 'crew'
)
)
)
);
]
]
]
];
public function collectData() {
public function collectData()
{
$url = $this->getURI();
$html = getSimpleHTMLDOM($url) or returnClientError('No results for this query.');
@ -33,10 +36,11 @@ class BAEBridge extends BridgeAbstract {
$detail = $annonce->find('footer a', 0);
$htmlDetail = getSimpleHTMLDOMCached(parent::getURI() . $detail->href);
if (!$htmlDetail)
if (!$htmlDetail) {
continue;
}
$item = array();
$item = [];
$item['title'] = $annonce->find('header h2', 0)->plaintext;
$item['uri'] = parent::getURI() . $detail->href;
@ -58,13 +62,14 @@ class BAEBridge extends BridgeAbstract {
$item['content'] = defaultLinkTo($content, parent::getURI());
$image = $htmlDetail->find('#zoom', 0);
if ($image) {
$item['enclosures'] = array(parent::getURI() . $image->getAttribute('src'));
$item['enclosures'] = [parent::getURI() . $image->getAttribute('src')];
}
$this->items[] = $item;
}
}
public function getURI() {
public function getURI()
{
$uri = parent::getURI();
if (!empty($this->getInput('type'))) {
if ($this->getInput('type') == 'boat') {
@ -79,8 +84,9 @@ class BAEBridge extends BridgeAbstract {
return $uri;
}
private function removeAccents($string) {
$chars = array(
private function removeAccents($string)
{
$chars = [
// Decompositions for Latin-1 Supplement
'ª' => 'a', 'º' => 'o',
'À' => 'A', 'Á' => 'A',
@ -254,7 +260,7 @@ class BAEBridge extends BridgeAbstract {
'Ǚ' => 'U', 'ǚ' => 'u',
// grave accent
'Ǜ' => 'U', 'ǜ' => 'u',
);
];
$string = strtr($string, $chars);

View file

@ -1,55 +1,57 @@
<?php
class BadDragonBridge extends BridgeAbstract {
class BadDragonBridge extends BridgeAbstract
{
const NAME = 'Bad Dragon Bridge';
const URI = 'https://bad-dragon.com/';
const CACHE_TIMEOUT = 300; // 5min
const DESCRIPTION = 'Returns sales or new clearance items';
const MAINTAINER = 'Roliga';
const PARAMETERS = array(
'Sales' => array(
),
'Clearance' => array(
'ready_made' => array(
const PARAMETERS = [
'Sales' => [
],
'Clearance' => [
'ready_made' => [
'name' => 'Ready Made',
'type' => 'checkbox'
),
'flop' => array(
],
'flop' => [
'name' => 'Flops',
'type' => 'checkbox'
),
'skus' => array(
],
'skus' => [
'name' => 'Products',
'exampleValue' => 'chanceflared, crackers',
'title' => 'Comma separated list of product SKUs'
),
'onesize' => array(
],
'onesize' => [
'name' => 'One-Size',
'type' => 'checkbox'
),
'mini' => array(
],
'mini' => [
'name' => 'Mini',
'type' => 'checkbox'
),
'small' => array(
],
'small' => [
'name' => 'Small',
'type' => 'checkbox'
),
'medium' => array(
],
'medium' => [
'name' => 'Medium',
'type' => 'checkbox'
),
'large' => array(
],
'large' => [
'name' => 'Large',
'type' => 'checkbox'
),
'extralarge' => array(
],
'extralarge' => [
'name' => 'Extra Large',
'type' => 'checkbox'
),
'category' => array(
],
'category' => [
'name' => 'Category',
'type' => 'list',
'values' => array(
'values' => [
'All' => 'all',
'Accessories' => 'accessories',
'Merchandise' => 'merchandise',
@ -59,50 +61,50 @@ class BadDragonBridge extends BridgeAbstract {
'Lil\' Squirts' => 'shooter',
'Lil\' Vibes' => 'vibrator',
'Wearables' => 'wearable'
),
],
'defaultValue' => 'all',
),
'soft' => array(
],
'soft' => [
'name' => 'Soft Firmness',
'type' => 'checkbox'
),
'med_firm' => array(
],
'med_firm' => [
'name' => 'Medium Firmness',
'type' => 'checkbox'
),
'firm' => array(
],
'firm' => [
'name' => 'Firm',
'type' => 'checkbox'
),
'split' => array(
],
'split' => [
'name' => 'Split Firmness',
'type' => 'checkbox'
),
'maxprice' => array(
],
'maxprice' => [
'name' => 'Max Price',
'type' => 'number',
'required' => true,
'defaultValue' => 300
),
'minprice' => array(
],
'minprice' => [
'name' => 'Min Price',
'type' => 'number',
'defaultValue' => 0
),
'cumtube' => array(
],
'cumtube' => [
'name' => 'Cumtube',
'type' => 'checkbox'
),
'suctionCup' => array(
],
'suctionCup' => [
'name' => 'Suction Cup',
'type' => 'checkbox'
),
'noAccessories' => array(
],
'noAccessories' => [
'name' => 'No Accessories',
'type' => 'checkbox'
)
)
);
]
]
];
/*
* This sets index $strFrom (or $strTo if set) in $outArr to 'on' if
@ -122,14 +124,16 @@ class BadDragonBridge extends BridgeAbstract {
* [flop] => on
* )
* */
private function setParam($inArr, &$outArr, $param, $strFrom, $strTo = null) {
private function setParam($inArr, &$outArr, $param, $strFrom, $strTo = null)
{
if (isset($inArr[$param]) && in_array($strFrom, $inArr[$param])) {
$outArr[($strTo ?: $strFrom)] = 'on';
}
}
public function detectParameters($url) {
$params = array();
public function detectParameters($url)
{
$params = [];
// Sale
$regex = '/^(https?:\/\/)?bad-dragon\.com\/sales/';
@ -146,7 +150,7 @@ class BadDragonBridge extends BridgeAbstract {
$this->setParam($urlParams, $params, 'type', 'flop');
if (isset($urlParams['skus'])) {
$skus = array();
$skus = [];
foreach ($urlParams['skus'] as $sku) {
is_string($sku) && $skus[] = $sku;
is_array($sku) && $skus[] = $sku[0];
@ -195,7 +199,8 @@ class BadDragonBridge extends BridgeAbstract {
return null;
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'Sales':
return 'Bad Dragon Sales';
@ -206,7 +211,8 @@ class BadDragonBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case 'Sales':
return self::URI . 'sales';
@ -217,13 +223,14 @@ class BadDragonBridge extends BridgeAbstract {
}
}
public function collectData() {
public function collectData()
{
switch ($this->queriedContext) {
case 'Sales':
$sales = json_decode(getContents(self::URI . 'api/sales'));
foreach ($sales as $sale) {
$item = array();
$item = [];
$item['title'] = $sale->title;
$item['timestamp'] = strtotime($sale->startDate);
@ -279,7 +286,7 @@ class BadDragonBridge extends BridgeAbstract {
. 'api/inventory-toy/product-list'));
foreach ($toyData->toys as $toy) {
$item = array();
$item = [];
$item['uri'] = $this->getURI()
. '#'
@ -318,12 +325,12 @@ class BadDragonBridge extends BridgeAbstract {
. ($toy->cumtube ? 'Cumtube' : '')
. ($toy->suction_cup || $toy->cumtube ? '' : 'None');
// firmness
$firmnessTexts = array(
$firmnessTexts = [
'2' => 'Extra soft',
'3' => 'Soft',
'5' => 'Medium',
'8' => 'Firm'
);
];
$firmnesses = explode('/', $toy->firmness);
if (count($firmnesses) === 2) {
$content .= '<br /><b>Firmness:</b> '
@ -342,13 +349,13 @@ class BadDragonBridge extends BridgeAbstract {
$content .= '</p>';
$item['content'] = $content;
$enclosures = array();
$enclosures = [];
foreach ($toy->images as $image) {
$enclosures[] = $image->fullFilename;
}
$item['enclosures'] = $enclosures;
$categories = array();
$categories = [];
$categories[] = $toy->sku;
$categories[] = $toy->type;
$categories[] = $toy->size;
@ -366,7 +373,8 @@ class BadDragonBridge extends BridgeAbstract {
}
}
private function inputToURL($api = false) {
private function inputToURL($api = false)
{
$url = self::URI;
$url .= ($api ? 'api/inventory-toys?' : 'shop/clearance?');

View file

@ -1,90 +1,106 @@
<?php
class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
class BakaUpdatesMangaReleasesBridge extends BridgeAbstract
{
const NAME = 'Baka Updates Manga Releases';
const URI = 'https://www.mangaupdates.com/';
const DESCRIPTION = 'Get the latest series releases';
const MAINTAINER = 'fulmeek, KamaleiZestri';
const PARAMETERS = array(
'By series' => array(
'series_id' => array(
const PARAMETERS = [
'By series' => [
'series_id' => [
'name' => 'Series ID',
'type' => 'number',
'required' => true,
'exampleValue' => '188066'
)
),
'By list' => array(
'list_id' => array(
]
],
'By list' => [
'list_id' => [
'name' => 'List ID and Type',
'type' => 'text',
'required' => true,
'exampleValue' => '4395&list=read'
)
)
);
]
]
];
const LIMIT_COLS = 5;
const LIMIT_ITEMS = 10;
const RELEASES_URL = 'https://www.mangaupdates.com/releases.html';
private $feedName = '';
public function collectData() {
if($this -> queriedContext == 'By series')
public function collectData()
{
if ($this -> queriedContext == 'By series') {
$this -> collectDataBySeries();
else //queriedContext == 'By list'
} else { //queriedContext == 'By list'
$this -> collectDataByList();
}
}
public function getURI(){
public function getURI()
{
if ($this -> queriedContext == 'By series') {
$series_id = $this->getInput('series_id');
if (!empty($series_id)) {
return self::URI . 'releases.html?search=' . $series_id . '&stype=series';
}
} else //queriedContext == 'By list'
} else { //queriedContext == 'By list'
return self::RELEASES_URL;
}
return self::URI;
}
public function getName(){
public function getName()
{
if (!empty($this->feedName)) {
return $this->feedName . ' - ' . self::NAME;
}
return parent::getName();
}
private function getSanitizedHash($string) {
private function getSanitizedHash($string)
{
return hash('sha1', preg_replace('/[^a-zA-Z0-9\-\.]/', '', ucwords(strtolower($string))));
}
private function filterText($text) {
private function filterText($text)
{
return rtrim($text, '* ');
}
private function filterHTML($text) {
private function filterHTML($text)
{
return $this->filterText(html_entity_decode($text));
}
private function findID($manga) {
private function findID($manga)
{
// sometimes new series are on the release list that have no ID. just drop them.
if (@$this -> filterHTML($manga -> find('a', 0) -> href) != null) {
preg_match('/id=([0-9]*)/', $this -> filterHTML($manga -> find('a', 0) -> href), $match);
return $match[1];
} else
} else {
return 0;
}
}
private function collectDataBySeries() {
private function collectDataBySeries()
{
$html = getSimpleHTMLDOM($this->getURI());
// content is an unstructured pile of divs, ugly to parse
$cols = $html->find('div#main_content div.row > div.text');
if (!$cols)
if (!$cols) {
returnServerError('No releases');
}
$rows = array_slice(
array_chunk($cols, self::LIMIT_COLS), 0, self::LIMIT_ITEMS
array_chunk($cols, self::LIMIT_COLS),
0,
self::LIMIT_ITEMS
);
if (isset($rows[0][1])) {
@ -92,16 +108,19 @@ class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
}
foreach ($rows as $cols) {
if (count($cols) < self::LIMIT_COLS) continue;
if (count($cols) < self::LIMIT_COLS) {
continue;
}
$item = array();
$title = array();
$item = [];
$title = [];
$item['content'] = '';
$objDate = $cols[0];
if ($objDate)
if ($objDate) {
$item['timestamp'] = strtotime($objDate->plaintext);
}
$objTitle = $cols[1];
if ($objTitle) {
@ -110,12 +129,14 @@ class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
}
$objVolume = $cols[2];
if ($objVolume && !empty($objVolume->plaintext))
if ($objVolume && !empty($objVolume->plaintext)) {
$title[] = 'Vol.' . $objVolume->plaintext;
}
$objChapter = $cols[3];
if ($objChapter && !empty($objChapter->plaintext))
if ($objChapter && !empty($objChapter->plaintext)) {
$title[] = 'Chp.' . $objChapter->plaintext;
}
$objAuthor = $cols[4];
if ($objAuthor && !empty($objAuthor->plaintext)) {
@ -131,9 +152,10 @@ class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
}
}
private function collectDataByList() {
private function collectDataByList()
{
$this -> feedName = 'Releases';
$list = array();
$list = [];
$releasesHTML = getSimpleHTMLDOM(self::RELEASES_URL);
@ -153,10 +175,12 @@ class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
foreach ($rows as $cols) {
//check if current manga is in user's list.
$id = $this -> findId($cols[0]);
if(!array_search($id, $list)) continue;
if (!array_search($id, $list)) {
continue;
}
$item = array();
$title = array();
$item = [];
$title = [];
$item['content'] = '';
@ -167,8 +191,9 @@ class BakaUpdatesMangaReleasesBridge extends BridgeAbstract {
}
$objVolChap = $cols[1];
if ($objVolChap && !empty($objVolChap->plaintext))
if ($objVolChap && !empty($objVolChap->plaintext)) {
$title[] = $this -> filterHTML($objVolChap -> innertext);
}
$objAuthor = $cols[2];
if ($objAuthor && !empty($objAuthor->plaintext)) {

View file

@ -1,120 +1,123 @@
<?php
class BandcampBridge extends BridgeAbstract {
class BandcampBridge extends BridgeAbstract
{
const MAINTAINER = 'sebsauvage, Roliga';
const NAME = 'Bandcamp Bridge';
const URI = 'https://bandcamp.com/';
const CACHE_TIMEOUT = 600; // 10min
const DESCRIPTION = 'New bandcamp releases by tag, band or album';
const PARAMETERS = array(
'By tag' => array(
'tag' => array(
const PARAMETERS = [
'By tag' => [
'tag' => [
'name' => 'tag',
'type' => 'text',
'required' => true,
'exampleValue' => 'hip-hop-rap'
)
),
'By band' => array(
'band' => array(
]
],
'By band' => [
'band' => [
'name' => 'band',
'type' => 'text',
'title' => 'Band name as seen in the band page URL',
'required' => true,
'exampleValue' => 'aesoprock'
),
'type' => array(
],
'type' => [
'name' => 'Articles are',
'type' => 'list',
'values' => array(
'values' => [
'Releases' => 'releases',
'Releases, new one when track list changes' => 'changes',
'Individual tracks' => 'tracks'
),
],
'defaultValue' => 'changes'
),
'limit' => array(
],
'limit' => [
'name' => 'limit',
'type' => 'number',
'required' => true,
'title' => 'Number of releases to return',
'defaultValue' => 5
)
),
'By label' => array(
'label' => array(
]
],
'By label' => [
'label' => [
'name' => 'label',
'type' => 'text',
'title' => 'label name as seen in the label page URL',
'required' => true
),
'type' => array(
],
'type' => [
'name' => 'Articles are',
'type' => 'list',
'values' => array(
'values' => [
'Releases' => 'releases',
'Releases, new one when track list changes' => 'changes',
'Individual tracks' => 'tracks'
),
],
'defaultValue' => 'changes'
),
'limit' => array(
],
'limit' => [
'name' => 'limit',
'type' => 'number',
'title' => 'Number of releases to return',
'defaultValue' => 5
)
),
'By album' => array(
'band' => array(
]
],
'By album' => [
'band' => [
'name' => 'band',
'type' => 'text',
'title' => 'Band name as seen in the album page URL',
'required' => true,
'exampleValue' => 'aesoprock'
),
'album' => array(
],
'album' => [
'name' => 'album',
'type' => 'text',
'title' => 'Album name as seen in the album page URL',
'required' => true,
'exampleValue' => 'appleseed'
),
'type' => array(
],
'type' => [
'name' => 'Articles are',
'type' => 'list',
'values' => array(
'values' => [
'Releases' => 'releases',
'Releases, new one when track list changes' => 'changes',
'Individual tracks' => 'tracks'
),
],
'defaultValue' => 'tracks'
)
)
);
]
]
];
const IMGURI = 'https://f4.bcbits.com/';
const IMGSIZE_300PX = 23;
const IMGSIZE_700PX = 16;
private $feedName;
public function getIcon() {
public function getIcon()
{
return 'https://s4.bcbits.com/img/bc_favicon.ico';
}
public function collectData(){
public function collectData()
{
switch ($this->queriedContext) {
case 'By tag':
$url = self::URI . 'api/hub/1/dig_deeper';
$data = $this->buildRequestJson();
$header = array(
$header = [
'Content-Type: application/json',
'Content-Length: ' . strlen($data)
);
$opts = array(
];
$opts = [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $data
);
];
$content = getContents($url, $header, $opts);
$json = json_decode($content);
@ -139,13 +142,13 @@ class BandcampBridge extends BridgeAbstract {
$small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX);
$img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX);
$item = array(
$item = [
'uri' => $url,
'author' => $full_artist,
'title' => $full_title
);
];
$item['content'] = "<img src='$small_img' /><br/>$full_title";
$item['enclosures'] = array($img);
$item['enclosures'] = [$img];
$this->items[] = $item;
}
break;
@ -161,17 +164,18 @@ class BandcampBridge extends BridgeAbstract {
}
$regex = '/band_id=(\d+)/';
if(preg_match($regex, $html, $matches) == false)
if (preg_match($regex, $html, $matches) == false) {
returnServerError('Unable to find band ID on: ' . $this->getURI());
}
$band_id = $matches[1];
$tralbums = array();
$tralbums = [];
switch ($this->queriedContext) {
case 'By band':
case 'By label':
$query_data = array(
$query_data = [
'band_id' => $band_id
);
];
$band_data = $this->apiGet('mobile/22/band_details', $query_data);
$num_albums = min(count($band_data->discography), $this->getInput('limit'));
@ -181,25 +185,26 @@ class BandcampBridge extends BridgeAbstract {
// 'a' or 't' for albums and individual tracks respectively
$tralbum_type = substr($album_basic_data->item_type, 0, 1);
$query_data = array(
$query_data = [
'band_id' => $band_id,
'tralbum_type' => $tralbum_type,
'tralbum_id' => $album_basic_data->item_id
);
];
$tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data);
}
break;
case 'By album':
$regex = '/album=(\d+)/';
if(preg_match($regex, $html, $matches) == false)
if (preg_match($regex, $html, $matches) == false) {
returnServerError('Unable to find album ID on: ' . $this->getURI());
}
$album_id = $matches[1];
$query_data = array(
$query_data = [
'band_id' => $band_id,
'tralbum_type' => 'a',
'tralbum_id' => $album_id
);
];
$tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data);
break;
@ -208,11 +213,11 @@ class BandcampBridge extends BridgeAbstract {
foreach ($tralbums as $tralbum_data) {
if ($tralbum_data->type === 'a' && $this->getInput('type') === 'tracks') {
foreach ($tralbum_data->tracks as $track) {
$query_data = array(
$query_data = [
'band_id' => $band_id,
'tralbum_type' => 't',
'tralbum_id' => $track->track_id
);
];
$track_data = $this->apiGet('mobile/22/tralbum_details', $query_data);
$this->items[] = $this->buildTralbumItem($track_data);
@ -225,7 +230,8 @@ class BandcampBridge extends BridgeAbstract {
}
}
private function buildTralbumItem($tralbum_data){
private function buildTralbumItem($tralbum_data)
{
$band_data = $tralbum_data->band;
// Format title like: ARTIST - ALBUM/TRACK (OPTIONAL RELEASER)
@ -250,15 +256,15 @@ class BandcampBridge extends BridgeAbstract {
$small_img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_300PX);
$img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_700PX);
$item = array(
$item = [
'uri' => $tralbum_data->bandcamp_url,
'author' => $full_artist,
'title' => $full_title,
'enclosures' => array($img),
'enclosures' => [$img],
'timestamp' => $tralbum_data->release_date
);
];
$item['categories'] = array();
$item['categories'] = [];
foreach ($tralbum_data->tags as $tag) {
$item['categories'][] = $tag->norm_name;
}
@ -289,26 +295,30 @@ class BandcampBridge extends BridgeAbstract {
return $item;
}
private function buildRequestJson(){
$requestJson = array(
private function buildRequestJson()
{
$requestJson = [
'tag' => $this->getInput('tag'),
'page' => 1,
'sort' => 'date'
);
];
return json_encode($requestJson);
}
private function getImageUrl($id, $size){
private function getImageUrl($id, $size)
{
return self::IMGURI . 'img/a' . $id . '_' . $size . '.jpg';
}
private function apiGet($endpoint, $query_data) {
private function apiGet($endpoint, $query_data)
{
$url = self::URI . 'api/' . $endpoint . '?' . http_build_query($query_data);
$data = json_decode(getContents($url));
return $data;
}
public function getURI(){
public function getURI()
{
switch ($this->queriedContext) {
case 'By tag':
if (!is_null($this->getInput('tag'))) {
@ -345,7 +355,8 @@ class BandcampBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName(){
public function getName()
{
switch ($this->queriedContext) {
case 'By tag':
if (!is_null($this->getInput('tag'))) {
@ -378,8 +389,9 @@ class BandcampBridge extends BridgeAbstract {
return parent::getName();
}
public function detectParameters($url) {
$params = array();
public function detectParameters($url)
{
$params = [];
// By tag
$regex = '/^(https?:\/\/)?bandcamp\.com\/tag\/([^\/.&?\n]+)/';

View file

@ -1,16 +1,18 @@
<?php
class BandcampDailyBridge extends BridgeAbstract {
class BandcampDailyBridge extends BridgeAbstract
{
const NAME = 'Bandcamp Daily Bridge';
const URI = 'https://daily.bandcamp.com';
const DESCRIPTION = 'Returns newest articles';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(
'Latest articles' => array(),
'Best of' => array(
'best-content' => array(
const PARAMETERS = [
'Latest articles' => [],
'Best of' => [
'best-content' => [
'name' => 'content',
'type' => 'list',
'values' => array(
'values' => [
'Best Ambient' => 'best-ambient',
'Best Beat Tapes' => 'best-beat-tapes',
'Best Dance 12\'s' => 'best-dance-12s',
@ -23,15 +25,15 @@ class BandcampDailyBridge extends BridgeAbstract {
'Best Punk' => 'best-punk',
'Best Reissues' => 'best-reissues',
'Best Soul' => 'best-soul',
),
],
'defaultValue' => 'best-ambient',
),
),
'Genres' => array(
'genres-content' => array(
],
],
'Genres' => [
'genres-content' => [
'name' => 'content',
'type' => 'list',
'values' => array(
'values' => [
'Acoustic' => 'genres/acoustic',
'Alternative' => 'genres/alternative',
'Ambient' => 'genres/ambient',
@ -57,15 +59,15 @@ class BandcampDailyBridge extends BridgeAbstract {
'Soundtrack' => 'genres/soundtrack',
'Spoken Word' => 'genres/spoken-word',
'World' => 'genres/world',
),
],
'defaultValue' => 'genres/acoustic',
),
),
'Franchises' => array(
'franchises-content' => array(
],
],
'Franchises' => [
'franchises-content' => [
'name' => 'content',
'type' => 'list',
'values' => array(
'values' => [
'Lists' => 'lists',
'Features' => 'features',
'Album of the Day' => 'album-of-the-day',
@ -81,15 +83,16 @@ class BandcampDailyBridge extends BridgeAbstract {
'Scene Report' => 'scene-report',
'Seven Essential Releases' => 'seven-essential-releases',
'The Merch Table' => 'the-merch-table',
),
],
'defaultValue' => 'lists',
),
)
);
],
]
];
const CACHE_TIMEOUT = 3600; // 1 hour
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI())
or returnServerError('Could not request: ' . $this->getURI());
@ -98,7 +101,7 @@ class BandcampDailyBridge extends BridgeAbstract {
$articles = $html->find('articles-list', 0);
foreach ($articles->find('div.list-article') as $index => $article) {
$item = array();
$item = [];
$articlePath = $article->find('a.title', 0)->href;
@ -126,7 +129,8 @@ class BandcampDailyBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case 'Latest articles':
return self::URI . '/latest';
@ -141,7 +145,8 @@ class BandcampDailyBridge extends BridgeAbstract {
}
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'Latest articles':
return $this->queriedContext . ' - Bandcamp Daily';

View file

@ -1,20 +1,22 @@
<?php
class BastaBridge extends BridgeAbstract {
class BastaBridge extends BridgeAbstract
{
const MAINTAINER = 'qwertygc';
const NAME = 'Bastamag Bridge';
const URI = 'https://www.bastamag.net/';
const CACHE_TIMEOUT = 7200; // 2h
const DESCRIPTION = 'Returns the newest articles.';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI . 'spip.php?page=backend');
$limit = 0;
foreach ($html->find('item') as $element) {
if ($limit < 10) {
$item = array();
$item = [];
$item['title'] = $element->find('title', 0)->innertext;
$item['uri'] = $element->find('guid', 0)->plaintext;
$item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext);

View file

@ -1,16 +1,20 @@
<?php
class BinanceBridge extends BridgeAbstract {
class BinanceBridge extends BridgeAbstract
{
const NAME = 'Binance Blog';
const URI = 'https://www.binance.com/en/blog';
const DESCRIPTION = 'Subscribe to the Binance blog.';
const MAINTAINER = 'thefranke';
const CACHE_TIMEOUT = 3600; // 1h
public function getIcon() {
public function getIcon()
{
return 'https://bin.bnbstatic.com/static/images/common/favicon.ico';
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI)
or returnServerError('Could not fetch Binance blog data.');
@ -18,14 +22,13 @@ class BinanceBridge extends BridgeAbstract {
$appDataJson = json_decode($appData[0]->innertext);
foreach ($appDataJson->pageData->redux->blogList->blogList as $element) {
$date = $element->postTime;
$abstract = $element->brief;
$uri = self::URI . '/' . $element->lang . '/blog/' . $element->idStr;
$title = $element->title;
$content = $element->content;
$item = array();
$item = [];
$item['title'] = $title;
$item['uri'] = $uri;
$item['timestamp'] = substr($date, 0, -3);
@ -34,8 +37,9 @@ class BinanceBridge extends BridgeAbstract {
$this->items[] = $item;
if (count($this->items) >= 10)
if (count($this->items) >= 10) {
break;
}
}
}
}

View file

@ -1,23 +1,24 @@
<?php
class BlaguesDeMerdeBridge extends BridgeAbstract {
class BlaguesDeMerdeBridge extends BridgeAbstract
{
const MAINTAINER = 'superbaillot.net, logmanoriginal';
const NAME = 'Blagues De Merde';
const URI = 'http://www.blaguesdemerde.fr/';
const CACHE_TIMEOUT = 7200; // 2h
const DESCRIPTION = 'Blagues De Merde';
public function getIcon() {
public function getIcon()
{
return self::URI . 'assets/img/favicon.ico';
}
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
foreach ($html->find('div.blague') as $element) {
$item = array();
$item = [];
$item['uri'] = static::URI . '#' . $element->id;
$item['author'] = $element->find('div[class="blague-footer"] p strong', 0)->plaintext;
@ -38,8 +39,6 @@ class BlaguesDeMerdeBridge extends BridgeAbstract {
$item['timestamp'] = strtotime($matches[1]);
$this->items[] = $item;
}
}
}
}

View file

@ -1,12 +1,14 @@
<?php
class BleepingComputerBridge extends FeedExpander {
class BleepingComputerBridge extends FeedExpander
{
const MAINTAINER = 'csisoap';
const NAME = 'Bleeping Computer';
const URI = 'https://www.bleepingcomputer.com/';
const DESCRIPTION = 'Returns the newest articles.';
protected function parseItem($item){
protected function parseItem($item)
{
$item = parent::parseItem($item);
$article_html = getSimpleHTMLDOMCached($item['uri']);
@ -22,7 +24,8 @@ class BleepingComputerBridge extends FeedExpander {
return $item;
}
public function collectData(){
public function collectData()
{
$feed = static::URI . 'feed/';
$this->collectExpandableDatas($feed);
}

View file

@ -1,17 +1,17 @@
<?php
class BlizzardNewsBridge extends XPathAbstract {
class BlizzardNewsBridge extends XPathAbstract
{
const NAME = 'Blizzard News';
const URI = 'https://news.blizzard.com';
const DESCRIPTION = 'Blizzard (game company) newsfeed';
const MAINTAINER = 'Niehztog';
const PARAMETERS = array(
'' => array(
'locale' => array(
const PARAMETERS = [
'' => [
'locale' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'Deutsch' => 'de-de',
'English (EU)' => 'en-gb',
'English (US)' => 'en-us',
@ -27,12 +27,12 @@ class BlizzardNewsBridge extends XPathAbstract {
'ภาษาไทย' => 'th-th',
'简体中文' => 'zh-cn',
'繁體中文' => 'zh-tw'
),
],
'defaultValue' => 'en-us',
'title' => 'Select your language'
)
)
);
]
]
];
const CACHE_TIMEOUT = 3600;
const XPATH_EXPRESSION_ITEM = '/html/body/div/div[4]/div[2]/div[2]/div/div/section/ol/li/article';
@ -49,8 +49,8 @@ class BlizzardNewsBridge extends XPathAbstract {
* Source Web page URL (should provide either HTML or XML content)
* @return string
*/
protected function getSourceUrl(){
protected function getSourceUrl()
{
$locale = $this->getInput('locale');
if ('zh-cn' === $locale) {
return 'https://cn.news.blizzard.com';

View file

@ -1,6 +1,7 @@
<?php
class BookMyShowBridge extends BridgeAbstract {
class BookMyShowBridge extends BridgeAbstract
{
const MAINTAINER = 'captn3m0';
const NAME = 'BookMyShow Bridge';
const URI = 'https://in.bookmyshow.com';
@ -1091,7 +1092,8 @@ class BookMyShowBridge extends BridgeAbstract {
// The city information is passed via a cookie
const URL_PREFIX = 'https://in.bookmyshow.com/serv/getData?cmd=QUICKBOOK&type=';
public function collectData(){
public function collectData()
{
$city = $this->getInput('city');
$category = $this->getInput('category');
@ -1120,11 +1122,13 @@ class BookMyShowBridge extends BridgeAbstract {
$this->items = array_slice($this->items, 0, 15);
}
private function makeUrl($category){
private function makeUrl($category)
{
return self::URL_PREFIX . $category;
}
private function getDatesHtml($dates){
private function getDatesHtml($dates)
{
$tz = new DateTimeZone(self::TIMEZONE);
$firstDate = DateTime::createFromFormat('Ymd', $dates[0]['ShowDateCode'], $tz)
->format('D, d M Y');
@ -1142,7 +1146,8 @@ class BookMyShowBridge extends BridgeAbstract {
* @param array $event
* @see https://gist.github.com/captn3m0/6dbd539ca67579d22d6f90fab710ccd2 Sample JSON data for various events
*/
private function generateEventHtml($event, $category){
private function generateEventHtml($event, $category)
{
$html = $this->getDatesHtml($event['arrDates']);
switch ($category) {
case self::MOVIES:
@ -1160,7 +1165,8 @@ class BookMyShowBridge extends BridgeAbstract {
* Generates a simple Venue HTML, even for multiple venues
* spread across multiple dates as a description list.
*/
private function generateVenueHtml($venues){
private function generateVenueHtml($venues)
{
$html = '<h3>Venues</h3><table><thead><tr><th>Venue</th><th>Directions</th></tr></thead><tbody>';
foreach ($venues as $i => $venueData) {
@ -1180,7 +1186,8 @@ class BookMyShowBridge extends BridgeAbstract {
* Generates a simple Table with event Data
* @todo Add support for jsonGenre as a tags row
*/
private function generateEventDetailsTable($event, $headers = self::TABLE_HEADERS){
private function generateEventDetailsTable($event, $headers = self::TABLE_HEADERS)
{
$table = '';
foreach ($headers as $key => $header) {
if ($header == 'Language') {
@ -1206,7 +1213,8 @@ EOT;
return "<table>$table</table>";
}
private function generateStandardHtml($event){
private function generateStandardHtml($event)
{
$table = $this->generateEventDetailsTable($event);
$imgsrc = $event['BannerURL'];
@ -1224,7 +1232,8 @@ EOT;
* Converts some movie details from child entries, such as language
* into a single row item, either as a list, or as a Y/N
*/
private function generateInnerMovieDetails($data){
private function generateInnerMovieDetails($data)
{
// Show list of languages and list of formats
$headers = ['EventLanguage', 'EventDimension'];
// if any of these has a Y for any of the screenings, mark it as YES
@ -1270,7 +1279,8 @@ EOT;
return $html;
}
private function generateMovieHtml($eventGroup){
private function generateMovieHtml($eventGroup)
{
$data = $eventGroup['ChildEvents'][0];
$table = $this->generateEventDetailsTable($data, self::MOVIE_TABLE_HEADERS);
@ -1290,17 +1300,18 @@ EOT;
More Details are available on the <a href="$url">BookMyShow website</a> and a trailer is available
<a href="${data['EventTrailerURL']}" title="Trailer URL">here</a>
EOT;
}
/**
* Generates a canonical movie URL
*/
private function generateMovieUrl($eventGroup){
private function generateMovieUrl($eventGroup)
{
return self::URI . '/movies/' . $eventGroup['EventURLTitle'] . '/' . $eventGroup['EventCode'];
}
private function generateMoviesData($eventGroup){
private function generateMoviesData($eventGroup)
{
// Additional data picked up from the first Child Event
$data = $eventGroup['ChildEvents'][0];
$date = new DateTime($data['EventDate']);
@ -1323,7 +1334,8 @@ EOT;
];
}
private function generateEventData($event, $category){
private function generateEventData($event, $category)
{
if ($category == self::MOVIES) {
return $this->generateMoviesData($event);
}
@ -1334,7 +1346,8 @@ EOT;
/**
* Takes an event data as array and returns data for RSS Post
*/
private function generateGenericEventData($event, $category){
private function generateGenericEventData($event, $category)
{
$datetime = $event['Event_dtmCreated'];
if (empty($datetime)) {
return null;
@ -1362,7 +1375,8 @@ EOT;
* Check if this is an online event. We can't rely on
* EventIsWebView, since that is set to Y for everything
*/
private function isEventOnline($event){
private function isEventOnline($event)
{
if (isset($event['arrVenues']) && count($event['arrVenues']) === 1) {
if (preg_match('/(Online|Zoom)/i', $event['arrVenues'][0]['VenueName'])) {
return true;
@ -1372,7 +1386,8 @@ EOT;
return false;
}
private function matchesLanguage(){
private function matchesLanguage()
{
if ($this->getInput('language') !== 'all') {
$language = $this->getInput('language');
return in_array($language, $this->languages);
@ -1380,7 +1395,8 @@ EOT;
return true;
}
private function matchesOnline($event){
private function matchesOnline($event)
{
if ($this->getInput('include_online')) {
return true;
}
@ -1390,14 +1406,16 @@ EOT;
/**
* Currently only checks if the language filter matches
*/
private function matchesFilters($category, $event){
private function matchesFilters($category, $event)
{
return $this->matchesLanguage() and $this->matchesOnline($event);
}
/**
* Generates the RSS Feed title
*/
public function getName(){
public function getName()
{
$city = $this->getInput('city');
$category = $this->getInput('category');
if (!is_null($city) and !is_null($category)) {
@ -1420,7 +1438,8 @@ EOT;
* @param string $city City Code
* @return array list of headers
*/
private function makeHeaders($city){
private function makeHeaders($city)
{
$uniqid = uniqid();
$rgn = urlencode("|Code=$city|");
return [
@ -1432,7 +1451,8 @@ EOT;
* Generates various URLs as per https://tools.ietf.org/html/rfc5870
* and other standards
*/
private function generateDirectionsHtml($lat, $long, $address = ''){
private function generateDirectionsHtml($lat, $long, $address = '')
{
$address = urlencode($address);
$links = [

View file

@ -1,59 +1,64 @@
<?php
class BooruprojectBridge extends DanbooruBridge {
class BooruprojectBridge extends DanbooruBridge
{
const MAINTAINER = 'mitsukarenai';
const NAME = 'Booruproject';
const URI = 'https://booru.org/';
const DESCRIPTION = 'Returns images from given page of booruproject';
const PARAMETERS = array(
'global' => array(
'p' => array(
const PARAMETERS = [
'global' => [
'p' => [
'name' => 'page',
'defaultValue' => 0,
'type' => 'number'
),
't' => array(
],
't' => [
'name' => 'tags',
'required' => true,
'exampleValue' => 'tagme',
'title' => 'Use "all" to get all posts'
)
),
'Booru subdomain (subdomain.booru.org)' => array(
'i' => array(
]
],
'Booru subdomain (subdomain.booru.org)' => [
'i' => [
'name' => 'Subdomain',
'required' => true,
'exampleValue' => 'rm'
)
)
);
]
]
];
const PATHTODATA = '.thumb';
const IDATTRIBUTE = 'id';
const TAGATTRIBUTE = 'title';
const PIDBYPAGE = 20;
protected function getFullURI(){
protected function getFullURI()
{
return $this->getURI()
. 'index.php?page=post&s=list&pid='
. ($this->getInput('p') ? ($this->getInput('p') - 1) * static::PIDBYPAGE : '')
. '&tags=' . urlencode($this->getInput('t'));
}
protected function getTags($element){
protected function getTags($element)
{
$tags = parent::getTags($element);
$tags = explode(' ', $tags);
// Remove statistics from the tags list (identified by colon)
foreach ($tags as $key => $tag) {
if(strpos($tag, ':') !== false) unset($tags[$key]);
if (strpos($tag, ':') !== false) {
unset($tags[$key]);
}
}
return implode(' ', $tags);
}
public function getURI(){
public function getURI()
{
if (!is_null($this->getInput('i'))) {
return 'https://' . $this->getInput('i') . '.booru.org/';
}
@ -61,7 +66,8 @@ class BooruprojectBridge extends DanbooruBridge {
return parent::getURI();
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('i'))) {
return static::NAME . ' ' . $this->getInput('i');
}

View file

@ -1,14 +1,16 @@
<?php
class BrutBridge extends BridgeAbstract {
class BrutBridge extends BridgeAbstract
{
const NAME = 'Brut Bridge';
const URI = 'https://www.brut.media';
const DESCRIPTION = 'Returns 10 newest videos by category and edition';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(array(
'category' => array(
const PARAMETERS = [[
'category' => [
'name' => 'Category',
'type' => 'list',
'values' => array(
'values' => [
'News' => 'news',
'International' => 'international',
'Economy' => 'economy',
@ -17,37 +19,37 @@ class BrutBridge extends BridgeAbstract {
'Sports' => 'sport',
'Nature' => 'nature',
'Health' => 'health',
),
],
'defaultValue' => 'news',
),
'edition' => array(
],
'edition' => [
'name' => ' Edition',
'type' => 'list',
'values' => array(
'values' => [
'United States' => 'us',
'United Kingdom' => 'uk',
'France' => 'fr',
'Spain' => 'es',
'India' => 'in',
'Mexico' => 'mx',
),
],
'defaultValue' => 'us',
)
)
);
]
]
];
const CACHE_TIMEOUT = 1800; // 30 mins
private $jsonRegex = '/window\.__PRELOADED_STATE__ = ((?:.*)});/';
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI());
$results = $html->find('div.results', 0);
foreach ($results->find('li.col-6.col-sm-4.col-md-3.col-lg-2.px-2.pb-4') as $li) {
$item = array();
$item = [];
$videoPath = self::URI . $li->children(0)->href;
$videoPageHtml = getSimpleHTMLDOMCached($videoPath, 3600);
@ -83,8 +85,8 @@ EOD;
}
}
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('edition')) && !is_null($this->getInput('category'))) {
return self::URI . '/' . $this->getInput('edition') . '/' . $this->getInput('category');
}
@ -92,8 +94,8 @@ EOD;
return parent::getURI();
}
public function getName() {
public function getName()
{
if (!is_null($this->getInput('edition')) && !is_null($this->getInput('category'))) {
$parameters = $this->getParameters();
@ -110,8 +112,8 @@ EOD;
/**
* Extract JSON from page
*/
private function extractJson($html) {
private function extractJson($html)
{
if (!preg_match($this->jsonRegex, $html, $parts)) {
returnServerError('Failed to extract data from page');
}

View file

@ -1,65 +1,69 @@
<?php
class BugzillaBridge extends BridgeAbstract {
class BugzillaBridge extends BridgeAbstract
{
const NAME = 'Bugzilla Bridge';
const URI = 'https://www.bugzilla.org/';
const DESCRIPTION = 'Bridge for any Bugzilla instance';
const MAINTAINER = 'Yaman Qalieh';
const PARAMETERS = array(
'global' => array(
'instance' => array(
const PARAMETERS = [
'global' => [
'instance' => [
'name' => 'Instance URL',
'required' => true,
'exampleValue' => 'https://bugzilla.mozilla.org'
)
),
'Bug comments' => array(
'id' => array(
]
],
'Bug comments' => [
'id' => [
'name' => 'Bug tracking ID',
'type' => 'number',
'required' => true,
'title' => 'Insert bug tracking ID',
'exampleValue' => 121241
),
'limit' => array(
],
'limit' => [
'name' => 'Number of comments to return',
'type' => 'number',
'required' => false,
'title' => 'Specify number of comments to return',
'defaultValue' => -1
),
'skiptags' => array(
],
'skiptags' => [
'name' => 'Skip offtopic comments',
'type' => 'checkbox',
'title' => 'Excludes comments tagged as advocacy, metoo, or offtopic from the feed'
)
)
);
]
]
];
const SKIPPED_ACTIVITY = array(
const SKIPPED_ACTIVITY = [
'cc' => true,
'comment_tag' => true
);
];
const SKIPPED_TAGS = array('advocacy', 'metoo', 'offtopic');
const SKIPPED_TAGS = ['advocacy', 'metoo', 'offtopic'];
private $instance;
private $bugid;
private $buguri;
private $title;
public function getName() {
public function getName()
{
if (!is_null($this->title)) {
return $this->title;
}
return parent::getName();
}
public function getURI() {
public function getURI()
{
return $this->buguri ?? parent::getURI();
}
public function collectData() {
public function collectData()
{
$this->instance = rtrim($this->getInput('instance'), '/');
$this->bugid = $this->getInput('id');
$this->buguri = $this->instance . '/show_bug.cgi?id=' . $this->bugid;
@ -78,7 +82,8 @@ class BugzillaBridge extends BridgeAbstract {
}
}
protected function getTitle($url) {
protected function getTitle($url)
{
// Only request the summary for a faster request
$json = json_decode(getContents($url . '?include_fields=summary'), true);
$this->title = 'Bug ' . $this->bugid . ' - ' .
@ -87,7 +92,8 @@ class BugzillaBridge extends BridgeAbstract {
substr($this->instance, 8);
}
protected function collectComments($url) {
protected function collectComments($url)
{
$json = json_decode(getContents($url), true);
// Array of comments is here
@ -96,9 +102,11 @@ class BugzillaBridge extends BridgeAbstract {
}
foreach ($json['bugs'][$this->bugid]['comments'] as $comment) {
$item = array();
if ($this->getInput('skiptags') and
array_intersect(self::SKIPPED_TAGS, $comment['tags'])) {
$item = [];
if (
$this->getInput('skiptags') and
array_intersect(self::SKIPPED_TAGS, $comment['tags'])
) {
continue;
}
$item['categories'] = $comment['tags'];
@ -111,13 +119,14 @@ class BugzillaBridge extends BridgeAbstract {
$item['content'] = markdownToHtml($item['content']);
}
if (!is_null($comment['attachment_id'])) {
$item['enclosures'] = array($this->instance . '/attachment.cgi?id=' . $comment['attachment_id']);
$item['enclosures'] = [$this->instance . '/attachment.cgi?id=' . $comment['attachment_id']];
}
$this->items[] = $item;
}
}
protected function collectUpdates($url) {
protected function collectUpdates($url)
{
$json = json_decode(getContents($url), true);
// Array of changesets which contain an array of changes
@ -134,7 +143,7 @@ class BugzillaBridge extends BridgeAbstract {
continue;
}
$item = array();
$item = [];
$item['uri'] = $this->buguri;
$item['title'] = 'Updated';
$item['timestamp'] = $timestamp;
@ -147,7 +156,8 @@ class BugzillaBridge extends BridgeAbstract {
}
}
protected function getUser($user) {
protected function getUser($user)
{
// Check if the user endpoint is available
if ($this->loadCacheValue($this->instance . 'userEndpointClosed')) {
return $user;
@ -162,7 +172,7 @@ class BugzillaBridge extends BridgeAbstract {
try {
$json = json_decode(getContents($url), true);
if (isset($json['error']) and $json['error']) {
throw new Exception;
throw new Exception();
}
} catch (Exception $e) {
$this->saveCacheValue($this->instance . 'userEndpointClosed', true);

View file

@ -6,13 +6,13 @@ class BukowskisBridge extends BridgeAbstract
const URI = 'https://www.bukowskis.com';
const DESCRIPTION = 'Fetches info about auction objects from Bukowskis auction house';
const MAINTAINER = 'Qluxzz';
const PARAMETERS = array(array(
'category' => array(
const PARAMETERS = [[
'category' => [
'name' => 'Category',
'type' => 'list',
'values' => array(
'values' => [
'All categories' => '',
'Art' => array(
'Art' => [
'All' => 'art',
'Classic Art' => 'art.classic-art',
'Classic Finnish Art' => 'art.classic-finnish-art',
@ -27,31 +27,31 @@ class BukowskisBridge extends BridgeAbstract
'Prints' => 'art.prints',
'Sculpture' => 'art.sculpture',
'Swedish Old Masters' => 'art.swedish-old-masters',
),
'Asian Ceramics & Works of Art' => array(
],
'Asian Ceramics & Works of Art' => [
'All' => 'asian-ceramics-works-of-art',
'Other' => 'asian-ceramics-works-of-art.other',
'Porcelain' => 'asian-ceramics-works-of-art.porcelain',
),
'Books & Manuscripts' => array(
],
'Books & Manuscripts' => [
'All' => 'books-manuscripts',
'Books' => 'books-manuscripts.books',
),
'Carpets, rugs & textiles' => array(
],
'Carpets, rugs & textiles' => [
'All' => 'carpets-rugs-textiles',
'European' => 'carpets-rugs-textiles.european',
'Oriental' => 'carpets-rugs-textiles.oriental',
'Rest of the world' => 'carpets-rugs-textiles.rest-of-the-world',
'Scandinavian' => 'carpets-rugs-textiles.scandinavian',
),
'Ceramics & porcelain' => array(
],
'Ceramics & porcelain' => [
'All' => 'ceramics-porcelain',
'Ceramic ware' => 'ceramics-porcelain.ceramic-ware',
'European' => 'ceramics-porcelain.european',
'Rest of the world' => 'ceramics-porcelain.rest-of-the-world',
'Scandinavian' => 'ceramics-porcelain.scandinavian',
),
'Collectibles' => array(
],
'Collectibles' => [
'All' => 'collectibles',
'Advertising & Retail' => 'collectibles.advertising-retail',
'Memorabilia' => 'collectibles.memorabilia',
@ -60,18 +60,18 @@ class BukowskisBridge extends BridgeAbstract
'Retro & Popular Culture' => 'collectibles.retro-popular-culture',
'Technica & Nautica' => 'collectibles.technica-nautica',
'Toys' => 'collectibles.toys',
),
'Design' => array(
],
'Design' => [
'All' => 'design',
'Art glass' => 'design.art-glass',
'Furniture' => 'design.furniture',
'Other' => 'design.other',
),
'Folk art' => array(
],
'Folk art' => [
'All' => 'folk-art',
'All categories' => 'lots',
),
'Furniture' => array(
],
'Furniture' => [
'All' => 'furniture',
'Armchairs & Sofas' => 'furniture.armchairs-sofas',
'Cabinets & Bureaus' => 'furniture.cabinets-bureaus',
@ -81,13 +81,13 @@ class BukowskisBridge extends BridgeAbstract
'Other' => 'furniture.other',
'Shelves & Book cases' => 'furniture.shelves-book-cases',
'Tables' => 'furniture.tables',
),
'Glassware' => array(
],
'Glassware' => [
'All' => 'glassware',
'Glassware' => 'glassware.glassware',
'Other' => 'glassware.other',
),
'Jewellery' => array(
],
'Jewellery' => [
'All' => 'jewellery',
'Bracelets' => 'jewellery.bracelets',
'Brooches' => 'jewellery.brooches',
@ -95,8 +95,8 @@ class BukowskisBridge extends BridgeAbstract
'Necklaces & Pendants' => 'jewellery.necklaces-pendants',
'Other' => 'jewellery.other',
'Rings' => 'jewellery.rings',
),
'Lighting' => array(
],
'Lighting' => [
'All' => 'lighting',
'Candle sticks & Candelabras' => 'lighting.candle-sticks-candelabras',
'Ceiling lights' => 'lighting.ceiling-lights',
@ -105,46 +105,46 @@ class BukowskisBridge extends BridgeAbstract
'Other' => 'lighting.other',
'Table lights' => 'lighting.table-lights',
'Wall lights' => 'lighting.wall-lights',
),
'Militaria' => array(
],
'Militaria' => [
'All' => 'militaria',
'Honors & Medals' => 'militaria.honors-medals',
'Other militaria' => 'militaria.other-militaria',
'Weaponry' => 'militaria.weaponry',
),
'Miscellaneous' => array(
],
'Miscellaneous' => [
'All' => 'miscellaneous',
'Brass, Copper & Pewter' => 'miscellaneous.brass-copper-pewter',
'Nickel silver' => 'miscellaneous.nickel-silver',
'Oriental' => 'miscellaneous.oriental',
'Other' => 'miscellaneous.other',
),
'Silver' => array(
],
'Silver' => [
'All' => 'silver',
'Candle sticks' => 'silver.candle-sticks',
'Cups & Bowls' => 'silver.cups-bowls',
'Cutlery' => 'silver.cutlery',
'Other' => 'silver.other',
),
'Timepieces' => array(
],
'Timepieces' => [
'All' => 'timepieces',
'Other' => 'timepieces.other',
'Pocket watches' => 'timepieces.pocket-watches',
'Table clocks' => 'timepieces.table-clocks',
'Wrist watches' => 'timepieces.wrist-watches',
),
'Vintage & Fashion' => array(
],
'Vintage & Fashion' => [
'All' => 'vintage-fashion',
'Accessories' => 'vintage-fashion.accessories',
'Bags & Trunks' => 'vintage-fashion.bags-trunks',
'Clothes' => 'vintage-fashion.clothes',
),
)
),
'sort_order' => array(
],
]
],
'sort_order' => [
'name' => 'Sort order',
'type' => 'list',
'values' => array(
'values' => [
'Ending soon' => 'ending',
'Most recent' => 'recent',
'Most bids' => 'most',
@ -154,18 +154,18 @@ class BukowskisBridge extends BridgeAbstract
'Lowest estimate' => 'low',
'Highest estimate' => 'high',
'Alphabetical' => 'alphabetical',
),
),
'language' => array(
],
],
'language' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'English' => 'en',
'Swedish' => 'sv',
'Finnish' => 'fi'
),
),
));
],
],
]];
const CACHE_TIMEOUT = 3600; // 1 hour
@ -180,11 +180,13 @@ class BukowskisBridge extends BridgeAbstract
$url = $baseUrl . '/' . $language . '/lots';
if ($category)
if ($category) {
$url = $url . '/category/' . $category;
}
if ($sort_order)
if ($sort_order) {
$url = $url . '/sort/' . $sort_order;
}
$html = getSimpleHTMLDOM($url);
@ -201,13 +203,13 @@ class BukowskisBridge extends BridgeAbstract
)
);
$this->items[] = array(
$this->items[] = [
'title' => $title,
'uri' => $baseUrl . $relative_url,
'uid' => $lot->getAttribute('data-lot-id'),
'content' => count($images) > 0 ? "<img src='$images[0]'/><br/>$title" : $title,
'enclosures' => array_slice($images, 1),
);
];
}
}

View file

@ -1,6 +1,7 @@
<?php
class BundesbankBridge extends BridgeAbstract {
class BundesbankBridge extends BridgeAbstract
{
const PARAM_LANG = 'lang';
const LANG_EN = 'en';
@ -12,41 +13,45 @@ class BundesbankBridge extends BridgeAbstract {
const MAINTAINER = 'logmanoriginal';
const CACHE_TIMEOUT = 86400; // 24 hours
const PARAMETERS = array(
array(
self::PARAM_LANG => array(
const PARAMETERS = [
[
self::PARAM_LANG => [
'name' => 'Language',
'type' => 'list',
'defaultValue' => self::LANG_DE,
'values' => array(
'values' => [
'English' => self::LANG_EN,
'Deutsch' => self::LANG_DE
)
)
)
);
]
]
]
];
public function getIcon() {
public function getIcon()
{
return self::URI . 'resource/crblob/1890/a7f48ee0ae35348748121770ba3ca009/mL/favicon-ico-data.ico';
}
public function getURI() {
public function getURI()
{
switch ($this->getInput(self::PARAM_LANG)) {
case self::LANG_EN: return self::URI . 'en/publications/reports/studies';
case self::LANG_DE: return self::URI . 'de/publikationen/berichte/studien';
case self::LANG_EN:
return self::URI . 'en/publications/reports/studies';
case self::LANG_DE:
return self::URI . 'de/publikationen/berichte/studien';
}
return parent::getURI();
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI());
$html = defaultLinkTo($html, $this->getURI());
foreach ($html->find('ul.resultlist li') as $study) {
$item = array();
$item = [];
$item['uri'] = $study->find('.teasable__link', 0)->href;
@ -72,13 +77,12 @@ class BundesbankBridge extends BridgeAbstract {
// Downloads and older studies don't have images
if ($study->find('.teasable__image', 0)) {
$item['enclosures'] = array(
$item['enclosures'] = [
$study->find('.teasable__image img', 0)->src
);
];
}
$this->items[] = $item;
}
}
}

View file

@ -1,5 +1,7 @@
<?php
class BundestagParteispendenBridge extends BridgeAbstract {
class BundestagParteispendenBridge extends BridgeAbstract
{
const MAINTAINER = 'mibe';
const NAME = 'Deutscher Bundestag - Parteispenden';
const URI = 'https://www.bundestag.de/parlament/praesidium/parteienfinanzierung/fundstellen50000';
@ -52,10 +54,11 @@ URI;
private function generateItemFromRow(simple_html_dom_node $row)
{
// The row must have 5 columns. There are monthly header rows, which are ignored here.
if(count($row->children) != 5)
if (count($row->children) != 5) {
return null;
}
$item = array();
$item = [];
// | column | paragraph inside column
$party = $row->children[0]->children[0]->innertext;
@ -69,20 +72,22 @@ URI;
$content = sprintf(self::CONTENT_TEMPLATE, $party, $amount, $donor, $date);
$item = array(
$item = [
'title' => $party . ': ' . $amount,
'content' => $content,
'uid' => sha1($content),
);
];
// Try to get the link to the official document
if ($dip != null)
$item['enclosures'] = array($dip->href);
if ($dip != null) {
$item['enclosures'] = [$dip->href];
}
// Try to parse the date
$dateTime = DateTime::createFromFormat('d.m.Y', $date);
if ($dateTime !== false)
if ($dateTime !== false) {
$item['timestamp'] = $dateTime->getTimestamp();
}
return $item;
}

View file

@ -1,12 +1,14 @@
<?php
class CBCEditorsBlogBridge extends BridgeAbstract {
class CBCEditorsBlogBridge extends BridgeAbstract
{
const MAINTAINER = 'quickwick';
const NAME = 'CBC Editors Blog';
const URI = 'https://www.cbc.ca/news/editorsblog';
const DESCRIPTION = 'Recent CBC Editor\'s Blog posts';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
// Loop on each blog post entry
@ -19,7 +21,7 @@ class CBCEditorsBlogBridge extends BridgeAbstract {
$thumbnailUri = rtrim(explode(',', $thumbnailUris)[0], ' 300w');
// Fill item
$item = array();
$item = [];
$item['uri'] = $articleUri;
$item['id'] = $item['uri'];
$item['timestamp'] = $timestamp;

View file

@ -1,17 +1,18 @@
<?php
class CNETBridge extends BridgeAbstract {
class CNETBridge extends BridgeAbstract
{
const MAINTAINER = 'ORelio';
const NAME = 'CNET News';
const URI = 'https://www.cnet.com/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Returns the newest articles.';
const PARAMETERS = array(
array(
'topic' => array(
const PARAMETERS = [
[
'topic' => [
'name' => 'Topic',
'type' => 'list',
'values' => array(
'values' => [
'All articles' => '',
'Apple' => 'apple',
'Google' => 'google',
@ -22,12 +23,13 @@ class CNETBridge extends BridgeAbstract {
'Security' => 'topics-security',
'Internet' => 'topics-internet',
'Tech Industry' => 'topics-tech-industry'
)
)
)
);
]
]
]
];
private function cleanArticle($article_html) {
private function cleanArticle($article_html)
{
$offset_p = strpos($article_html, '<p>');
$offset_figure = strpos($article_html, '<figure');
$offset = ($offset_figure < $offset_p ? $offset_figure : $offset_p);
@ -44,12 +46,13 @@ class CNETBridge extends BridgeAbstract {
return $article_html;
}
public function collectData() {
public function collectData()
{
// Retrieve and check user input
$topic = str_replace('-', '/', $this->getInput('topic'));
if (!empty($topic) && (substr_count($topic, '/') > 1 || !ctype_alpha(str_replace('/', '', $topic))))
if (!empty($topic) && (substr_count($topic, '/') > 1 || !ctype_alpha(str_replace('/', '', $topic)))) {
returnClientError('Invalid topic: ' . $topic);
}
// Retrieve webpage
$pageUrl = self::URI . (empty($topic) ? 'news/' : $topic . '/');
@ -57,7 +60,6 @@ class CNETBridge extends BridgeAbstract {
// Process articles
foreach ($html->find('div.assetBody, div.riverPost') as $element) {
if (count($this->items) >= 10) {
break;
}
@ -69,37 +71,41 @@ class CNETBridge extends BridgeAbstract {
$article_author = trim($element->find('a[rel=author], a.name', 0)->plaintext);
$article_content = '<p><b>' . trim($element->find('p.dek', 0)->plaintext) . '</b></p>';
if (is_null($article_thumbnail))
if (is_null($article_thumbnail)) {
$article_thumbnail = extractFromDelimiters($element->innertext, '<img src="', '"');
}
if (!empty($article_title) && !empty($article_uri) && strpos($article_uri, self::URI . 'news/') !== false) {
$article_html = getSimpleHTMLDOMCached($article_uri) or $article_html = null;
if (!is_null($article_html)) {
if (empty($article_thumbnail))
if (empty($article_thumbnail)) {
$article_thumbnail = $article_html->find('div.originalImage', 0);
if (empty($article_thumbnail))
}
if (empty($article_thumbnail)) {
$article_thumbnail = $article_html->find('span.imageContainer', 0);
if (is_object($article_thumbnail))
}
if (is_object($article_thumbnail)) {
$article_thumbnail = $article_thumbnail->find('img', 0)->src;
}
$article_content .= trim(
$this->cleanArticle(
extractFromDelimiters(
$article_html, '<article', '<footer'
$article_html,
'<article',
'<footer'
)
)
);
}
$item = array();
$item = [];
$item['uri'] = $article_uri;
$item['title'] = $article_title;
$item['author'] = $article_author;
$item['timestamp'] = $article_timestamp;
$item['enclosures'] = array($article_thumbnail);
$item['enclosures'] = [$article_thumbnail];
$item['content'] = $article_content;
$this->items[] = $item;
}

View file

@ -1,4 +1,5 @@
<?php
class CNETFranceBridge extends FeedExpander
{
const MAINTAINER = 'leomaradan';
@ -6,25 +7,25 @@ class CNETFranceBridge extends FeedExpander
const URI = 'https://www.cnetfrance.fr/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'CNET France RSS with filters';
const PARAMETERS = array(
'filters' => array(
'title' => array(
const PARAMETERS = [
'filters' => [
'title' => [
'name' => 'Exclude by title',
'required' => false,
'title' => 'Title term, separated by semicolon (;)',
'exampleValue' => 'bon plan;bons plans;au meilleur prix;des meilleures offres;Amazon Prime Day;RED by SFR ou B&You'
),
'url' => array(
],
'url' => [
'name' => 'Exclude by url',
'required' => false,
'title' => 'URL term, separated by semicolon (;)',
'exampleValue' => 'bon-plan;bons-plans'
)
)
);
]
]
];
private $bannedTitle = array();
private $bannedURL = array();
private $bannedTitle = [];
private $bannedURL = [];
public function collectData()
{

View file

@ -7,29 +7,30 @@
// it is not reliable and contain no useful information. This bridge create a
// sane feed with additional information like tags and a link to the CWE
// a description of the vulnerability.
class CVEDetailsBridge extends BridgeAbstract {
class CVEDetailsBridge extends BridgeAbstract
{
const MAINTAINER = 'Aaron Fischer';
const NAME = 'CVE Details';
const CACHE_TIMEOUT = 60 * 60 * 6; // 6 hours
const DESCRIPTION = 'Report new CVE vulnerabilities for a given vendor (and product)';
const URI = 'https://www.cvedetails.com';
const PARAMETERS = array(array(
const PARAMETERS = [[
// The Vendor ID can be taken from the URL
'vendor_id' => array(
'vendor_id' => [
'name' => 'Vendor ID',
'type' => 'number',
'required' => true,
'exampleValue' => 74, // PHP
),
],
// The optional Product ID can be taken from the URL as well
'product_id' => array(
'product_id' => [
'name' => 'Product ID',
'type' => 'number',
'required' => false,
'exampleValue' => 128, // PHP
),
));
],
]];
private $html = null;
private $vendor = '';
@ -39,7 +40,8 @@ class CVEDetailsBridge extends BridgeAbstract {
// Because of the optional product ID, we need to attach it if it is
// set. The search result page has the exact same structure (with and
// without the product ID).
private function buildUrl() {
private function buildUrl()
{
$url = self::URI . '/vulnerability-list/vendor_id-' . $this->getInput('vendor_id');
if ($this->getInput('product_id') !== '') {
$url .= '/product_id-' . $this->getInput('product_id');
@ -54,7 +56,8 @@ class CVEDetailsBridge extends BridgeAbstract {
// Make the actual request to cvedetails.com and stores the response
// (HTML) for later use and extract vendor and product from it.
private function fetchContent() {
private function fetchContent()
{
$html = getSimpleHTMLDOM($this->buildUrl());
$this->html = defaultLinkTo($html, self::URI);
@ -74,7 +77,8 @@ class CVEDetailsBridge extends BridgeAbstract {
}
// Build the name of the feed.
public function getName() {
public function getName()
{
if ($this->getInput('vendor_id') == '') {
return self::NAME;
}
@ -92,7 +96,8 @@ class CVEDetailsBridge extends BridgeAbstract {
}
// Pull the data from the HTML response and fill the items..
public function collectData() {
public function collectData()
{
if ($this->html == null) {
$this->fetchContent();
}
@ -101,8 +106,8 @@ class CVEDetailsBridge extends BridgeAbstract {
// There are some optional vulnerability types, which will be
// added to the categories as well as the CWE number -- which is
// always given.
$categories = array($this->vendor);
$enclosures = array();
$categories = [$this->vendor];
$enclosures = [];
$cwe = $tr->find('td', 2)->find('a', 0);
if ($cwe != null) {
@ -121,7 +126,7 @@ class CVEDetailsBridge extends BridgeAbstract {
// The CVE number itself
$title = $tr->find('td', 1)->find('a', 0)->innertext;
$this->items[] = array(
$this->items[] = [
'uri' => $tr->find('td', 1)->find('a', 0)->href,
'title' => $title,
'timestamp' => $tr->find('td', 5)->innertext,
@ -129,7 +134,7 @@ class CVEDetailsBridge extends BridgeAbstract {
'categories' => $categories,
'enclosures' => $enclosures,
'uid' => $tr->find('td', 1)->find('a', 0)->innertext,
);
];
// We only want to fetch the latest 10 CVEs
if (count($this->items) >= 10) {

View file

@ -1,30 +1,32 @@
<?php
class CachetBridge extends BridgeAbstract {
class CachetBridge extends BridgeAbstract
{
const NAME = 'Cachet Bridge';
const URI = 'https://cachethq.io/';
const DESCRIPTION = 'Returns status updates from any Cachet installation';
const MAINTAINER = 'klimplant';
const PARAMETERS = array(
array(
'host' => array(
const PARAMETERS = [
[
'host' => [
'name' => 'Cachet installation',
'type' => 'text',
'required' => true,
'title' => 'The URL of the Cachet installation',
'exampleValue' => 'https://demo.cachethq.io/',
), 'additional_info' => array(
], 'additional_info' => [
'name' => 'Additional Timestamps',
'type' => 'checkbox',
'title' => 'Whether to include the given timestamps'
)
)
);
]
]
];
const CACHE_TIMEOUT = 300;
private $componentCache = array();
private $componentCache = [];
public function getURI() {
public function getURI()
{
return $this->getInput('host') === null ? 'https://cachethq.io/' : $this->getInput('host');
}
@ -34,7 +36,8 @@ class CachetBridge extends BridgeAbstract {
* @param string $ping
* @return boolean
*/
private function validatePing($ping) {
private function validatePing($ping)
{
$ping = json_decode($ping);
if ($ping === null) {
return false;
@ -48,7 +51,8 @@ class CachetBridge extends BridgeAbstract {
* @param integer $id
* @return string
*/
private function getComponentName($id) {
private function getComponentName($id)
{
if ($id === 0) {
return '';
}
@ -64,7 +68,8 @@ class CachetBridge extends BridgeAbstract {
return $component->data->name;
}
public function collectData() {
public function collectData()
{
$ping = getContents(urljoin($this->getURI(), '/api/v1/ping'));
if (!$this->validatePing($ping)) {
returnClientError('Provided URI is invalid!');
@ -84,7 +89,6 @@ class CachetBridge extends BridgeAbstract {
});
foreach ($incidents->data as $incident) {
if (isset($incident->permalink)) {
$permalink = $incident->permalink;
} else {
@ -114,13 +118,13 @@ class CachetBridge extends BridgeAbstract {
$uidOrig = $permalink . $incident->created_at;
$uid = hash('sha512', $uidOrig);
$timestamp = strtotime($incident->created_at);
$categories = array();
$categories = [];
$categories[] = $incident->human_status;
if ($componentName !== '') {
$categories[] = $componentName;
}
$item = array();
$item = [];
$item['uri'] = $permalink;
$item['title'] = $title;
$item['timestamp'] = $timestamp;

View file

@ -1,15 +1,19 @@
<?php
class CarThrottleBridge extends FeedExpander {
class CarThrottleBridge extends FeedExpander
{
const NAME = 'Car Throttle ';
const URI = 'https://www.carthrottle.com';
const DESCRIPTION = 'Get the latest car-related news from Car Throttle.';
const MAINTAINER = 't0stiman';
public function collectData() {
public function collectData()
{
$this->collectExpandableDatas('https://www.carthrottle.com/rss', 10);
}
protected function parseItem($feedItem) {
protected function parseItem($feedItem)
{
$item = parent::parseItem($feedItem);
//fetch page
@ -23,7 +27,6 @@ class CarThrottleBridge extends FeedExpander {
//convert <iframe>s to <a>s. meant for embedded videos.
foreach ($item['content']->find('iframe') as $found) {
$iframeUrl = $found->getAttribute('src');
if ($iframeUrl) {

View file

@ -1,61 +1,69 @@
<?php
class CastorusBridge extends BridgeAbstract {
class CastorusBridge extends BridgeAbstract
{
const MAINTAINER = 'logmanoriginal';
const NAME = 'Castorus Bridge';
const URI = 'https://www.castorus.com';
const CACHE_TIMEOUT = 600; // 10min
const DESCRIPTION = 'Returns the latest changes';
const PARAMETERS = array(
'Get latest changes' => array(),
'Get latest changes via ZIP code' => array(
'zip' => array(
const PARAMETERS = [
'Get latest changes' => [],
'Get latest changes via ZIP code' => [
'zip' => [
'name' => 'ZIP code',
'type' => 'text',
'required' => true,
'exampleValue' => '7',
'title' => 'Insert ZIP code (complete or partial). e.g: 78125 OR 781 OR 7'
)
),
'Get latest changes via city name' => array(
'city' => array(
]
],
'Get latest changes via city name' => [
'city' => [
'name' => 'City name',
'type' => 'text',
'required' => true,
'exampleValue' => 'Paris',
'title' => 'Insert city name (complete or partial). e.g: Paris OR Par OR P'
)
)
);
]
]
];
// Extracts the title from an actitiy
private function extractActivityTitle($activity){
private function extractActivityTitle($activity)
{
$title = $activity->find('a', 0);
if(!$title)
if (!$title) {
returnServerError('Cannot find title!');
}
return trim($title->plaintext);
}
// Extracts the url from an actitiy
private function extractActivityUrl($activity){
private function extractActivityUrl($activity)
{
$url = $activity->find('a', 0);
if(!$url)
if (!$url) {
returnServerError('Cannot find url!');
}
return self::URI . $url->href;
}
// Extracts the time from an activity
private function extractActivityTime($activity){
private function extractActivityTime($activity)
{
// Unfortunately the time is part of the parent node,
// so we have to clear all child nodes first
$nodes = $activity->find('*');
if(!$nodes)
if (!$nodes) {
returnServerError('Cannot find nodes!');
}
foreach ($nodes as $node) {
$node->outertext = '';
@ -65,31 +73,36 @@ class CastorusBridge extends BridgeAbstract {
}
// Extracts the price change
private function extractActivityPrice($activity){
private function extractActivityPrice($activity)
{
$price = $activity->find('span', 1);
if(!$price)
if (!$price) {
returnServerError('Cannot find price!');
}
return $price->innertext;
}
public function collectData(){
public function collectData()
{
$zip_filter = trim($this->getInput('zip'));
$city_filter = trim($this->getInput('city'));
$html = getSimpleHTMLDOM(self::URI);
if(!$html)
if (!$html) {
returnServerError('Could not load data from ' . self::URI . '!');
}
$activities = $html->find('div#activite > li');
if(!$activities)
if (!$activities) {
returnServerError('Failed to find activities!');
}
foreach ($activities as $activity) {
$item = array();
$item = [];
$item['title'] = $this->extractActivityTitle($activity);
$item['uri'] = $this->extractActivityUrl($activity);
@ -102,13 +115,17 @@ class CastorusBridge extends BridgeAbstract {
. $this->extractActivityPrice($activity)
. '</p>';
if(isset($zip_filter)
&& !(substr($item['title'], 0, strlen($zip_filter)) === $zip_filter)) {
if (
isset($zip_filter)
&& !(substr($item['title'], 0, strlen($zip_filter)) === $zip_filter)
) {
continue; // Skip this item
}
if(isset($city_filter)
&& !(substr($item['title'], strpos($item['title'], ' ') + 1, strlen($city_filter)) === $city_filter)) {
if (
isset($city_filter)
&& !(substr($item['title'], strpos($item['title'], ' ') + 1, strlen($city_filter)) === $city_filter)
) {
continue; // Skip this item
}

View file

@ -1,40 +1,42 @@
<?php
class CdactionBridge extends BridgeAbstract {
class CdactionBridge extends BridgeAbstract
{
const NAME = 'CD-ACTION bridge';
const URI = 'https://cdaction.pl';
const DESCRIPTION = 'Fetches the latest posts from given category.';
const MAINTAINER = 'tomaszkane';
const PARAMETERS = array( array(
'category' => array(
const PARAMETERS = [ [
'category' => [
'name' => 'Kategoria',
'type' => 'list',
'values' => array(
'values' => [
'Najnowsze (wszystkie)' => 'najnowsze',
'Newsy' => 'newsy',
'Recenzje' => 'recenzje',
'Teksty' => array(
'Teksty' => [
'Publicystyka' => 'publicystyka',
'Zapowiedzi' => 'zapowiedzi',
'Już graliśmy' => 'juz-gralismy',
'Poradniki' => 'poradniki',
),
],
'Kultura' => 'kultura',
'Wideo' => 'wideo',
'Czasopismo' => 'czasopismo',
'Technologie' => array(
'Technologie' => [
'Artykuły' => 'artykuly',
'Testy' => 'testy',
),
'Na luzie' => array(
],
'Na luzie' => [
'Konkursy' => 'konkursy',
'Nadgodziny' => 'nadgodziny',
)
)
))
);
]
]
]]
];
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI() . '/' . $this->getInput('category'));
$newsJson = $html->find('script#__NEXT_DATA__', 0)->innertext;
@ -44,7 +46,7 @@ class CdactionBridge extends BridgeAbstract {
$queriesIndex = $this->getInput('category') === 'najnowsze' ? 0 : 1;
foreach ($newsJson->props->pageProps->dehydratedState->queries[$queriesIndex]->state->data->results as $news) {
$item = array();
$item = [];
$item['uri'] = $this->getURI() . '/' . $news->category->slug . '/' . $news->slug;
$item['title'] = $news->title;
$item['timestamp'] = $news->publishedAt;

View file

@ -1,28 +1,30 @@
<?php
class CeskaTelevizeBridge extends BridgeAbstract {
class CeskaTelevizeBridge extends BridgeAbstract
{
const NAME = 'Česká televize Bridge';
const URI = 'https://www.ceskatelevize.cz';
const CACHE_TIMEOUT = 3600;
const DESCRIPTION = 'Return newest videos';
const MAINTAINER = 'kolarcz';
const PARAMETERS = array(
array(
'url' => array(
const PARAMETERS = [
[
'url' => [
'name' => 'url to the show',
'required' => true,
'exampleValue' => 'https://www.ceskatelevize.cz/porady/1097181328-udalosti/'
)
)
);
]
]
];
private function fixChars($text) {
private function fixChars($text)
{
return html_entity_decode($text, ENT_QUOTES, 'UTF-8');
}
private function getUploadTimeFromString($string) {
private function getUploadTimeFromString($string)
{
if (strpos($string, 'dnes') !== false) {
return strtotime('today');
} elseif (strpos($string, 'včera') !== false) {
@ -35,7 +37,8 @@ class CeskaTelevizeBridge extends BridgeAbstract {
return strtotime($date);
}
public function collectData() {
public function collectData()
{
$url = $this->getInput('url');
$validUrl = '/^(https:\/\/www\.ceskatelevize\.cz\/porady\/\d+-[a-z0-9-]+\/)(bonus\/)?$/';
@ -61,23 +64,25 @@ class CeskaTelevizeBridge extends BridgeAbstract {
$itemThumbnail = $element->find('img', 0);
$itemUri = self::URI . $element->getAttribute('href');
$item = array(
$item = [
'title' => $this->fixChars($itemTitle->plaintext),
'uri' => $itemUri,
'content' => '<img src="' . $itemThumbnail->getAttribute('src') . '" /><br />'
. $this->fixChars($itemContent->plaintext),
'timestamp' => $this->getUploadTimeFromString($itemDate->plaintext)
);
];
$this->items[] = $item;
}
}
public function getURI() {
public function getURI()
{
return isset($this->feedUri) ? $this->feedUri : parent::getURI();
}
public function getName() {
public function getName()
{
return isset($this->feedName) ? $this->feedName : parent::getName();
}
}

View file

@ -1,69 +1,71 @@
<?php
class CodebergBridge extends BridgeAbstract {
class CodebergBridge extends BridgeAbstract
{
const NAME = 'Codeberg Bridge';
const URI = 'https://codeberg.org/';
const DESCRIPTION = 'Returns commits, issues, pull requests or releases for a repository.';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(
'Commits' => array(
'branch' => array(
const PARAMETERS = [
'Commits' => [
'branch' => [
'name' => 'branch',
'type' => 'text',
'exampleValue' => 'main',
'required' => false,
'title' => 'Optional, main branch is used by default.',
),
),
'Issues' => array(),
'Issue Comments' => array(
'issueId' => array(
],
],
'Issues' => [],
'Issue Comments' => [
'issueId' => [
'name' => 'Issue ID',
'type' => 'text',
'required' => true,
'exampleValue' => '513',
)
),
'Pull Requests' => array(),
'Releases' => array(),
'global' => array(
'username' => array(
]
],
'Pull Requests' => [],
'Releases' => [],
'global' => [
'username' => [
'name' => 'Username',
'type' => 'text',
'exampleValue' => 'Codeberg',
'title' => 'Username of account that the repository belongs to.',
'required' => true,
),
'repo' => array(
],
'repo' => [
'name' => 'Repository',
'type' => 'text',
'exampleValue' => 'Community',
'required' => true,
)
)
);
]
]
];
const CACHE_TIMEOUT = 1800;
const TEST_DETECT_PARAMETERS = array(
'https://codeberg.org/Codeberg/Community/issues/507' => array(
const TEST_DETECT_PARAMETERS = [
'https://codeberg.org/Codeberg/Community/issues/507' => [
'context' => 'Issue Comments', 'username' => 'Codeberg', 'repo' => 'Community', 'issueId' => '507'
),
'https://codeberg.org/Codeberg/Community/issues' => array(
],
'https://codeberg.org/Codeberg/Community/issues' => [
'context' => 'Issues', 'username' => 'Codeberg', 'repo' => 'Community'
),
'https://codeberg.org/Codeberg/Community/pulls' => array(
],
'https://codeberg.org/Codeberg/Community/pulls' => [
'context' => 'Pull Requests', 'username' => 'Codeberg', 'repo' => 'Community'
),
'https://codeberg.org/Codeberg/Community/releases' => array(
],
'https://codeberg.org/Codeberg/Community/releases' => [
'context' => 'Releases', 'username' => 'Codeberg', 'repo' => 'Community'
),
'https://codeberg.org/Codeberg/Community/commits/branch/master' => array(
],
'https://codeberg.org/Codeberg/Community/commits/branch/master' => [
'context' => 'Commits', 'username' => 'Codeberg', 'repo' => 'Community', 'branch' => 'master'
),
'https://codeberg.org/Codeberg/Community/commits' => array(
],
'https://codeberg.org/Codeberg/Community/commits' => [
'context' => 'Commits', 'username' => 'Codeberg', 'repo' => 'Community'
)
);
]
];
private $defaultBranch = 'main';
private $issueTitle = '';
@ -74,8 +76,9 @@ class CodebergBridge extends BridgeAbstract {
private $releasesUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/releases/';
private $issueCommentsUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/issues\/([0-9]+)/';
public function detectParameters($url) {
$params = array();
public function detectParameters($url)
{
$params = [];
// Issue Comments
if (preg_match($this->issueCommentsUrlRegex, $url, $matches)) {
@ -130,7 +133,8 @@ class CodebergBridge extends BridgeAbstract {
return null;
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI());
$html = defaultLinkTo($html, $this->getURI());
@ -156,7 +160,8 @@ class CodebergBridge extends BridgeAbstract {
}
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'Commits':
if ($this->getBranch() === $this->defaultBranch) {
@ -177,7 +182,8 @@ class CodebergBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case 'Commits':
return self::URI . $this->getRepo() . '/commits/branch/' . $this->getBranch();
@ -194,7 +200,8 @@ class CodebergBridge extends BridgeAbstract {
}
}
private function getBranch() {
private function getBranch()
{
if ($this->getInput('branch')) {
return $this->getInput('branch');
}
@ -202,19 +209,21 @@ class CodebergBridge extends BridgeAbstract {
return $this->defaultBranch;
}
private function getRepo() {
private function getRepo()
{
return $this->getInput('username') . '/' . $this->getInput('repo');
}
/**
* Extract commits
*/
private function extractCommits($html) {
private function extractCommits($html)
{
$table = $html->find('table#commits-table', 0);
$tbody = $table->find('tbody.commit-list', 0);
foreach ($tbody->find('tr') as $tr) {
$item = array();
$item = [];
$message = $tr->find('td.message', 0);
@ -238,11 +247,12 @@ class CodebergBridge extends BridgeAbstract {
/**
* Extract issues
*/
private function extractIssues($html) {
private function extractIssues($html)
{
$div = $html->find('div.issue.list', 0);
foreach ($div->find('li.item') as $li) {
$item = array();
$item = [];
$number = trim($li->find('a.index,ml-0.mr-2', 0)->plaintext);
@ -268,12 +278,13 @@ class CodebergBridge extends BridgeAbstract {
/**
* Extract issue comments
*/
private function extractIssueComments($html) {
private function extractIssueComments($html)
{
$this->issueTitle = $html->find('span#issue-title', 0)->plaintext
. ' (' . $html->find('span.index', 0)->plaintext . ')';
foreach ($html->find('div.timeline-item.comment') as $div) {
$item = array();
$item = [];
if ($div->class === 'timeline-item comment merge box') {
continue;
@ -297,11 +308,12 @@ class CodebergBridge extends BridgeAbstract {
/**
* Extract pulls
*/
private function extractPulls($html) {
private function extractPulls($html)
{
$div = $html->find('div.issue.list', 0);
foreach ($div->find('li.item') as $li) {
$item = array();
$item = [];
$number = trim($li->find('a.index,ml-0.mr-2', 0)->plaintext);
@ -327,11 +339,12 @@ class CodebergBridge extends BridgeAbstract {
/**
* Extract releases
*/
private function extractReleases($html) {
private function extractReleases($html)
{
$ul = $html->find('ul#release-list', 0);
foreach ($ul->find('li.ui.grid') as $li) {
$item = array();
$item = [];
$item['title'] = $li->find('h4', 0)->plaintext;
$item['uri'] = $li->find('h4', 0)->find('a', 0)->href;
@ -358,7 +371,8 @@ HTML;
/**
* Extract downloads for a releases
*/
private function extractDownloads($html, $skipFirst = false) {
private function extractDownloads($html, $skipFirst = false)
{
$downloads = '';
foreach ($html->find('a') as $index => $a) {
@ -380,7 +394,8 @@ EOD;
/**
* Ellipsis title to first 100 characters
*/
private function ellipsisTitle($text) {
private function ellipsisTitle($text)
{
$length = 100;
if (strlen($text) > $length) {
@ -393,7 +408,8 @@ EOD;
/**
* Strip SVG tag
*/
private function stripSvg($html) {
private function stripSvg($html)
{
if ($html->find('svg', 0)) {
$html->find('svg', 0)->outertext = '';
}

View file

@ -1,14 +1,16 @@
<?php
class CollegeDeFranceBridge extends BridgeAbstract {
class CollegeDeFranceBridge extends BridgeAbstract
{
const MAINTAINER = 'pit-fgfjiudghdf';
const NAME = 'CollegeDeFrance';
const URI = 'https://www.college-de-france.fr/';
const CACHE_TIMEOUT = 10800; // 3h
const DESCRIPTION = 'Returns the latest audio and video from CollegeDeFrance';
public function collectData(){
$months = array(
public function collectData()
{
$months = [
'01' => 'janv.',
'02' => 'févr.',
'03' => 'mars',
@ -21,7 +23,7 @@ class CollegeDeFranceBridge extends BridgeAbstract {
'10' => 'oct.',
'11' => 'nov.',
'12' => 'déc.'
);
];
// The "API" used by the site returns a list of partial HTML in this form
/* <li>
@ -37,7 +39,7 @@ class CollegeDeFranceBridge extends BridgeAbstract {
. 'components/search-audiovideo.jsp?fulltext=&siteid=1156951719600&lang=FR&type=all');
foreach ($html->find('a[data-target]') as $element) {
$item = array();
$item = [];
$item['title'] = $element->find('.title', 0)->plaintext;
// Most relative URLs contains an hour in addition to the date, so let's use it

View file

@ -1,20 +1,23 @@
<?php
class ComboiosDePortugalBridge extends BridgeAbstract {
class ComboiosDePortugalBridge extends BridgeAbstract
{
const NAME = 'CP | Avisos';
const BASE_URI = 'https://www.cp.pt';
const URI = self::BASE_URI . '/passageiros/pt';
const DESCRIPTION = 'Comboios de Portugal | Avisos';
const MAINTAINER = 'somini';
public function collectData() {
public function collectData()
{
# Do not verify SSL certificate (the server doesn't send the intermediate)
# https://github.com/RSS-Bridge/rss-bridge/issues/2397
$html = getSimpleHTMLDOM($this->getURI() . '/consultar-horarios/avisos', array(), array(
$html = getSimpleHTMLDOM($this->getURI() . '/consultar-horarios/avisos', [], [
CURLOPT_SSL_VERIFYPEER => 0,
));
]);
foreach ($html->find('.warnings-table a') as $element) {
$item = array();
$item = [];
$item['title'] = $element->innertext;
$item['uri'] = self::BASE_URI . implode('/', array_map('urlencode', explode('/', $element->href)));

View file

@ -1,31 +1,34 @@
<?php
class ComicsKingdomBridge extends BridgeAbstract {
class ComicsKingdomBridge extends BridgeAbstract
{
const MAINTAINER = 'stjohnjohnson';
const NAME = 'Comics Kingdom Unofficial RSS';
const URI = 'https://comicskingdom.com/';
const CACHE_TIMEOUT = 21600; // 6h
const DESCRIPTION = 'Comics Kingdom Unofficial RSS';
const PARAMETERS = array( array(
'comicname' => array(
const PARAMETERS = [ [
'comicname' => [
'name' => 'comicname',
'type' => 'text',
'exampleValue' => 'mutts',
'title' => 'The name of the comic in the URL after https://comicskingdom.com/',
'required' => true
)
));
]
]];
public function collectData(){
$html = getSimpleHTMLDOM($this->getURI(), array(), array(), true, false);
public function collectData()
{
$html = getSimpleHTMLDOM($this->getURI(), [], [], true, false);
// Get author from first page
$author = $html->find('div.author p', 0);;
$author = $html->find('div.author p', 0);
;
// Get current date/link
$link = $html->find('meta[property=og:url]', -1)->content;
for ($i = 0; $i < 3; $i++) {
$item = array();
$item = [];
$page = getSimpleHTMLDOM($link);
@ -42,11 +45,14 @@ class ComicsKingdomBridge extends BridgeAbstract {
$this->items[] = $item;
$link = $page->find('div.comic-viewer-inline a', 0)->href;
if (empty($link)) break; // allow bridge to continue if there's less than 3 comics
if (empty($link)) {
break; // allow bridge to continue if there's less than 3 comics
}
}
}
public function getURI(){
public function getURI()
{
if (!is_null($this->getInput('comicname'))) {
return self::URI . urlencode($this->getInput('comicname'));
}
@ -54,7 +60,8 @@ class ComicsKingdomBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('comicname'))) {
return $this->getInput('comicname') . ' - Comics Kingdom';
}

View file

@ -1,22 +1,26 @@
<?php
class CommonDreamsBridge extends FeedExpander {
class CommonDreamsBridge extends FeedExpander
{
const MAINTAINER = 'nyutag';
const NAME = 'CommonDreams Bridge';
const URI = 'https://www.commondreams.org/';
const DESCRIPTION = 'Returns the newest articles.';
public function collectData(){
public function collectData()
{
$this->collectExpandableDatas('http://www.commondreams.org/rss.xml', 10);
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
$item = parent::parseItem($newsItem);
$item['content'] = $this->extractContent($item['uri']);
return $item;
}
private function extractContent($url){
private function extractContent($url)
{
$html3 = getSimpleHTMLDOMCached($url);
$text = $html3->find('div[class=field--type-text-with-summary]', 0)->innertext;
$html3->clear();

View file

@ -1,13 +1,15 @@
<?php
class CopieDoubleBridge extends BridgeAbstract {
class CopieDoubleBridge extends BridgeAbstract
{
const MAINTAINER = 'superbaillot.net';
const NAME = 'CopieDouble';
const URI = 'http://www.copie-double.com/';
const CACHE_TIMEOUT = 14400; // 4h
const DESCRIPTION = 'CopieDouble';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
$table = $html->find('table table', 2);
@ -16,7 +18,7 @@ class CopieDoubleBridge extends BridgeAbstract {
$td = $element->find('td', 0);
if ($td->class === 'couleur_1') {
$item = array();
$item = [];
$title = $td->innertext;
$pos = strpos($title, '<a');
$title = substr($title, 0, $pos);

View file

@ -1,17 +1,20 @@
<?php
class CourrierInternationalBridge extends FeedExpander {
class CourrierInternationalBridge extends FeedExpander
{
const MAINTAINER = 'teromene';
const NAME = 'Courrier International Bridge';
const URI = 'https://www.courrierinternational.com/';
const CACHE_TIMEOUT = 300; // 5 min
const DESCRIPTION = 'Returns the newest articles';
public function collectData(){
public function collectData()
{
$this->collectExpandableDatas(static::URI . 'feed/all/rss.xml', 20);
}
protected function parseItem($feedItem){
protected function parseItem($feedItem)
{
$item = parent::parseItem($feedItem);
$articlePage = getSimpleHTMLDOMCached($feedItem->link);

View file

@ -1,51 +1,55 @@
<?php
class CraigslistBridge extends BridgeAbstract {
class CraigslistBridge extends BridgeAbstract
{
const NAME = 'Craigslist Bridge';
const URI = 'https://craigslist.org/';
const DESCRIPTION = 'Returns craigslist search results';
const PARAMETERS = array( array(
'region' => array(
const PARAMETERS = [ [
'region' => [
'name' => 'Region',
'title' => 'The subdomain before craigslist.org in the URL',
'exampleValue' => 'sfbay',
'required' => true
),
'search' => array(
],
'search' => [
'name' => 'Search Query',
'title' => 'Everything in the URL after /search/',
'exampleValue' => 'sya?query=laptop',
'required' => true
),
'limit' => array(
],
'limit' => [
'name' => 'Number of Posts',
'type' => 'number',
'title' => 'The maximum number of posts is 120. Use 0 for unlimited posts.',
'defaultValue' => '25'
)
));
]
]];
const TEST_DETECT_PARAMETERS = array(
'https://sfbay.craigslist.org/search/sya?query=laptop' => array(
const TEST_DETECT_PARAMETERS = [
'https://sfbay.craigslist.org/search/sya?query=laptop' => [
'region' => 'sfbay', 'search' => 'sya?query=laptop'
),
'https://newyork.craigslist.org/search/sss?query=32gb+flash+drive&bundleDuplicates=1&max_price=20' => array(
],
'https://newyork.craigslist.org/search/sss?query=32gb+flash+drive&bundleDuplicates=1&max_price=20' => [
'region' => 'newyork', 'search' => 'sss?query=32gb+flash+drive&bundleDuplicates=1&max_price=20'
),
);
],
];
const URL_REGEX = '/^https:\/\/(?<region>\w+).craigslist.org\/search\/(?<search>.+)/';
public function detectParameters($url) {
public function detectParameters($url)
{
if (preg_match(self::URL_REGEX, $url, $matches)) {
$params = array();
$params = [];
$params['region'] = $matches['region'];
$params['search'] = $matches['search'];
return $params;
}
}
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('region'))) {
$domain = 'https://' . $this->getInput('region') . '.craigslist.org/search/';
return urljoin($domain, $this->getInput('search'));
@ -53,7 +57,8 @@ class CraigslistBridge extends BridgeAbstract {
return parent::getURI();
}
public function collectData() {
public function collectData()
{
$uri = $this->getURI();
$html = getSimpleHTMLDOM($uri);
@ -71,14 +76,13 @@ class CraigslistBridge extends BridgeAbstract {
}
foreach ($results as $post) {
// Skip "nearby results" banner and results
// This only appears when searchNearby is not specified
if ($post->tag == 'h4') {
break;
}
$item = array();
$item = [];
$heading = $post->find('.result-heading a', 0);
$item['uri'] = $heading->href;

View file

@ -1,39 +1,41 @@
<?php
class CrewbayBridge extends BridgeAbstract {
class CrewbayBridge extends BridgeAbstract
{
const MAINTAINER = 'couraudt';
const NAME = 'Crewbay Bridge';
const URI = 'https://www.crewbay.com';
const DESCRIPTION = 'Returns the newest sailing offers.';
const PARAMETERS = array(
array(
'keyword' => array(
const PARAMETERS = [
[
'keyword' => [
'name' => 'Filter by keyword',
'title' => 'Enter the keyword to filter here'
),
'type' => array(
],
'type' => [
'name' => 'Type of search',
'title' => 'Choose between finding a boat or a crew',
'type' => 'list',
'values' => array(
'values' => [
'Find a boat' => 'boats',
'Find a crew' => 'crew'
)
),
'status' => array(
]
],
'status' => [
'name' => 'Status on the boat',
'title' => 'Choose between recreational or professional classified ads',
'type' => 'list',
'values' => array(
'values' => [
'Recreational' => 'recreational',
'Professional' => 'professional'
)
),
'recreational_position' => array(
]
],
'recreational_position' => [
'name' => 'Recreational position wanted',
'title' => 'Filter by recreational position you wanted aboard',
'required' => false,
'type' => 'list',
'values' => array(
'values' => [
'' => '',
'Amateur Crew' => 'Amateur Crew',
'Friendship' => 'Friendship',
@ -41,14 +43,14 @@ class CrewbayBridge extends BridgeAbstract {
'Racing' => 'Racing',
'Voluntary work' => 'Voluntary work',
'Mile building' => 'Mile building'
)
),
'professional_position' => array(
]
],
'professional_position' => [
'name' => 'Professional position wanted',
'title' => 'Filter by professional position you wanted aboard',
'required' => false,
'type' => 'list',
'values' => array(
'values' => [
'' => '',
'1st Engineer' => '1st Engineer',
'1st Mate' => '1st Mate',
@ -99,12 +101,13 @@ class CrewbayBridge extends BridgeAbstract {
'Stew/Masseuse' => 'Stew/Masseuse',
'Manager' => 'Manager',
'Sailing instructor' => 'Sailing instructor'
)
)
)
);
]
]
]
];
public function collectData() {
public function collectData()
{
$url = $this->getURI();
$html = getSimpleHTMLDOM($url) or returnClientError('No results for this query.');
@ -118,9 +121,9 @@ class CrewbayBridge extends BridgeAbstract {
if (!empty($this->getInput('recreational_position')) || !empty($this->getInput('professional_position'))) {
if ($this->getInput('type') == 'boats') {
if ($this->getInput('status') == 'professional') {
$positions = array($annonce->find('.title .position', 0)->plaintext);
$positions = [$annonce->find('.title .position', 0)->plaintext];
} else {
$positions = array(str_replace('Wanted:', '', $annonce->find('.content li', 0)->plaintext));
$positions = [str_replace('Wanted:', '', $annonce->find('.content li', 0)->plaintext)];
}
} else {
$list = $htmlDetail->find('.viewer-details .viewer-list');
@ -141,7 +144,7 @@ class CrewbayBridge extends BridgeAbstract {
}
}
$item = array();
$item = [];
if ($this->getInput('type') == 'boats') {
$titleSelector = '.title h2';
@ -158,7 +161,7 @@ class CrewbayBridge extends BridgeAbstract {
$item['uri'] = $detail->href;
$images = $annonce->find('.avatar img');
$item['enclosures'] = array(end($images)->getAttribute('src'));
$item['enclosures'] = [end($images)->getAttribute('src')];
$content = $htmlDetail->find('.viewer-intro--info', 0)->innertext;
@ -166,7 +169,7 @@ class CrewbayBridge extends BridgeAbstract {
foreach ($sections as $section) {
if ($section->find('.viewer-section-title', 0)) {
$class = str_replace('viewer-', '', explode(' ', $section->getAttribute('class'))[0]);
if (!in_array($class, array('apply', 'photos', 'reviews', 'contact', 'experience', 'qa'))) {
if (!in_array($class, ['apply', 'photos', 'reviews', 'contact', 'experience', 'qa'])) {
// Basic sections
$content .= $section->find('.viewer-section-title h3', 0)->outertext;
$content .= $section->find('.viewer-section-content', 0)->innertext;
@ -192,7 +195,7 @@ class CrewbayBridge extends BridgeAbstract {
$tags = $htmlDetail->find('li.viewer-tags--tag');
foreach ($tags as $tag) {
if (!isset($item['categories'])) {
$item['categories'] = array();
$item['categories'] = [];
}
$text = trim($tag->plaintext);
if (!in_array($text, $item['categories'])) {
@ -203,11 +206,14 @@ class CrewbayBridge extends BridgeAbstract {
$this->items[] = $item;
$limit += 1;
if ($limit == 10) break;
if ($limit == 10) {
break;
}
}
}
public function getURI() {
public function getURI()
{
$uri = parent::getURI();
if ($this->getInput('type') == 'boats') {

View file

@ -1,25 +1,28 @@
<?php
class CryptomeBridge extends BridgeAbstract {
class CryptomeBridge extends BridgeAbstract
{
const MAINTAINER = 'BoboTiG';
const NAME = 'Cryptome';
const URI = 'https://cryptome.org/';
const CACHE_TIMEOUT = 21600; // 6h
const DESCRIPTION = 'Returns the N most recent documents.';
const PARAMETERS = array( array(
'n' => array(
const PARAMETERS = [ [
'n' => [
'name' => 'number of elements',
'type' => 'number',
'required' => true,
'exampleValue' => 10
)
));
]
]];
public function getIcon() {
public function getIcon()
{
return self::URI . '/favicon.ico';
}
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
$number = $this->getInput('n');
@ -29,7 +32,7 @@ class CryptomeBridge extends BridgeAbstract {
$i = 0;
foreach ($html->find('pre', 1)->find('b') as $element) {
foreach ($element->find('a') as $element1) {
$item = array();
$item = [];
$item['uri'] = $element1->href;
$item['title'] = $element->plaintext;
$this->items[] = $item;

View file

@ -1,36 +1,39 @@
<?php
class CubariBridge extends BridgeAbstract
{
const NAME = 'Cubari';
const URI = 'https://cubari.moe';
const DESCRIPTION = 'Parses given cubari-formatted JSON file for updates.';
const MAINTAINER = 'KamaleiZestri';
const PARAMETERS = array(array(
'gist' => array(
const PARAMETERS = [[
'gist' => [
'name' => 'Gist/Raw Url',
'type' => 'text',
'required' => true,
'exampleValue' => 'https://raw.githubusercontent.com/kurisumx/baka/main/ikedan'
)
));
]
]];
private $mangaTitle = '';
public function getName()
{
if (!empty($this->mangaTitle))
if (!empty($this->mangaTitle)) {
return $this->mangaTitle . ' - ' . self::NAME;
else
} else {
return self::NAME;
}
}
public function getURI()
{
if ($this->getInput('gist') != '')
if ($this->getInput('gist') != '') {
return self::URI . '/read/gist/' . $this->getEncodedGist();
else
} else {
return self::URI;
}
}
/**
* The Cubari bridge.
@ -78,12 +81,13 @@ class CubariBridge extends BridgeAbstract
protected function getItemFromChapter($chapnum, $chapter)
{
$item = array();
$item = [];
$item['uri'] = $this->getURI() . '/' . $chapnum;
$item['title'] = 'Chapter ' . $chapnum . ' - ' . $chapter['title'] . ' - ' . $this->mangaTitle;
foreach ($chapter['groups'] as $key => $value)
foreach ($chapter['groups'] as $key => $value) {
$item['author'] = $key;
}
$item['timestamp'] = $chapter['last_updated'];
$item['content'] = '<p>Manga: <a href=' . $this->getURI() . '>' . $this->mangaTitle . '</a> </p>

View file

@ -1,22 +1,24 @@
<?php
class CuriousCatBridge extends BridgeAbstract {
class CuriousCatBridge extends BridgeAbstract
{
const NAME = 'Curious Cat Bridge';
const URI = 'https://curiouscat.me';
const DESCRIPTION = 'Returns list of newest questions and answers for a user profile';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(array(
'username' => array(
const PARAMETERS = [[
'username' => [
'name' => 'Username',
'type' => 'text',
'required' => true,
'exampleValue' => 'koethekoethe',
)
));
]
]];
const CACHE_TIMEOUT = 3600;
public function collectData() {
public function collectData()
{
$url = self::URI . '/api/v2/profile?username=' . urlencode($this->getInput('username'));
$apiJson = getContents($url);
@ -24,7 +26,7 @@ class CuriousCatBridge extends BridgeAbstract {
$apiData = json_decode($apiJson, true);
foreach ($apiData['posts'] as $post) {
$item = array();
$item = [];
$item['author'] = 'Anonymous';
@ -42,8 +44,8 @@ class CuriousCatBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('username'))) {
return self::URI . '/' . $this->getInput('username');
}
@ -51,8 +53,8 @@ class CuriousCatBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName() {
public function getName()
{
if (!is_null($this->getInput('username'))) {
return $this->getInput('username') . ' - Curious Cat';
}
@ -60,8 +62,8 @@ class CuriousCatBridge extends BridgeAbstract {
return parent::getName();
}
private function processContent($post) {
private function processContent($post)
{
$author = 'Anonymous';
if ($post['senderData']['id'] !== false) {
@ -85,7 +87,8 @@ EOD;
return $content;
}
private function ellipsisTitle($text) {
private function ellipsisTitle($text)
{
$length = 150;
if (strlen($text) > $length) {
@ -96,13 +99,12 @@ EOD;
return $text;
}
private function formatUrls($content) {
private function formatUrls($content)
{
return preg_replace(
'/(http[s]{0,1}\:\/\/[a-zA-Z0-9.\/\?\&=\-_]{4,})/ims',
'<a target="_blank" href="$1" target="_blank">$1</a> ',
$content
);
}
}

View file

@ -1,20 +1,25 @@
<?php
class CyanideAndHappinessBridge extends BridgeAbstract {
class CyanideAndHappinessBridge extends BridgeAbstract
{
const NAME = 'Cyanide & Happiness';
const URI = 'https://explosm.net/';
const DESCRIPTION = 'The Webcomic from Explosm.';
const MAINTAINER = 'sal0max';
const CACHE_TIMEOUT = 60 * 60 * 2; // 2 hours
public function getIcon() {
public function getIcon()
{
return self::URI . 'favicon-32x32.png';
}
public function getURI(){
public function getURI()
{
return self::URI . 'comics/latest#comic';
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM($this->getUri());
foreach ($html->find('[class*=ComicImage]') as $element) {
@ -23,14 +28,14 @@ class CyanideAndHappinessBridge extends BridgeAbstract {
$image = $element->find('img', 0)->src;
$link = $html->find('[rel=canonical]', 0)->href;
$item = array(
$item = [
'uid' => $link,
'author' => $author,
'title' => $date,
'uri' => $link . '#comic',
'timestamp' => str_replace('.', '-', $date) . 'T00:00:00Z',
'content' => "<img src=\"$image\" />"
);
];
$this->items[] = $item;
}
}

View file

@ -1,54 +1,55 @@
<?php
class DailymotionBridge extends BridgeAbstract {
class DailymotionBridge extends BridgeAbstract
{
const MAINTAINER = 'mitsukarenai';
const NAME = 'Dailymotion Bridge';
const URI = 'https://www.dailymotion.com/';
const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Returns the 5 newest videos by username/playlist or search';
const PARAMETERS = array (
'By username' => array(
'u' => array(
const PARAMETERS = [
'By username' => [
'u' => [
'name' => 'username',
'required' => true,
'exampleValue' => 'moviepilot',
)
),
'By playlist id' => array(
'p' => array(
]
],
'By playlist id' => [
'p' => [
'name' => 'playlist id',
'required' => true,
'exampleValue' => 'x6xyc6',
)
),
'From search results' => array(
's' => array(
]
],
'From search results' => [
's' => [
'name' => 'Search keyword',
'required' => true,
'exampleValue' => 'matrix',
),
'pa' => array(
],
'pa' => [
'name' => 'Page',
'type' => 'number',
'defaultValue' => 1,
)
)
);
]
]
];
private $feedName = '';
private $apiUrl = 'https://api.dailymotion.com';
private $apiFields = 'created_time,description,id,owner.screenname,tags,thumbnail_url,title,url';
public function getIcon() {
public function getIcon()
{
return 'https://static1-ssl.dmcdn.net/images/neon/favicons/android-icon-36x36.png.vf806ca4ed0deed812';
}
public function collectData() {
public function collectData()
{
if ($this->queriedContext === 'By username' || $this->queriedContext === 'By playlist id') {
$apiJson = getContents($this->getApiUrl());
$apiData = json_decode($apiJson, true);
@ -56,7 +57,7 @@ class DailymotionBridge extends BridgeAbstract {
$this->feedName = $this->getPlaylistTitle($this->getInput('p'));
foreach ($apiData['list'] as $apiItem) {
$item = array();
$item = [];
$item['uri'] = $apiItem['url'];
$item['uid'] = $apiItem['id'];
@ -73,11 +74,10 @@ class DailymotionBridge extends BridgeAbstract {
}
if ($this->queriedContext === 'From search results') {
$html = getSimpleHTMLDOM($this->getURI());
foreach ($html->find('div.media a.preview_link') as $element) {
$item = array();
$item = [];
$item['id'] = str_replace('/video/', '', strtok($element->href, '_'));
$metadata = $this->getMetadata($item['id']);
@ -109,7 +109,8 @@ class DailymotionBridge extends BridgeAbstract {
}
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'By username':
$specific = $this->getInput('u');
@ -125,13 +126,15 @@ class DailymotionBridge extends BridgeAbstract {
case 'From search results':
$specific = $this->getInput('s');
break;
default: return parent::getName();
default:
return parent::getName();
}
return $specific . ' : Dailymotion';
}
public function getURI(){
public function getURI()
{
$uri = self::URI;
switch ($this->queriedContext) {
case 'By username':
@ -153,13 +156,15 @@ class DailymotionBridge extends BridgeAbstract {
$uri .= '/' . $pa;
}
break;
default: return parent::getURI();
default:
return parent::getURI();
}
return $uri;
}
private function getMetadata($id) {
$metadata = array();
private function getMetadata($id)
{
$metadata = [];
$html = getSimpleHTMLDOM(self::URI . 'video/' . $id);
@ -176,7 +181,8 @@ class DailymotionBridge extends BridgeAbstract {
return $metadata;
}
private function getPlaylistTitle($id) {
private function getPlaylistTitle($id)
{
$title = '';
$url = self::URI . 'playlist/' . $id;
@ -187,8 +193,8 @@ class DailymotionBridge extends BridgeAbstract {
return $title;
}
private function getApiUrl() {
private function getApiUrl()
{
switch ($this->queriedContext) {
case 'By username':
return $this->apiUrl . '/user/' . $this->getInput('u')

View file

@ -1,47 +1,51 @@
<?php
class DanbooruBridge extends BridgeAbstract {
class DanbooruBridge extends BridgeAbstract
{
const MAINTAINER = 'mitsukarenai, logmanoriginal';
const NAME = 'Danbooru';
const URI = 'http://donmai.us/';
const CACHE_TIMEOUT = 1800; // 30min
const DESCRIPTION = 'Returns images from given page';
const PARAMETERS = array(
'global' => array(
'p' => array(
const PARAMETERS = [
'global' => [
'p' => [
'name' => 'page',
'defaultValue' => 1,
'type' => 'number'
),
't' => array(
],
't' => [
'type' => 'text',
'name' => 'tags',
'exampleValue' => 'cosplay',
)
),
0 => array()
);
]
],
0 => []
];
const PATHTODATA = 'article';
const IDATTRIBUTE = 'data-id';
const TAGATTRIBUTE = 'alt';
protected function getFullURI(){
protected function getFullURI()
{
return $this->getURI()
. 'posts?&page=' . $this->getInput('p')
. '&tags=' . urlencode($this->getInput('t'));
}
protected function getTags($element){
protected function getTags($element)
{
return $element->find('img', 0)->getAttribute(static::TAGATTRIBUTE);
}
protected function getItemFromElement($element){
protected function getItemFromElement($element)
{
// Fix links
defaultLinkTo($element, $this->getURI());
$item = array();
$item = [];
$item['uri'] = html_entity_decode($element->find('a', 0)->href);
$item['postid'] = (int)preg_replace('/[^0-9]/', '', $element->getAttribute(static::IDATTRIBUTE));
$item['timestamp'] = time();
@ -58,7 +62,8 @@ class DanbooruBridge extends BridgeAbstract {
return $item;
}
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOMCached($this->getFullURI());
foreach ($html->find(static::PATHTODATA) as $element) {

View file

@ -1,18 +1,19 @@
<?php
class DansTonChatBridge extends BridgeAbstract {
class DansTonChatBridge extends BridgeAbstract
{
const MAINTAINER = 'Astalaseven';
const NAME = 'DansTonChat Bridge';
const URI = 'https://danstonchat.com/';
const CACHE_TIMEOUT = 21600; //6h
const DESCRIPTION = 'Returns latest quotes from DansTonChat.';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI . 'latest.html');
foreach ($html->find('div.item') as $element) {
$item = array();
$item = [];
$item['uri'] = $element->find('a', 0)->href;
$titleContent = $element->find('h3 a', 0);
if ($titleContent) {

View file

@ -1,15 +1,17 @@
<?php
class DarkReadingBridge extends FeedExpander {
class DarkReadingBridge extends FeedExpander
{
const MAINTAINER = 'ORelio';
const NAME = 'Dark Reading Bridge';
const URI = 'https://www.darkreading.com/';
const DESCRIPTION = 'Returns the newest articles from Dark Reading';
const PARAMETERS = array( array(
'feed' => array(
const PARAMETERS = [ [
'feed' => [
'name' => 'Feed',
'type' => 'list',
'values' => array(
'values' => [
'All Dark Reading Stories' => '000_AllArticles',
'Attacks/Breaches' => '644_Attacks/Breaches',
'Application Security' => '645_Application%20Security',
@ -32,12 +34,13 @@ class DarkReadingBridge extends FeedExpander {
'Advanced Threats' => '662_Advanced%20Threats',
'Insider Threats' => '663_Insider%20Threats',
'Vulnerability Management' => '664_Vulnerability%20Management',
)
),
]
],
'limit' => self::LIMIT,
));
]];
public function collectData(){
public function collectData()
{
$feed = $this->getInput('feed');
$feed_splitted = explode('_', $feed);
$feed_id = $feed_splitted[0];
@ -53,28 +56,32 @@ class DarkReadingBridge extends FeedExpander {
$this->collectExpandableDatas($feed_url, $limit);
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
$item = parent::parseItem($newsItem);
$article = getSimpleHTMLDOMCached($item['uri']);
$item['content'] = $this->extractArticleContent($article);
$item['enclosures'] = array(); //remove author profile picture
$item['enclosures'] = []; //remove author profile picture
$image = $article->find('meta[property="og:image"]', 0);
if (is_object($image)) {
$image = $image->content;
$item['enclosures'] = array($image);
$item['enclosures'] = [$image];
}
return $item;
}
private function extractArticleContent($article){
private function extractArticleContent($article)
{
$content = $article->find('div.article-content', 0)->innertext;
foreach (array(
foreach (
[
'<div class="divsplitter',
'<div style="float: left; margin-right: 2px;',
'<div class="more-insights',
'<div id="more-insights',
) as $div_start) {
] as $div_start
) {
$content = stripRecursiveHTMLSection($content, 'div', $div_start);
}

View file

@ -1,17 +1,18 @@
<?php
class DauphineLibereBridge extends FeedExpander {
class DauphineLibereBridge extends FeedExpander
{
const MAINTAINER = 'qwertygc';
const NAME = 'Dauphine Bridge';
const URI = 'https://www.ledauphine.com/';
const CACHE_TIMEOUT = 7200; // 2h
const DESCRIPTION = 'Returns the newest articles.';
const PARAMETERS = array( array(
'u' => array(
const PARAMETERS = [ [
'u' => [
'name' => 'Catégorie de l\'article',
'type' => 'list',
'values' => array(
'values' => [
'À la une' => '',
'France Monde' => 'france-monde',
'Faits Divers' => 'faits-divers',
@ -27,11 +28,12 @@ class DauphineLibereBridge extends FeedExpander {
'Savoie' => 'savoie',
'Haute-Savoie' => 'haute-savoie',
'Vaucluse' => 'vaucluse'
)
)
));
]
]
]];
public function collectData(){
public function collectData()
{
$url = self::URI . 'rss';
if (empty($this->getInput('u'))) {
@ -41,13 +43,15 @@ class DauphineLibereBridge extends FeedExpander {
$this->collectExpandableDatas($url, 10);
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
$item = parent::parseItem($newsItem);
$item['content'] = $this->extractContent($item['uri']);
return $item;
}
private function extractContent($url){
private function extractContent($url)
{
$html2 = getSimpleHTMLDOMCached($url);
foreach ($html2->find('.noprint, link, script, iframe, .shareTool, .contentInfo') as $remove) {
$remove->outertext = '';

View file

@ -1,11 +1,14 @@
<?php
class DavesTrailerPageBridge extends BridgeAbstract {
class DavesTrailerPageBridge extends BridgeAbstract
{
const MAINTAINER = 'johnnygroovy';
const NAME = 'Daves Trailer Page Bridge';
const URI = 'https://www.davestrailerpage.co.uk/';
const DESCRIPTION = 'Last trailers in HD thanks to Dave.';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(static::URI)
or returnClientError('No results for this query.');
@ -17,7 +20,7 @@ class DavesTrailerPageBridge extends BridgeAbstract {
continue;
}
$item = array();
$item = [];
// title
$item['title'] = $tr->find('td', 0)->find('b', 0)->plaintext;

View file

@ -1,47 +1,48 @@
<?php
class DealabsBridge extends PepperBridgeAbstract {
class DealabsBridge extends PepperBridgeAbstract
{
const NAME = 'Dealabs Bridge';
const URI = 'https://www.dealabs.com/';
const DESCRIPTION = 'Affiche les Deals de Dealabs';
const MAINTAINER = 'sysadminstory';
const PARAMETERS = array(
'Recherche par Mot(s) clé(s)' => array (
'q' => array(
const PARAMETERS = [
'Recherche par Mot(s) clé(s)' => [
'q' => [
'name' => 'Mot(s) clé(s)',
'type' => 'text',
'exampleValue' => 'lampe',
'required' => true
),
'hide_expired' => array(
],
'hide_expired' => [
'name' => 'Masquer les éléments expirés',
'type' => 'checkbox',
),
'hide_local' => array(
],
'hide_local' => [
'name' => 'Masquer les deals locaux',
'type' => 'checkbox',
'title' => 'Masquer les deals en magasins physiques',
),
'priceFrom' => array(
],
'priceFrom' => [
'name' => 'Prix minimum',
'type' => 'text',
'title' => 'Prix mnimum en euros',
'required' => false
),
'priceTo' => array(
],
'priceTo' => [
'name' => 'Prix maximum',
'type' => 'text',
'title' => 'Prix maximum en euros',
'required' => false
),
),
],
],
'Deals par groupe' => array(
'group' => array(
'Deals par groupe' => [
'group' => [
'name' => 'Groupe',
'type' => 'list',
'title' => 'Groupe dont il faut afficher les deals',
'values' => array(
'values' => [
'Abattants WC' => 'abattants-wc',
'Abonnement PlayStation Plus' => 'playstation-plus',
'Abonnements cinéma' => 'abonnements-cinema',
@ -1868,42 +1869,42 @@ class DealabsBridge extends PepperBridgeAbstract {
'Yeelight' => 'xiaomi-yeelight',
'Yoshi&#039;s Crafted World' => 'yoshi-crafted-world',
'Zoos' => 'zoos',
)
),
'order' => array(
]
],
'order' => [
'name' => 'Trier par',
'type' => 'list',
'title' => 'Ordre de tri des deals',
'values' => array(
'values' => [
'Du deal le plus Hot au moins Hot' => '-hot',
'Du deal le plus récent au plus ancien' => '-nouveaux',
)
)
),
'Surveillance Discussion' => array(
'url' => array(
]
]
],
'Surveillance Discussion' => [
'url' => [
'name' => 'URL de la discussion',
'type' => 'text',
'required' => true,
'title' => 'URL discussion à surveiller: https://www.dealabs.com/discussions/titre-1234',
'exampleValue' => 'https://www.dealabs.com/discussions/jeux-steam-gratuits-gleam-woobox-etc-1071415',
),
],
'only_with_url' => array(
'only_with_url' => [
'name' => 'Exclure les commentaires sans URL',
'type' => 'checkbox',
'title' => 'Exclure les commentaires ne contenant pas d\'URL dans le flux',
'defaultValue' => false,
)
]
)
]
);
];
public $lang = array(
'bridge-uri' => SELF::URI,
'bridge-name' => SELF::NAME,
public $lang = [
'bridge-uri' => self::URI,
'bridge-name' => self::NAME,
'context-keyword' => 'Recherche par Mot(s) clé(s)',
'context-group' => 'Deals par groupe',
'context-talk' => 'Surveillance Discussion',
@ -1911,9 +1912,9 @@ class DealabsBridge extends PepperBridgeAbstract {
'request-error' => 'Impossible de joindre Dealabs',
'thread-error' => 'Impossible de déterminer l\'ID de la discussion. Vérifiez l\'URL que vous avez entré',
'no-results' => 'Il n&#039;y a rien à afficher pour le moment :(',
'relative-date-indicator' => array(
'relative-date-indicator' => [
'il y a',
),
],
'price' => 'Prix',
'shipping' => 'Livraison',
'origin' => 'Origine',
@ -1921,7 +1922,7 @@ class DealabsBridge extends PepperBridgeAbstract {
'title-keyword' => 'Recherche',
'title-group' => 'Groupe',
'title-talk' => 'Surveillance Discussion',
'local-months' => array(
'local-months' => [
'janvier',
'février',
'mars',
@ -1934,8 +1935,8 @@ class DealabsBridge extends PepperBridgeAbstract {
'octobre',
'novembre',
'décembre'
),
'local-time-relative' => array(
],
'local-time-relative' => [
'il y a ',
'min',
'h',
@ -1944,22 +1945,19 @@ class DealabsBridge extends PepperBridgeAbstract {
'mois',
'ans',
'et '
),
'date-prefixes' => array(
],
'date-prefixes' => [
'Actualisé ',
),
'relative-date-alt-prefixes' => array(
],
'relative-date-alt-prefixes' => [
'Actualisé ',
),
'relative-date-ignore-suffix' => array(
),
],
'relative-date-ignore-suffix' => [
],
'localdeal' => array(
'localdeal' => [
'Local',
'Pays d\'expédition'
),
);
],
];
}

View file

@ -1,40 +1,41 @@
<?php
class DemoBridge extends BridgeAbstract {
class DemoBridge extends BridgeAbstract
{
const MAINTAINER = 'teromene';
const NAME = 'DemoBridge';
const URI = 'http://github.com/rss-bridge/rss-bridge';
const DESCRIPTION = 'Bridge used for demos';
const PARAMETERS = array(
'testCheckbox' => array(
'testCheckbox' => array(
const PARAMETERS = [
'testCheckbox' => [
'testCheckbox' => [
'type' => 'checkbox',
'name' => 'test des checkbox'
)
),
'testList' => array(
'testList' => array(
]
],
'testList' => [
'testList' => [
'type' => 'list',
'name' => 'test des listes',
'values' => array(
'values' => [
'Test' => 'test',
'Test 2' => 'test2'
)
)
),
'testNumber' => array(
'testNumber' => array(
]
]
],
'testNumber' => [
'testNumber' => [
'type' => 'number',
'name' => 'test des numéros',
'exampleValue' => '1515632'
)
)
);
]
]
];
public function collectData(){
$item = array();
public function collectData()
{
$item = [];
$item['author'] = 'Me!';
$item['title'] = 'Test';
$item['content'] = 'Awesome content !';

View file

@ -1,37 +1,40 @@
<?php
class DerpibooruBridge extends BridgeAbstract {
class DerpibooruBridge extends BridgeAbstract
{
const NAME = 'Derpibooru Bridge';
const URI = 'https://derpibooru.org/';
const DESCRIPTION = 'Returns newest images from a Derpibooru search';
const CACHE_TIMEOUT = 300; // 5min
const MAINTAINER = 'Roliga';
const PARAMETERS = array(
array(
'f' => array(
const PARAMETERS = [
[
'f' => [
'name' => 'Filter',
'type' => 'list',
'values' => array(
'values' => [
'Everything' => 56027,
'18+ R34' => 37432,
'Legacy Default' => 37431,
'18+ Dark' => 37429,
'Maximum Spoilers' => 37430,
'Default' => 100073
),
],
'defaultValue' => 56027
),
'q' => array(
],
'q' => [
'name' => 'Query',
'required' => true,
'exampleValue' => 'dog',
)
)
);
]
]
];
public function detectParameters($url){
$params = array();
public function detectParameters($url)
{
$params = [];
// Search page e.g. https://derpibooru.org/search?q=cute
$regex = '/^(https?:\/\/)?(www\.)?derpibooru.org\/search.+q=([^\/&?\n]+)/';
@ -50,7 +53,8 @@ class DerpibooruBridge extends BridgeAbstract {
return null;
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('q'))) {
return 'Derpibooru search for: '
. $this->getInput('q');
@ -59,7 +63,8 @@ class DerpibooruBridge extends BridgeAbstract {
}
}
public function getURI(){
public function getURI()
{
if (!is_null($this->getInput('f')) && !is_null($this->getInput('q'))) {
return self::URI
. 'search?filter_id='
@ -71,7 +76,8 @@ class DerpibooruBridge extends BridgeAbstract {
}
}
public function collectData(){
public function collectData()
{
$queryJson = json_decode(getContents(
self::URI
. 'api/v1/json/search/images?filter_id='
@ -81,7 +87,7 @@ class DerpibooruBridge extends BridgeAbstract {
));
foreach ($queryJson->images as $post) {
$item = array();
$item = [];
$postUri = self::URI . $post->id;
@ -89,7 +95,7 @@ class DerpibooruBridge extends BridgeAbstract {
$item['title'] = $post->name;
$item['timestamp'] = strtotime($post->created_at);
$item['author'] = $post->uploader;
$item['enclosures'] = array($post->view_url);
$item['enclosures'] = [$post->view_url];
$item['categories'] = $post->tags;
$item['content'] = '<p><a href="' // image preview

View file

@ -1,6 +1,7 @@
<?php
class DesoutterBridge extends BridgeAbstract {
class DesoutterBridge extends BridgeAbstract
{
const CATEGORY_NEWS = 'News & Events';
const CATEGORY_INDUSTRY = 'Industry 4.0 News';
@ -10,14 +11,14 @@ class DesoutterBridge extends BridgeAbstract {
const MAINTAINER = 'logmanoriginal';
const CACHE_TIMEOUT = 86400; // 24 hours
const PARAMETERS = array(
self::CATEGORY_NEWS => array(
'news_lang' => array(
const PARAMETERS = [
self::CATEGORY_NEWS => [
'news_lang' => [
'name' => 'Language',
'type' => 'list',
'title' => 'Select your language',
'defaultValue' => 'https://www.desouttertools.com/about-desoutter/news-events',
'values' => array(
'values' => [
'Corporate'
=> 'https://www.desouttertools.com/about-desoutter/news-events',
'Česko'
@ -58,16 +59,16 @@ class DesoutterBridge extends BridgeAbstract {
=> 'https://www.desoutter.com.tr/desoutter-hakkinda/haberler-etkinlikler',
'中国'
=> 'https://www.desouttertools.com.cn/guan-yu-ma-tou/xin-wen-he-huo-dong',
)
),
),
self::CATEGORY_INDUSTRY => array(
'industry_lang' => array(
]
],
],
self::CATEGORY_INDUSTRY => [
'industry_lang' => [
'name' => 'Language',
'type' => 'list',
'title' => 'Select your language',
'defaultValue' => 'Corporate',
'values' => array(
'values' => [
'Corporate'
=> 'https://www.desouttertools.com/industry-4-0/news',
'Česko'
@ -108,28 +109,29 @@ class DesoutterBridge extends BridgeAbstract {
=> 'https://www.desoutter.com.tr/endustri-4-0/haberler',
'中国'
=> 'https://www.desouttertools.com.cn/industry-4-0/news',
)
),
),
'global' => array(
'full' => array(
]
],
],
'global' => [
'full' => [
'name' => 'Load full articles',
'type' => 'checkbox',
'title' => 'Enable to load the full article for each item'
),
'limit' => array(
],
'limit' => [
'name' => 'Limit',
'type' => 'number',
'required' => true,
'defaultValue' => 3,
'title' => "Maximum number of items to return in the feed.\n0 = unlimited"
)
)
);
]
]
];
private $title;
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case self::CATEGORY_NEWS:
return $this->getInput('news_lang') ?: parent::getURI();
@ -140,12 +142,13 @@ class DesoutterBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName() {
public function getName()
{
return isset($this->title) ? $this->title . ' - ' . parent::getName() : parent::getName();
}
public function collectData() {
public function collectData()
{
// Uncomment to generate list of languages automtically (dev mode)
/*
switch($this->queriedContext) {
@ -165,7 +168,7 @@ class DesoutterBridge extends BridgeAbstract {
$limit = $this->getInput('limit') ?: 0;
foreach ($html->find('article') as $article) {
$item = array();
$item = [];
$item['uri'] = $article->find('a', 0)->href;
$item['title'] = $article->find('a[title]', 0)->title;
@ -178,12 +181,14 @@ class DesoutterBridge extends BridgeAbstract {
$this->items[] = $item;
if ($limit > 0 && count($this->items) >= $limit) break;
if ($limit > 0 && count($this->items) >= $limit) {
break;
}
}
}
}
private function getFullNewsArticle($uri) {
private function getFullNewsArticle($uri)
{
$html = getSimpleHTMLDOMCached($uri);
$html = defaultLinkTo($html, $this->getURI());
@ -197,7 +202,8 @@ class DesoutterBridge extends BridgeAbstract {
* on the 'Corporate' site.
* @return void
*/
private function extractNewsLanguages() {
private function extractNewsLanguages()
{
$html = getSimpleHTMLDOMCached('https://www.desouttertools.com/about-desoutter/news-events');
$html = defaultLinkTo($html, static::URI);
@ -222,7 +228,8 @@ class DesoutterBridge extends BridgeAbstract {
* on the 'Corporate' site.
* @return void
*/
private function extractIndustryLanguages() {
private function extractIndustryLanguages()
{
$html = getSimpleHTMLDOMCached('https://www.desouttertools.com/industry-4-0/news');
$html = defaultLinkTo($html, static::URI);

View file

@ -1,6 +1,7 @@
<?php
class DevToBridge extends BridgeAbstract {
class DevToBridge extends BridgeAbstract
{
const CONTEXT_BY_TAG = 'By tag';
const NAME = 'dev.to Bridge';
@ -9,25 +10,26 @@ class DevToBridge extends BridgeAbstract {
const MAINTAINER = 'logmanoriginal';
const CACHE_TIMEOUT = 10800; // 15 min.
const PARAMETERS = array(
self::CONTEXT_BY_TAG => array(
'tag' => array(
const PARAMETERS = [
self::CONTEXT_BY_TAG => [
'tag' => [
'name' => 'Tag',
'type' => 'text',
'required' => true,
'title' => 'Insert your tag',
'exampleValue' => 'python'
),
'full' => array(
],
'full' => [
'name' => 'Full article',
'type' => 'checkbox',
'required' => false,
'title' => 'Enable to receive the full article for each item'
)
)
);
]
]
];
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case self::CONTEXT_BY_TAG:
if ($tag = $this->getInput('tag')) {
@ -39,12 +41,14 @@ class DevToBridge extends BridgeAbstract {
return parent::getURI();
}
public function getIcon() {
public function getIcon()
{
return 'https://practicaldev-herokuapp-com.freetls.fastly.net/assets/
apple-icon-5c6fa9f2bce280428589c6195b7f1924206a53b782b371cfe2d02da932c8c173.png';
}
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOMCached($this->getURI());
$html = defaultLinkTo($html, static::URI);
@ -53,7 +57,7 @@ apple-icon-5c6fa9f2bce280428589c6195b7f1924206a53b782b371cfe2d02da932c8c173.png'
or returnServerError('Could not find articles!');
foreach ($articles as $article) {
$item = array();
$item = [];
$item['uri'] = $article->find('a[id*=article-link]', 0)->href;
$item['title'] = $article->find('h2 > a', 0)->plaintext;
@ -62,7 +66,7 @@ apple-icon-5c6fa9f2bce280428589c6195b7f1924206a53b782b371cfe2d02da932c8c173.png'
$item['author'] = $article->find('a.crayons-story__secondary.fw-medium', 0)->plaintext;
// Profile image
$item['enclosures'] = array($article->find('img', 0)->src);
$item['enclosures'] = [$article->find('img', 0)->src];
if ($this->getInput('full')) {
$fullArticle = $this->getFullArticle($item['uri']);
@ -85,7 +89,8 @@ EOD;
}
}
public function getName() {
public function getName()
{
if (!is_null($this->getInput('tag'))) {
return ucfirst($this->getInput('tag')) . ' - dev.to';
}
@ -93,7 +98,8 @@ EOD;
return parent::getName();
}
private function getFullArticle($url) {
private function getFullArticle($url)
{
$html = getSimpleHTMLDOMCached($url);
$html = defaultLinkTo($html, static::URI);

View file

@ -2,7 +2,6 @@
class DeveloppezDotComBridge extends FeedExpander
{
const MAINTAINER = 'Binnette';
const NAME = 'Developpez.com Actus (FR)';
const URI = 'https://www.developpez.com/';
@ -11,20 +10,20 @@ class DeveloppezDotComBridge extends FeedExpander
const CACHE_TIMEOUT = 1800; // 30min
const DESCRIPTION = 'Returns complete posts from developpez.com';
// Encodings used by Developpez.com in their articles body
const ENCONDINGS = array('Windows-1252', 'UTF-8');
const PARAMETERS = array(
array(
'limit' => array(
const ENCONDINGS = ['Windows-1252', 'UTF-8'];
const PARAMETERS = [
[
'limit' => [
'name' => 'Max items',
'type' => 'number',
'defaultValue' => 5,
),
],
// list of the differents RSS availables
'domain' => array(
'domain' => [
'type' => 'list',
'name' => 'Domaine',
'title' => 'Chosissez un sous-domaine',
'values' => array(
'values' => [
'= Domaine principal =' => 'www',
'4d' => '4d',
'abbyy' => 'abbyy',
@ -159,10 +158,10 @@ class DeveloppezDotComBridge extends FeedExpander
'xhtml' => 'xhtml',
'xml' => 'xml',
'zend-framework' => 'zend-framework'
),
)
)
);
],
]
]
];
/**
* Return the RSS url for selected domain
@ -364,7 +363,7 @@ class DeveloppezDotComBridge extends FeedExpander
private function getAllVideoUrl($item)
{
// Array of video url
$url = array();
$url = [];
// Developpez use a div with the class video-container
$divsVideo = $item->find('div.video-container');

View file

@ -1,20 +1,22 @@
<?php
class DiarioDeNoticiasBridge extends BridgeAbstract {
class DiarioDeNoticiasBridge extends BridgeAbstract
{
const NAME = 'Diário de Notícias (PT)';
const URI = 'https://dn.pt';
const DESCRIPTION = 'Diário de Notícias (DN.PT)';
const MAINTAINER = 'somini';
const PARAMETERS = array(
'Tag' => array(
'n' => array(
const PARAMETERS = [
'Tag' => [
'n' => [
'name' => 'Tag Name',
'required' => true,
'exampleValue' => 'rogerio-casanova',
)
)
);
]
]
];
const MONPT = array(
const MONPT = [
'jan',
'fev',
'mar',
@ -27,13 +29,15 @@ class DiarioDeNoticiasBridge extends BridgeAbstract {
'out',
'nov',
'dez',
);
];
public function getIcon() {
public function getIcon()
{
return 'https://static.globalnoticias.pt/dn/common/images/favicons/favicon-128.png';
}
public function getName() {
public function getName()
{
switch ($this->queriedContext) {
case 'Tag':
$name = self::NAME . ' | Tag | ' . $this->getInput('n');
@ -44,7 +48,8 @@ class DiarioDeNoticiasBridge extends BridgeAbstract {
return $name;
}
public function getURI() {
public function getURI()
{
switch ($this->queriedContext) {
case 'Tag':
$url = self::URI . '/tag/' . $this->getInput('n') . '.html';
@ -55,12 +60,13 @@ class DiarioDeNoticiasBridge extends BridgeAbstract {
return $url;
}
public function collectData() {
public function collectData()
{
$archives = self::getURI();
$html = getSimpleHTMLDOMCached($archives);
foreach ($html->find('article') as $element) {
$item = array();
$item = [];
$title = $element->find('.t-am-title', 0);
$link = $element->find('a.t-am-text', 0);
@ -79,6 +85,5 @@ class DiarioDeNoticiasBridge extends BridgeAbstract {
$this->items[] = $item;
}
}
}

View file

@ -1,5 +1,7 @@
<?php
class DiarioDoAlentejoBridge extends BridgeAbstract {
class DiarioDoAlentejoBridge extends BridgeAbstract
{
const MAINTAINER = 'somini';
const NAME = 'Diário do Alentejo';
const URI = 'https://www.diariodoalentejo.pt';
@ -7,7 +9,7 @@ class DiarioDoAlentejoBridge extends BridgeAbstract {
const CACHE_TIMEOUT = 28800; // 8h
/* This is used to hack around obtaining a timestamp. It's just a list of Month names in Portuguese ... */
const PT_MONTH_NAMES = array(
const PT_MONTH_NAMES = [
'janeiro',
'fevereiro',
'março',
@ -19,18 +21,20 @@ class DiarioDoAlentejoBridge extends BridgeAbstract {
'setembro',
'outubro',
'novembro',
'dezembro');
'dezembro'];
public function getIcon() {
public function getIcon()
{
return 'https://www.diariodoalentejo.pt/images/favicon/apple-touch-icon.png';
}
public function collectData(){
public function collectData()
{
/* This is slow as molasses (>30s!), keep the cache timeout high to avoid killing the host */
$html = getSimpleHTMLDOMCached($this->getURI() . '/pt/noticias-listagem.aspx');
foreach ($html->find('.list_news .item') as $element) {
$item = array();
$item = [];
$item_link = $element->find('.body h2.title a', 0);
/* Another broken URL, see also `bridges/ComboiosDePortugalBridge.php` */
@ -38,9 +42,14 @@ class DiarioDoAlentejoBridge extends BridgeAbstract {
$item['title'] = $item_link->innertext;
$item['timestamp'] = str_ireplace(
array_map(function($name) { return ' ' . $name . ' '; }, self::PT_MONTH_NAMES),
array_map(function($num) { return sprintf('-%02d-', $num); }, range(1, sizeof(self::PT_MONTH_NAMES))),
$element->find('span.date', 0)->innertext);
array_map(function ($name) {
return ' ' . $name . ' ';
}, self::PT_MONTH_NAMES),
array_map(function ($num) {
return sprintf('-%02d-', $num);
}, range(1, sizeof(self::PT_MONTH_NAMES))),
$element->find('span.date', 0)->innertext
);
/* Fix the Image URL */
$item_image = $element->find('img.thumb', 0);

View file

@ -1,46 +1,47 @@
<?php
class DiceBridge extends BridgeAbstract {
class DiceBridge extends BridgeAbstract
{
const MAINTAINER = 'rogerdc';
const NAME = 'Dice Unofficial RSS';
const URI = 'https://www.dice.com/';
const DESCRIPTION = 'The Unofficial Dice RSS';
// const CACHE_TIMEOUT = 86400; // 1 day
const PARAMETERS = array(array(
'for_one' => array(
const PARAMETERS = [[
'for_one' => [
'name' => 'With at least one of the words',
'required' => false,
),
'for_all' => array(
],
'for_all' => [
'name' => 'With all of the words',
'required' => false,
),
'for_exact' => array(
],
'for_exact' => [
'name' => 'With the exact phrase',
'required' => false,
),
'for_none' => array(
],
'for_none' => [
'name' => 'With none of these words',
'required' => false,
),
'for_jt' => array(
],
'for_jt' => [
'name' => 'Within job title',
'required' => false,
),
'for_com' => array(
],
'for_com' => [
'name' => 'Within company name',
'required' => false,
),
'for_loc' => array(
],
'for_loc' => [
'name' => 'City, State, or ZIP code',
'required' => false,
),
'radius' => array(
],
'radius' => [
'name' => 'Radius in miles',
'type' => 'list',
'required' => false,
'values' => array(
'values' => [
'Exact Location' => 'El',
'Within 5 miles' => '5',
'Within 10 miles' => '10',
@ -50,14 +51,14 @@ class DiceBridge extends BridgeAbstract {
'Within 50 miles' => '50',
'Within 75 miles' => '75',
'Within 100 miles' => '100',
),
],
'defaultValue' => '0',
),
'jtype' => array(
],
'jtype' => [
'name' => 'Job type',
'type' => 'list',
'required' => false,
'values' => array(
'values' => [
'Full-Time' => 'Full Time',
'Part-Time' => 'Part Time',
'Contract - Independent' => 'Contract Independent',
@ -66,20 +67,22 @@ class DiceBridge extends BridgeAbstract {
'Contract to Hire - W2' => 'C2H W2',
'Third Party - Contract - Corp-to-Corp' => 'Contract Corp-To-Corp',
'Third Party - Contract to Hire - Corp-to-Corp' => 'C2H Corp-To-Corp',
),
],
'defaultValue' => 'Full Time',
),
'telecommute' => array(
],
'telecommute' => [
'name' => 'Telecommute',
'type' => 'checkbox',
),
));
],
]];
public function getIcon() {
public function getIcon()
{
return 'https://assets.dice.com/techpro/img/favicons/favicon.ico';
}
public function collectData() {
public function collectData()
{
$uri = 'https://www.dice.com/jobs/advancedResult.html';
$uri .= '?for_one=' . urlencode($this->getInput('for_one'));
$uri .= '&for_all=' . urlencode($this->getInput('for_all'));
@ -99,7 +102,7 @@ class DiceBridge extends BridgeAbstract {
$html = getSimpleHTMLDOM($uri);
foreach ($html->find('div.complete-serp-result-div') as $element) {
$item = array();
$item = [];
// Title
$masterLink = $element->find('a[id^=position]', 0);
$item['title'] = $masterLink->title;
@ -111,8 +114,9 @@ class DiceBridge extends BridgeAbstract {
$item['id'] = $masterLink->value;
// Image
$image = $element->find('img', 0);
if ($image)
if ($image) {
$item['image'] = $image->getAttribute('src');
}
// Content
$shortdesc = $element->find('.shortdesc', '0');
$shortdesc = ($shortdesc) ? $shortdesc->innertext : '';

View file

@ -1,29 +1,30 @@
<?php
class DilbertBridge extends BridgeAbstract {
class DilbertBridge extends BridgeAbstract
{
const MAINTAINER = 'kranack';
const NAME = 'Dilbert Daily Strip';
const URI = 'https://dilbert.com';
const CACHE_TIMEOUT = 21600; // 6h
const DESCRIPTION = 'The Unofficial Dilbert Daily Comic Strip';
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
foreach ($html->find('section.comic-item') as $element) {
$img = $element->find('img', 0);
$link = $element->find('a', 0);
$comic = $img->src;
$title = $img->alt;
$url = $link->href;
$date = substr(strrchr($url, '/'), 1);
if (empty($title))
if (empty($title)) {
$title = 'Dilbert Comic Strip on ' . $date;
}
$date = strtotime($date);
$item = array();
$item = [];
$item['uri'] = $url;
$item['title'] = $title;
$item['author'] = 'Scott Adams';

View file

@ -1,54 +1,53 @@
<?php
class DiscogsBridge extends BridgeAbstract {
class DiscogsBridge extends BridgeAbstract
{
const MAINTAINER = 'teromene';
const NAME = 'DiscogsBridge';
const URI = 'https://www.discogs.com/';
const DESCRIPTION = 'Returns releases from discogs';
const PARAMETERS = array(
'Artist Releases' => array(
'artistid' => array(
const PARAMETERS = [
'Artist Releases' => [
'artistid' => [
'name' => 'Artist ID',
'type' => 'number',
'required' => true,
'exampleValue' => '28104',
'title' => 'Only the ID from an artist page. EG /artist/28104-Aesop-Rock is 28104'
)
),
'Label Releases' => array(
'labelid' => array(
]
],
'Label Releases' => [
'labelid' => [
'name' => 'Label ID',
'type' => 'number',
'required' => true,
'exampleValue' => '8201',
'title' => 'Only the ID from a label page. EG /label/8201-Rhymesayers-Entertainment is 8201'
)
),
'User Wantlist' => array(
'username_wantlist' => array(
]
],
'User Wantlist' => [
'username_wantlist' => [
'name' => 'Username',
'type' => 'text',
'required' => true,
'exampleValue' => 'TheBlindMaster',
)
),
'User Folder' => array(
'username_folder' => array(
]
],
'User Folder' => [
'username_folder' => [
'name' => 'Username',
'type' => 'text',
),
'folderid' => array(
],
'folderid' => [
'name' => 'Folder ID',
'type' => 'number',
)
)
);
public function collectData() {
]
]
];
public function collectData()
{
if (!empty($this->getInput('artistid')) || !empty($this->getInput('labelid'))) {
if (!empty($this->getInput('artistid'))) {
$data = getContents('https://api.discogs.com/artists/'
. $this->getInput('artistid')
@ -61,8 +60,7 @@ class DiscogsBridge extends BridgeAbstract {
$jsonData = json_decode($data, true);
foreach ($jsonData['releases'] as $release) {
$item = array();
$item = [];
$item['author'] = $release['artist'];
$item['title'] = $release['title'];
$item['id'] = $release['id'];
@ -76,15 +74,12 @@ class DiscogsBridge extends BridgeAbstract {
$item['content'] = $item['author'] . ' - ' . $item['title'];
$this->items[] = $item;
}
} elseif (!empty($this->getInput('username_wantlist')) || !empty($this->getInput('username_folder'))) {
if (!empty($this->getInput('username_wantlist'))) {
$data = getContents('https://api.discogs.com/users/'
. $this->getInput('username_wantlist')
. '/wants?sort=added&sort_order=desc');
$jsonData = json_decode($data, true)['wants'];
} elseif (!empty($this->getInput('username_folder'))) {
$data = getContents('https://api.discogs.com/users/'
. $this->getInput('username_folder')
@ -94,9 +89,8 @@ class DiscogsBridge extends BridgeAbstract {
$jsonData = json_decode($data, true)['releases'];
}
foreach ($jsonData as $element) {
$infos = $element['basic_information'];
$item = array();
$item = [];
$item['title'] = $infos['title'];
$item['author'] = $infos['artists'][0]['name'];
$item['id'] = $infos['artists'][0]['id'];
@ -104,17 +98,17 @@ class DiscogsBridge extends BridgeAbstract {
$item['timestamp'] = strtotime($element['date_added']);
$item['content'] = $item['author'] . ' - ' . $item['title'];
$this->items[] = $item;
}
}
}
}
public function getURI() {
public function getURI()
{
return self::URI;
}
public function getName() {
public function getName()
{
return static::NAME;
}
}

View file

@ -1,33 +1,35 @@
<?php
class DockerHubBridge extends BridgeAbstract {
class DockerHubBridge extends BridgeAbstract
{
const NAME = 'Docker Hub Bridge';
const URI = 'https://hub.docker.com';
const DESCRIPTION = 'Returns new images for a container';
const MAINTAINER = 'VerifiedJoseph';
const PARAMETERS = array(
'User Submitted Image' => array(
'user' => array(
const PARAMETERS = [
'User Submitted Image' => [
'user' => [
'name' => 'User',
'type' => 'text',
'required' => true,
'exampleValue' => 'rssbridge',
),
'repo' => array(
],
'repo' => [
'name' => 'Repository',
'type' => 'text',
'required' => true,
'exampleValue' => 'rss-bridge',
)
),
'Official Image' => array(
'repo' => array(
]
],
'Official Image' => [
'repo' => [
'name' => 'Repository',
'type' => 'text',
'required' => true,
'exampleValue' => 'postgres',
)
),
);
]
],
];
const CACHE_TIMEOUT = 3600; // 1 hour
@ -35,8 +37,9 @@ class DockerHubBridge extends BridgeAbstract {
private $imageUrlRegex = '/hub\.docker\.com\/r\/([\w]+)\/([\w-]+)\/?/';
private $officialImageUrlRegex = '/hub\.docker\.com\/_\/([\w-]+)\/?/';
public function detectParameters($url) {
$params = array();
public function detectParameters($url)
{
$params = [];
// user submitted image
if (preg_match($this->imageUrlRegex, $url, $matches)) {
@ -56,13 +59,14 @@ class DockerHubBridge extends BridgeAbstract {
return null;
}
public function collectData() {
public function collectData()
{
$json = getContents($this->getApiUrl());
$data = json_decode($json, false);
foreach ($data->results as $result) {
$item = array();
$item = [];
$lastPushed = date('Y-m-d H:i:s', strtotime($result->tag_last_pushed));
@ -82,10 +86,10 @@ EOD;
$this->items[] = $item;
}
}
public function getURI() {
public function getURI()
{
if ($this->queriedContext === 'Official Image') {
return self::URI . '/_/' . $this->getRepo();
}
@ -97,7 +101,8 @@ EOD;
return parent::getURI();
}
public function getName() {
public function getName()
{
if ($this->getInput('repo')) {
return $this->getRepo() . ' - Docker Hub';
}
@ -105,7 +110,8 @@ EOD;
return parent::getName();
}
private function getRepo() {
private function getRepo()
{
if ($this->queriedContext === 'Official Image') {
return $this->getInput('repo');
}
@ -113,7 +119,8 @@ EOD;
return $this->getInput('user') . '/' . $this->getInput('repo');
}
private function getApiUrl() {
private function getApiUrl()
{
if ($this->queriedContext === 'Official Image') {
return $this->apiURL . 'library/' . $this->getRepo() . '/tags/?page_size=25&page=1';
}
@ -121,7 +128,8 @@ EOD;
return $this->apiURL . $this->getRepo() . '/tags/?page_size=25&page=1';
}
private function getLayerUrl($name, $digest) {
private function getLayerUrl($name, $digest)
{
if ($this->queriedContext === 'Official Image') {
return self::URI . '/layers/' . $this->getRepo() . '/library/' .
$this->getRepo() . '/' . $name . '/images/' . $digest;
@ -130,7 +138,8 @@ EOD;
return self::URI . '/layers/' . $this->getRepo() . '/' . $name . '/images/' . $digest;
}
private function getTagUrl($name) {
private function getTagUrl($name)
{
if ($this->queriedContext === 'Official Image') {
return self::URI . '/_/' . $this->getRepo() . '?tab=tags&name=' . $name;
}
@ -138,7 +147,8 @@ EOD;
return self::URI . '/r/' . $this->getRepo() . '/tags?name=' . $name;
}
private function getImages($result) {
private function getImages($result)
{
$html = <<<EOD
<table style="width:300px;"><thead><tr><th>Digest</th><th>OS/architecture</th></tr></thead></tbody>
EOD;
@ -158,7 +168,8 @@ EOD;
return $html . '</tbody></table>';
}
private function getShortDigestId($digest) {
private function getShortDigestId($digest)
{
$parts = explode(':', $digest);
return substr($parts[1], 0, 12);
}

View file

@ -1,36 +1,38 @@
<?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 {
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(
const PARAMETERS = [
[
'q' => [
'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 lurl. Doit commencer par /',
),
'p' => array(
],
'p' => [
'name' => 'Nombre de pages à scanner',
'type' => 'number',
'required' => true,
'defaultValue' => 5,
'title' => 'Indique le nombre de pages de donnons.org qui seront scannées'
)
)
);
]
]
];
public function collectData() {
public function collectData()
{
$pages = $this->getInput('p');
for ($i = 1; $i <= $pages; $i++) {
@ -38,7 +40,8 @@ class DonnonsBridge extends BridgeAbstract {
}
}
private function collectDataByPage($page) {
private function collectDataByPage($page)
{
$uri = $this->getPageURI($page);
$html = getSimpleHTMLDOM($uri);
@ -48,7 +51,7 @@ class DonnonsBridge extends BridgeAbstract {
if (!is_null($searchDiv)) {
$elements = $searchDiv->find('a.lst-annonce');
foreach ($elements as $element) {
$item = array();
$item = [];
// Lien vers le don
$item['uri'] = self::URI . $element->href;
@ -89,14 +92,15 @@ class DonnonsBridge extends BridgeAbstract {
$item['timestamp'] = $date;
$item['author'] = $author;
$item['content'] = $content;
$item['enclosures'] = array($image);
$item['enclosures'] = [$image];
$this->items[] = $item;
}
}
}
private function getPageURI($page) {
private function getPageURI($page)
{
$uri = $this->getURI();
$haveQueryParams = strpos($uri, '?') !== false;
@ -107,7 +111,8 @@ class DonnonsBridge extends BridgeAbstract {
}
}
public function getURI() {
public function getURI()
{
if (!is_null($this->getInput('q'))) {
return self::URI . $this->getInput('q');
}
@ -115,7 +120,8 @@ class DonnonsBridge extends BridgeAbstract {
return parent::getURI();
}
public function getName() {
public function getName()
{
if (!is_null($this->getInput('q'))) {
return 'Donnons.org - ' . $this->getInput('q');
}

View file

@ -1,24 +1,27 @@
<?php
class DribbbleBridge extends BridgeAbstract {
class DribbbleBridge extends BridgeAbstract
{
const MAINTAINER = 'quentinus95';
const NAME = 'Dribbble popular shots';
const URI = 'https://dribbble.com';
const CACHE_TIMEOUT = 1800;
const DESCRIPTION = 'Returns the newest popular shots from Dribbble.';
public function getIcon() {
public function getIcon()
{
return 'https://cdn.dribbble.com/assets/
favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
}
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
$json = $this->loadEmbeddedJsonData($html);
foreach ($html->find('li[id^="screenshot-"]') as $shot) {
$item = array();
$item = [];
$additional_data = $this->findJsonForShot($shot, $json);
if ($additional_data === null) {
@ -37,14 +40,15 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
$preview_path = $shot->find('figure img', 1)->attr['data-srcset'];
$item['content'] .= $this->getImageTag($preview_path, $item['title']);
$item['enclosures'] = array($this->getFullSizeImagePath($preview_path));
$item['enclosures'] = [$this->getFullSizeImagePath($preview_path)];
$this->items[] = $item;
}
}
private function loadEmbeddedJsonData($html){
$json = array();
private function loadEmbeddedJsonData($html)
{
$json = [];
$scripts = $html->find('script');
foreach ($scripts as $script) {
@ -73,7 +77,8 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
return $json;
}
private function findJsonForShot($shot, $json){
private function findJsonForShot($shot, $json)
{
foreach ($json as $element) {
if (strpos($shot->getAttribute('id'), (string)$element['id']) !== false) {
return $element;
@ -83,7 +88,8 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
return null;
}
private function getImageTag($preview_path, $title){
private function getImageTag($preview_path, $title)
{
return sprintf(
'<br /> <a href="%s"><img srcset="%s" alt="%s" /></a>',
$this->getFullSizeImagePath($preview_path),
@ -92,7 +98,8 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
);
}
private function getFullSizeImagePath($preview_path){
private function getFullSizeImagePath($preview_path)
{
// Get last image from srcset
$src_set_urls = explode(',', $preview_path);
$url = end($src_set_urls);

View file

@ -1,35 +1,37 @@
<?php
class Drive2ruBridge extends BridgeAbstract {
class Drive2ruBridge extends BridgeAbstract
{
const MAINTAINER = 'dotter-ak';
const NAME = 'Drive2.ru';
const URI = 'https://drive2.ru/';
const DESCRIPTION = 'Лента новостей и тестдрайвов, бортжурналов по выбранной марке или модели
(также работает с фильтром по категориям), блогов пользователей и публикаций по темам.';
const PARAMETERS = array(
'Новости и тест-драйвы' => array(),
'Бортжурналы (По модели или марке)' => array(
'url' => array(
const PARAMETERS = [
'Новости и тест-драйвы' => [],
'Бортжурналы (По модели или марке)' => [
'url' => [
'name' => 'Ссылка на страницу с бортжурналом',
'type' => 'text',
'required' => true,
'title' => 'Например: https://www.drive2.ru/experience/suzuki/g4895/',
'exampleValue' => 'https://www.drive2.ru/experience/suzuki/g4895/'
),
),
'Личные блоги' => array(
'username' => array(
],
],
'Личные блоги' => [
'username' => [
'name' => 'Никнейм пользователя на сайте',
'type' => 'text',
'required' => true,
'title' => 'Например: Mickey',
'exampleValue' => 'Mickey'
)
),
'Публикации по темам (Стоит почитать)' => array(
'topic' => array(
]
],
'Публикации по темам (Стоит почитать)' => [
'topic' => [
'name' => 'Темы',
'type' => 'list',
'values' => array(
'values' => [
'Автозвук' => '16',
'Автомобильный дизайн' => '10',
'Автоспорт' => '11',
@ -62,26 +64,27 @@ class Drive2ruBridge extends BridgeAbstract {
'Шины и диски' => '140',
'Электрика' => '130',
'Электромобили' => '131'
),
],
'defaultValue' => '16',
)
),
'global' => array(
'full_articles' => array(
]
],
'global' => [
'full_articles' => [
'name' => 'Загружать в ленту полный текст',
'type' => 'checkbox'
)
)
);
]
]
];
private $title;
private function getUserContent($url) {
private function getUserContent($url)
{
$html = getSimpleHTMLDOM($url);
$this->title = $html->find('title', 0)->innertext;
$articles = $html->find('div.js-entity');
foreach ($articles as $article) {
$item = array();
$item = [];
$item['title'] = $article->find('a.c-link--text', 0)->plaintext;
$item['uri'] = urljoin(self::URI, $article->find('a.c-link--text', 0)->href);
if ($this->getInput('full_articles')) {
@ -93,17 +96,20 @@ class Drive2ruBridge extends BridgeAbstract {
$item['content'] = $this->addReadMoreLink($article->find('div.c-post-preview__lead', 0), $item['uri']);
}
$item['author'] = $article->find('a.c-username--wrap', 0)->plaintext;
if (!is_null($article->find('img', 1))) $item['enclosures'][] = $article->find('img', 1)->src;
if (!is_null($article->find('img', 1))) {
$item['enclosures'][] = $article->find('img', 1)->src;
}
$this->items[] = $item;
}
}
private function getLogbooksContent($url) {
private function getLogbooksContent($url)
{
$html = getSimpleHTMLDOM($url);
$this->title = $html->find('title', 0)->innertext;
$articles = $html->find('div.js-entity');
foreach ($articles as $article) {
$item = array();
$item = [];
$item['title'] = $article->find('a.c-link--text', 1)->plaintext;
$item['uri'] = urljoin(self::URI, $article->find('a.c-link--text', 1)->href);
if ($this->getInput('full_articles')) {
@ -115,17 +121,20 @@ class Drive2ruBridge extends BridgeAbstract {
$item['content'] = $this->addReadMoreLink($article->find('div.c-post-preview__lead', 0), $item['uri']);
}
$item['author'] = $article->find('a.c-username--wrap', 0)->plaintext;
if (!is_null($article->find('img', 1))) $item['enclosures'][] = $article->find('img', 1)->src;
if (!is_null($article->find('img', 1))) {
$item['enclosures'][] = $article->find('img', 1)->src;
}
$this->items[] = $item;
}
}
private function getNews() {
private function getNews()
{
$html = getSimpleHTMLDOM('https://www.drive2.ru/editorial/');
$this->title = $html->find('title', 0)->innertext;
$articles = $html->find('div.c-article-card');
foreach ($articles as $article) {
$item = array();
$item = [];
$item['title'] = $article->find('a.c-link--text', 0)->plaintext;
$item['uri'] = urljoin(self::URI, $article->find('a.c-link--text', 0)->href);
if ($this->getInput('full_articles')) {
@ -137,23 +146,32 @@ class Drive2ruBridge extends BridgeAbstract {
$item['content'] = $this->addReadMoreLink($article->find('div.c-article-card__lead', 0), $item['uri']);
}
$item['author'] = 'Новости и тест-драйвы на Drive2.ru';
if (!is_null($article->find('img', 0))) $item['enclosures'][] = $article->find('img', 0)->src;
if (!is_null($article->find('img', 0))) {
$item['enclosures'][] = $article->find('img', 0)->src;
}
$this->items[] = $item;
}
}
private function adjustContent($content) {
foreach ($content->find('div.o-group') as $node)
private function adjustContent($content)
{
foreach ($content->find('div.o-group') as $node) {
$node->outertext = '';
foreach($content->find('div, span') as $attrs)
foreach ($attrs->getAllAttributes() as $attr => $val)
}
foreach ($content->find('div, span') as $attrs) {
foreach ($attrs->getAllAttributes() as $attr => $val) {
$attrs->removeAttribute($attr);
foreach ($content->getElementsByTagName('figcaption') as $attrs)
}
}
foreach ($content->getElementsByTagName('figcaption') as $attrs) {
$attrs->setAttribute(
'style',
'font-style: italic; font-size: small; margin: 0 100px 75px;');
foreach ($content->find('script') as $node)
'font-style: italic; font-size: small; margin: 0 100px 75px;'
);
}
foreach ($content->find('script') as $node) {
$node->outertext = '';
}
foreach ($content->find('iframe') as $node) {
preg_match('/embed\/(.*?)\?/', $node->src, $match);
$node->outertext = '<a href="https://www.youtube.com/watch?v=' . $match[1] .
@ -162,31 +180,38 @@ class Drive2ruBridge extends BridgeAbstract {
return $content;
}
private function addCommentsLink ($content, $url) {
private function addCommentsLink($content, $url)
{
return $content . '<br><a href="' . $url . '#comments">Перейти к комментариям</a>';
}
private function addReadMoreLink ($content, $url) {
if (!is_null($content))
private function addReadMoreLink($content, $url)
{
if (!is_null($content)) {
return preg_replace('!\s+!', ' ', str_replace('Читать дальше', '', $content->plaintext)) .
'<br><a href="' . $url . '">Читать далее</a>';
else return '';
} else {
return '';
}
}
public function collectData() {
public function collectData()
{
switch ($this->queriedContext) {
default:
case 'Новости и тест-драйвы':
$this->getNews();
break;
case 'Бортжурналы (По модели или марке)':
if (!preg_match('/^https:\/\/www.drive2.ru\/experience/', $this->getInput('url')))
if (!preg_match('/^https:\/\/www.drive2.ru\/experience/', $this->getInput('url'))) {
returnServerError('Invalid url');
}
$this->getLogbooksContent($this->getInput('url'));
break;
case 'Личные блоги':
if (!preg_match('/^[a-zA-Z0-9-]{3,16}$/', $this->getInput('username')))
if (!preg_match('/^[a-zA-Z0-9-]{3,16}$/', $this->getInput('username'))) {
returnServerError('Invalid username');
}
$this->getUserContent('https://www.drive2.ru/users/' . $this->getInput('username'));
break;
case 'Публикации по темам (Стоит почитать)':
@ -195,11 +220,13 @@ class Drive2ruBridge extends BridgeAbstract {
}
}
public function getName() {
public function getName()
{
return $this->title ?: parent::getName();
}
public function getIcon() {
public function getIcon()
{
return 'https://www.drive2.ru/favicon.ico';
}
}

View file

@ -1,6 +1,7 @@
<?php
class DuckDuckGoBridge extends BridgeAbstract {
class DuckDuckGoBridge extends BridgeAbstract
{
const MAINTAINER = 'Astalaseven';
const NAME = 'DuckDuckGo';
const URI = 'https://duckduckgo.com/';
@ -10,29 +11,30 @@ class DuckDuckGoBridge extends BridgeAbstract {
const SORT_DATE = '+sort:date';
const SORT_RELEVANCE = '';
const PARAMETERS = array( array(
'u' => array(
const PARAMETERS = [ [
'u' => [
'name' => 'keyword',
'exampleValue' => 'duck',
'required' => true
),
'sort' => array(
],
'sort' => [
'name' => 'sort by',
'type' => 'list',
'required' => false,
'values' => array(
'values' => [
'date' => self::SORT_DATE,
'relevance' => self::SORT_RELEVANCE
),
],
'defaultValue' => self::SORT_DATE
)
));
]
]];
public function collectData(){
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI . 'html/?kd=-1&q=' . $this->getInput('u') . $this->getInput('sort'));
foreach ($html->find('div.result') as $element) {
$item = array();
$item = [];
$item['uri'] = $element->find('a.result__a', 0)->href;
$item['title'] = $element->find('h2.result__title', 0)->plaintext;
$item['content'] = $element->find('a.result__snippet', 0)->plaintext;

View file

@ -1,51 +1,53 @@
<?php
class EZTVBridge extends BridgeAbstract {
class EZTVBridge extends BridgeAbstract
{
const MAINTAINER = 'alexAubin';
const NAME = 'EZTV';
const URI = 'https://eztv.re/';
const DESCRIPTION = 'Returns list of torrents for specific show(s)
on EZTV. Get IMDB IDs from IMDB.';
const PARAMETERS = array(
array(
'ids' => array(
const PARAMETERS = [
[
'ids' => [
'name' => 'Show IMDB IDs',
'exampleValue' => '8740790,1733785',
'required' => true,
'title' => 'One or more IMDB show IDs (can be found in the IMDB show URL)'
),
'no480' => array(
],
'no480' => [
'name' => 'No 480p',
'type' => 'checkbox',
'title' => 'Activate to exclude 480p torrents'
),
'no720' => array(
],
'no720' => [
'name' => 'No 720p',
'type' => 'checkbox',
'title' => 'Activate to exclude 720p torrents'
),
'no1080' => array(
],
'no1080' => [
'name' => 'No 1080p',
'type' => 'checkbox',
'title' => 'Activate to exclude 1080p torrents'
),
'no2160' => array(
],
'no2160' => [
'name' => 'No 2160p',
'type' => 'checkbox',
'title' => 'Activate to exclude 2160p torrents'
),
'noUnknownRes' => array(
],
'noUnknownRes' => [
'name' => 'No Unknown resolution',
'type' => 'checkbox',
'title' => 'Activate to exclude unknown resolution torrents'
),
)
);
],
]
];
// Shamelessly lifted from https://stackoverflow.com/a/2510459
protected function formatBytes($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
protected function formatBytes($bytes, $precision = 2)
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
@ -55,8 +57,9 @@ on EZTV. Get IMDB IDs from IMDB.';
return round($bytes, $precision) . ' ' . $units[$pow];
}
protected function getItemFromTorrent($torrent){
$item = array();
protected function getItemFromTorrent($torrent)
{
$item = [];
$item['uri'] = $torrent->episode_url;
$item['author'] = $torrent->imdb_id;
$item['timestamp'] = date('d F Y H:i:s', $torrent->date_released_unix);
@ -74,11 +77,13 @@ on EZTV. Get IMDB IDs from IMDB.';
return $item;
}
private static function compareDate($torrent1, $torrent2) {
private static function compareDate($torrent1, $torrent2)
{
return (strtotime($torrent1['timestamp']) < strtotime($torrent2['timestamp']) ? 1 : -1);
}
public function collectData(){
public function collectData()
{
$showIds = explode(',', $this->getInput('ids'));
foreach ($showIds as $showId) {
@ -93,11 +98,13 @@ on EZTV. Get IMDB IDs from IMDB.';
$regex2160 = '/2160p/';
$regexUnknown = '/(480p|720p|1080p|2160p)/';
// Skip unwanted resolution torrents
if ((preg_match($regex480, $title) === 1 && $this->getInput('no480'))
if (
(preg_match($regex480, $title) === 1 && $this->getInput('no480'))
|| (preg_match($regex720, $title) === 1 && $this->getInput('no720'))
|| (preg_match($regex1080, $title) === 1 && $this->getInput('no1080'))
|| (preg_match($regex2160, $title) === 1 && $this->getInput('no2160'))
|| (preg_match($regexUnknown, $title) !== 1 && $this->getInput('noUnknownRes'))) {
|| (preg_match($regexUnknown, $title) !== 1 && $this->getInput('noUnknownRes'))
) {
continue;
}
@ -106,6 +113,6 @@ on EZTV. Get IMDB IDs from IMDB.';
}
// Sort all torrents in array by date
usort($this->items, array('EZTVBridge', 'compareDate'));
usort($this->items, ['EZTVBridge', 'compareDate']);
}
}

View file

@ -1,29 +1,30 @@
<?php
class EconomistBridge extends FeedExpander {
class EconomistBridge extends FeedExpander
{
const MAINTAINER = 'bockiii';
const NAME = 'Economist Bridge';
const URI = 'https://www.economist.com/';
const CACHE_TIMEOUT = 3600; //1hour
const DESCRIPTION = 'Returns the latest articles for the selected category';
const PARAMETERS = array(
'global' => array(
'limit' => array(
const PARAMETERS = [
'global' => [
'limit' => [
'name' => 'Feed Item Limit',
'required' => true,
'type' => 'number',
'defaultValue' => 10,
'title' => 'Maximum number of returned feed items. Maximum 30, default 10'
)
),
'Topics' => array(
'topic' => array(
]
],
'Topics' => [
'topic' => [
'name' => 'Topics',
'type' => 'list',
'title' => 'Select a Topic',
'defaultValue' => 'latest',
'values' => array(
'values' => [
'Latest' => 'latest',
'The world this week' => 'the-world-this-week',
'Letters' => 'letters',
@ -45,15 +46,15 @@ class EconomistBridge extends FeedExpander {
'Obituaries' => 'obituary',
'Graphic detail' => 'graphic-detail',
'Indicators' => 'economic-and-financial-indicators',
)
)
),
'Blogs' => array(
'blog' => array(
]
]
],
'Blogs' => [
'blog' => [
'name' => 'Blogs',
'type' => 'list',
'title' => 'Select a Blog',
'values' => array(
'values' => [
'Bagehots notebook' => 'bagehots-notebook',
'Bartleby' => 'bartleby',
'Buttonwoods notebook' => 'buttonwoods-notebook',
@ -66,12 +67,13 @@ class EconomistBridge extends FeedExpander {
'Kaffeeklatsch' => 'kaffeeklatsch',
'Prospero' => 'prospero',
'The Economist Explains' => 'the-economist-explains',
)
)
)
);
]
]
]
];
public function collectData(){
public function collectData()
{
// get if topics or blogs were selected and store the selected category
switch ($this->queriedContext) {
case 'Topics':
@ -93,7 +95,8 @@ class EconomistBridge extends FeedExpander {
$this->collectExpandableDatas('https://www.economist.com/' . $category . '/rss.xml', $limit);
}
protected function parseItem($feedItem){
protected function parseItem($feedItem)
{
$item = parent::parseItem($feedItem);
$article = getSimpleHTMLDOM($item['uri']);
// before the article can be added, it needs to be cleaned up, thus, the extra function
@ -124,13 +127,16 @@ class EconomistBridge extends FeedExpander {
return $item;
}
private function cleanContent($article, $contentNode){
private function cleanContent($article, $contentNode)
{
// the actual article is in this div
$content = $article->find($contentNode, 0)->innertext;
// clean the article content. Remove all div's since the text is in paragraph elements
foreach (array(
foreach (
[
'<div '
) as $tag_start) {
] as $tag_start
) {
$content = stripRecursiveHTMLSection($content, 'div', $tag_start);
}
// now remove embedded iframes. The podcast postings contain these for example

View file

@ -1,4 +1,5 @@
<?php
class EconomistWorldInBriefBridge extends BridgeAbstract
{
const MAINTAINER = 'sqrtminusone';
@ -8,35 +9,35 @@ class EconomistWorldInBriefBridge extends BridgeAbstract
const CACHE_TIMEOUT = 3600; // 1 hour
const DESCRIPTION = 'Returns stories from the World in Brief section';
const PARAMETERS = array(
'' => array(
'splitGobbets' => array(
const PARAMETERS = [
'' => [
'splitGobbets' => [
'name' => 'Split the short stories',
'type' => 'checkbox',
'defaultValue' => false,
'title' => 'Whether to split the short stories into separate entries'
),
'limit' => array(
],
'limit' => [
'name' => 'Truncate headers for the short stories',
'type' => 'number',
'defaultValue' => 100
),
'agenda' => array(
],
'agenda' => [
'name' => 'Add agenda for the day',
'type' => 'checkbox',
'defaultValue' => 'checked'
),
'agendaPictures' => array(
],
'agendaPictures' => [
'name' => 'Include pictures to the agenda',
'type' => 'checkbox',
'defaultValue' => 'checked'
),
'quote' => array(
],
'quote' => [
'name' => 'Include the quote of the day',
'type' => 'checkbox'
)
)
);
]
]
];
public function collectData()
{
@ -72,13 +73,13 @@ class EconomistWorldInBriefBridge extends BridgeAbstract
if ($limit && mb_strlen($title) > $limit) {
$title = mb_substr($title, 0, $limit) . '...';
}
$item = array(
$item = [
'uri' => self::URI,
'title' => $title,
'content' => $gobbet->innertext,
'timestamp' => $today->format('U'),
'uid' => md5($gobbet->plaintext)
);
];
$this->items[] = $item;
}
}
@ -91,13 +92,13 @@ class EconomistWorldInBriefBridge extends BridgeAbstract
foreach ($gobbets->find('._gobbet') as $gobbet) {
$contents .= "<p>{$gobbet->innertext}";
}
$this->items[] = array(
$this->items[] = [
'uri' => self::URI,
'title' => 'World in brief at ' . $today->format('Y.m.d'),
'content' => $contents,
'timestamp' => $today->format('U'),
'uid' => 'world-in-brief-' . $today->format('U')
);
];
}
private function collectArticles($articles)
@ -116,26 +117,27 @@ class EconomistWorldInBriefBridge extends BridgeAbstract
$res_content .= '<img src="' . $img->src . '" />';
}
$res_content .= $content->innertext;
$this->items[] = array(
$this->items[] = [
'uri' => self::URI,
'title' => $title,
'content' => $res_content,
'timestamp' => $today->format('U'),
'uid' => 'story-' . $today->format('U') . "{$i}",
);
];
$i++;
}
}
private function addQuote($quote) {
private function addQuote($quote)
{
$today = new Datetime();
$today->setTime(0, 0, 0, 0);
$this->items[] = array(
$this->items[] = [
'uri' => self::URI,
'title' => 'Quote of the day ' . $today->format('Y.m.d'),
'content' => $quote->innertext,
'timestamp' => $today->format('U'),
'uid' => 'quote-' . $today->format('U')
);
];
}
}

View file

@ -1,34 +1,36 @@
<?php
class EliteDangerousGalnetBridge extends BridgeAbstract {
class EliteDangerousGalnetBridge extends BridgeAbstract
{
const MAINTAINER = 'corenting';
const NAME = 'Elite: Dangerous Galnet';
const URI = 'https://community.elitedangerous.com/galnet/';
const CACHE_TIMEOUT = 7200; // 2h
const DESCRIPTION = 'Returns the latest page of news from Galnet';
const PARAMETERS = array(
array(
'language' => array(
const PARAMETERS = [
[
'language' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'English' => 'en',
'French' => 'fr',
'German' => 'de'
),
],
'defaultValue' => 'en'
)
)
);
]
]
];
public function collectData(){
public function collectData()
{
$language = $this->getInput('language');
$url = 'https://community.elitedangerous.com/';
$url = $url . $language . '/galnet';
$html = getSimpleHTMLDOM($url);
foreach ($html->find('div.article') as $element) {
$item = array();
$item = [];
$uri = $element->find('h3 a', 0)->href;
$uri = 'https://community.elitedangerous.com/' . $language . $uri;

View file

@ -1,36 +1,37 @@
<?php
class ElloBridge extends BridgeAbstract {
class ElloBridge extends BridgeAbstract
{
const MAINTAINER = 'teromene';
const NAME = 'Ello Bridge';
const URI = 'https://ello.co/';
const CACHE_TIMEOUT = 4800; //2hours
const DESCRIPTION = 'Returns the newest posts for Ello';
const PARAMETERS = array(
'By User' => array(
'u' => array(
const PARAMETERS = [
'By User' => [
'u' => [
'name' => 'Username',
'required' => true,
'exampleValue' => 'zteph',
'title' => 'Username'
)
),
'Search' => array(
's' => array(
]
],
'Search' => [
's' => [
'name' => 'Search',
'required' => true,
'exampleValue' => 'bird',
'title' => 'Search'
)
)
);
]
]
];
public function collectData() {
$header = array(
public function collectData()
{
$header = [
'Authorization: Bearer ' . $this->getAPIKey()
);
];
if (!empty($this->getInput('u'))) {
$postData = getContents(self::URI . 'api/v2/users/~' . urlencode($this->getInput('u')) . '/posts', $header) or
@ -43,8 +44,7 @@ class ElloBridge extends BridgeAbstract {
$postData = json_decode($postData);
$count = 0;
foreach ($postData->posts as $post) {
$item = array();
$item = [];
$item['author'] = $this->getUsername($post, $postData);
$item['timestamp'] = strtotime($post->created_at);
$item['title'] = strip_tags($this->findText($post->summary));
@ -55,30 +55,24 @@ class ElloBridge extends BridgeAbstract {
$this->items[] = $item;
$count += 1;
}
}
}
private function findText($path) {
private function findText($path)
{
foreach ($path as $summaryElement) {
if ($summaryElement->kind == 'text') {
return $summaryElement->data;
}
}
return '';
}
private function getPostContent($path) {
private function getPostContent($path)
{
$content = '';
foreach ($path as $summaryElement) {
if ($summaryElement->kind == 'text') {
$content .= $summaryElement->data;
} elseif ($summaryElement->kind == 'image') {
@ -88,16 +82,14 @@ class ElloBridge extends BridgeAbstract {
}
$content .= '<img src="' . $summaryElement->data->url . '" alt="' . $alt . '" />';
}
}
return $content;
}
private function getEnclosures($post, $postData) {
$assets = array();
private function getEnclosures($post, $postData)
{
$assets = [];
foreach ($post->links->assets as $asset) {
foreach ($postData->linked->assets as $assetLink) {
if ($asset == $assetLink->id) {
@ -108,25 +100,24 @@ class ElloBridge extends BridgeAbstract {
}
return $assets;
}
private function getUsername($post, $postData) {
private function getUsername($post, $postData)
{
foreach ($postData->linked->users as $user) {
if ($user->id == $post->links->author->id) {
return $user->username;
}
}
}
private function getAPIKey() {
private function getAPIKey()
{
$cacheFac = new CacheFactory();
$cache = $cacheFac->create(Configuration::getConfig('cache', 'type'));
$cache->setScope(get_called_class());
$cache->setKey(array('key'));
$cache->setKey(['key']);
$key = $cache->loadData();
if ($key == null) {
@ -137,10 +128,10 @@ class ElloBridge extends BridgeAbstract {
}
return $key;
}
public function getName(){
public function getName()
{
if (!is_null($this->getInput('u'))) {
return $this->getInput('u') . ' - Ello Bridge';
}

View file

@ -1,22 +1,24 @@
<?php
class ElsevierBridge extends BridgeAbstract {
class ElsevierBridge extends BridgeAbstract
{
const MAINTAINER = 'dvikan';
const NAME = 'Elsevier journals recent articles';
const URI = 'https://www.journals.elsevier.com/';
const CACHE_TIMEOUT = 43200; //12h
const DESCRIPTION = 'Returns the recent articles published in Elsevier journals';
const PARAMETERS = array( array(
'j' => array(
const PARAMETERS = [ [
'j' => [
'name' => 'Journal name',
'required' => true,
'exampleValue' => 'academic-pediatrics',
'title' => 'Insert html-part of your journal'
)
));
]
]];
public function collectData(){
public function collectData()
{
// Not all journals have the /recent-articles page
$url = sprintf('https://www.journals.elsevier.com/%s/recent-articles/', $this->getInput('j'));
$html = getSimpleHTMLDOM($url);
@ -35,7 +37,8 @@ class ElsevierBridge extends BridgeAbstract {
}
}
public function getIcon(): string {
public function getIcon(): string
{
return 'https://cdn.elsevier.io/verona/includes/favicons/favicon-32x32.png';
}
}

View file

@ -1,25 +1,29 @@
<?php
class EngadgetBridge extends FeedExpander {
class EngadgetBridge extends FeedExpander
{
const MAINTAINER = 'IceWreck';
const NAME = 'Engadget Bridge';
const URI = 'https://www.engadget.com/';
const CACHE_TIMEOUT = 3600;
const DESCRIPTION = 'Article content for Engadget.';
public function collectData(){
public function collectData()
{
$this->collectExpandableDatas(static::URI . 'rss.xml', 15);
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
$item = parent::parseItem($newsItem);
// $articlePage gets the entire page's contents
$articlePage = getSimpleHTMLDOM($newsItem->link);
// figure contain's the main article image
$article = $articlePage->find('figure', 0);
// .article-text has the actual article
foreach($articlePage->find('.article-text') as $element)
foreach ($articlePage->find('.article-text') as $element) {
$article = $article . $element;
}
$item['content'] = $article;
return $item;
}

View file

@ -1,24 +1,25 @@
<?php
class EpicgamesBridge extends BridgeAbstract {
class EpicgamesBridge extends BridgeAbstract
{
const NAME = 'Epic Games Store News';
const MAINTAINER = 'otakuf';
const URI = 'https://www.epicgames.com';
const DESCRIPTION = 'Returns the latest posts from epicgames.com';
const CACHE_TIMEOUT = 3600; // 60min
const PARAMETERS = array( array(
'postcount' => array(
const PARAMETERS = [ [
'postcount' => [
'name' => 'Limit',
'type' => 'number',
'required' => true,
'title' => 'Maximum number of items to return',
'defaultValue' => 10,
),
'language' => array(
],
'language' => [
'name' => 'Language',
'type' => 'list',
'values' => array(
'values' => [
'English' => 'en',
'العربية' => 'ar',
'Deutsch' => 'de',
@ -35,13 +36,14 @@ class EpicgamesBridge extends BridgeAbstract {
'Türkçe' => 'tr',
'简体中文' => 'zh-CN',
'繁體中文' => 'zh-Hant',
),
],
'title' => 'Language of blog posts',
'defaultValue' => 'en',
),
));
],
]];
public function collectData() {
public function collectData()
{
$api = 'https://store-content.ak.epicgames.com/api/';
// Get sticky posts first
@ -58,7 +60,7 @@ class EpicgamesBridge extends BridgeAbstract {
$decodedData = array_merge(json_decode($dataSticky), json_decode($dataBlog));
foreach ($decodedData as $key => $value) {
$item = array();
$item = [];
$item['uri'] = self::URI . $value->url;
$item['title'] = $value->title;
$item['timestamp'] = $value->date;

View file

@ -1,40 +1,46 @@
<?php
class EsquerdaNetBridge extends FeedExpander {
class EsquerdaNetBridge extends FeedExpander
{
const MAINTAINER = 'somini';
const NAME = 'Esquerda.net';
const URI = 'https://www.esquerda.net';
const DESCRIPTION = 'Esquerda.net';
const PARAMETERS = array(
array(
'feed' => array(
const PARAMETERS = [
[
'feed' => [
'name' => 'Feed',
'type' => 'list',
'defaultValue' => 'Geral',
'values' => array(
'values' => [
'Geral' => 'geral',
'Dossier' => 'artigos-dossier',
'Vídeo' => 'video',
'Opinião' => 'opinioes',
'Rádio' => 'radio',
)
)
)
);
]
]
]
];
public function getURI() {
public function getURI()
{
$type = $this->getInput('feed');
return self::URI . '/rss/' . $type;
}
public function getIcon() {
public function getIcon()
{
return 'https://www.esquerda.net/sites/default/files/favicon_0.ico';
}
public function collectData(){
public function collectData()
{
parent::collectExpandableDatas($this->getURI());
}
protected function parseItem($newsItem){
protected function parseItem($newsItem)
{
# Fix Publish date
$badDate = $newsItem->pubDate;
preg_match('|(?P<day>\d\d)/(?P<month>\d\d)/(?P<year>\d\d\d\d) - (?P<hour>\d\d):(?P<minute>\d\d)|', $badDate, $d);

View file

@ -1,16 +1,18 @@
<?php
class EstCeQuonMetEnProdBridge extends BridgeAbstract {
class EstCeQuonMetEnProdBridge extends BridgeAbstract
{
const MAINTAINER = 'ORelio';
const NAME = 'Est-ce qu\'on met en prod aujourd\'hui ?';
const URI = 'https://www.estcequonmetenprodaujourdhui.info/';
const CACHE_TIMEOUT = 21600; // 6h
const DESCRIPTION = 'Should we put a website in production today? (French)';
public function collectData() {
public function collectData()
{
$html = getSimpleHTMLDOM(self::URI);
$item = array();
$item = [];
$item['uri'] = $this->getURI() . '#' . date('Y-m-d');
$item['title'] = $this->getName();
$item['author'] = 'Nicolas Hoffmann';

Some files were not shown because too many files have changed in this diff Show more