mirror of
https://github.com/RSS-Bridge/rss-bridge.git
synced 2025-08-17 22:02:09 +02:00
Compare commits
76 Commits
2018-12-11
...
2019-03-17
Author | SHA1 | Date | |
---|---|---|---|
|
ae2c35c18a | ||
|
5b80bcaa04 | ||
|
5ea985164e | ||
|
696afa96d3 | ||
|
326a707739 | ||
|
1ac66b3fdc | ||
|
f450b2e118 | ||
|
688c950916 | ||
|
9d85b951f7 | ||
|
dac685b887 | ||
|
d37f0c14a0 | ||
|
b96c25a3af | ||
|
dc1b1b13cc | ||
|
e3588f62bd | ||
|
958ba815c7 | ||
|
3d24596a52 | ||
|
f9ed934c8c | ||
|
777c204838 | ||
|
ae40f7b388 | ||
|
473a62ed44 | ||
|
4c58768d4d | ||
|
ca9c2abb60 | ||
|
556a417dd6 | ||
|
51ee541d5a | ||
|
69cb65c1af | ||
|
29b187fc12 | ||
|
80f6a8b3d4 | ||
|
32d4da8b76 | ||
|
0063d2c376 | ||
|
11a39af35c | ||
|
f65a4076ba | ||
|
25593d9c18 | ||
|
394149b114 | ||
|
a29512deee | ||
|
e0db349a57 | ||
|
d532d0e0c4 | ||
|
434c12672f | ||
|
ab2e566ee1 | ||
|
493e76e4b9 | ||
|
37d882a8d5 | ||
|
bcd7bccc46 | ||
|
2def7a04a3 | ||
|
3c5b23daa6 | ||
|
ef6709c402 | ||
|
fc96e97d51 | ||
|
600f2290b6 | ||
|
245af35a60 | ||
|
ef4923ae5c | ||
|
18229b5c70 | ||
|
3160e62293 | ||
|
f81d1b0846 | ||
|
8801ac9e64 | ||
|
288d4de218 | ||
|
f3f33cabed | ||
|
3e45643418 | ||
|
719320e1a4 | ||
|
81ee15a161 | ||
|
988635dcf3 | ||
|
4095cad9b4 | ||
|
e7d3a006c8 | ||
|
ce65f51d91 | ||
|
4b22862295 | ||
|
185a773e74 | ||
|
10659dd453 | ||
|
6b2a45c1e8 | ||
|
6e4b6fa1cc | ||
|
0cad5f24e6 | ||
|
cb6ad7c077 | ||
|
4438807b26 | ||
|
6c1d861529 | ||
|
dc83962483 | ||
|
bb2329fa3a | ||
|
758f37b452 | ||
|
fb8a064e3a | ||
|
b00971b2c3 | ||
|
a07ead42a7 |
@@ -19,7 +19,7 @@ script:
|
||||
- ~/.config/composer/vendor/bin/phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p;
|
||||
# Check PHP compatibility for the lowest supported version
|
||||
- if [[ $TRAVIS_PHP_VERSION == "5.6" ]]; then
|
||||
~/.config/composer/vendor/bin/phpcs . --standard=phpcompatibility.xml --warning-severity=0 --extensions=php -p;
|
||||
~/.config/composer/vendor/bin/phpcs . --standard=phpcompatibility.xml --extensions=php -p;
|
||||
fi
|
||||
# Run unit tests (stable)
|
||||
- if [[ $TRAVIS_PHP_VERSION == "7.0" ]]; then
|
||||
@@ -29,7 +29,7 @@ script:
|
||||
# Check PHP compatibility for all versions, starting at the lowest supported version in order to detect breaking changes
|
||||
- if [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then
|
||||
phpunit --configuration=phpunit.xml --include-path=lib/;
|
||||
~/.config/composer/vendor/bin/phpcs . --standard=PHPCompatibility --warning-severity=0 --extensions=php -p --runtime-set testVersion 5.6-;
|
||||
~/.config/composer/vendor/bin/phpcs . --standard=PHPCompatibility --extensions=php -p --runtime-set testVersion 5.6-;
|
||||
fi
|
||||
|
||||
matrix:
|
||||
|
66
README.md
66
README.md
@@ -66,6 +66,7 @@ RSS-Bridge requires PHP 5.6 or higher with following extensions enabled:
|
||||
- [`simplexml`](https://secure.php.net/manual/en/book.simplexml.php)
|
||||
- [`curl`](https://secure.php.net/manual/en/book.curl.php)
|
||||
- [`json`](https://secure.php.net/manual/en/book.json.php)
|
||||
- [`sqlite3`](http://php.net/manual/en/book.sqlite3.php) (only when using SQLiteCache)
|
||||
|
||||
Find more information on our [Wiki](https://github.com/rss-bridge/rss-bridge/wiki)
|
||||
|
||||
@@ -111,41 +112,16 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
|
||||
-->
|
||||
|
||||
* [16mhz](https://github.com/16mhz)
|
||||
* [adamchainz](https://github.com/adamchainz)
|
||||
* [Ahiles3005](https://github.com/Ahiles3005)
|
||||
* [Albirew](https://github.com/Albirew)
|
||||
* [aledeg](https://github.com/aledeg)
|
||||
* [alexAubin](https://github.com/alexAubin)
|
||||
* [AmauryCarrade](https://github.com/AmauryCarrade)
|
||||
* [AntoineTurmel](https://github.com/AntoineTurmel)
|
||||
* [ArthurHoaro](https://github.com/ArthurHoaro)
|
||||
* [Astalaseven](https://github.com/Astalaseven)
|
||||
* [Astyan-42](https://github.com/Astyan-42)
|
||||
* [Daiyousei](https://github.com/Daiyousei)
|
||||
* [Djuuu](https://github.com/Djuuu)
|
||||
* [Draeli](https://github.com/Draeli)
|
||||
* [EtienneM](https://github.com/EtienneM)
|
||||
* [Frenzie](https://github.com/Frenzie)
|
||||
* [Ginko-Aloe](https://github.com/Ginko-Aloe)
|
||||
* [Glandos](https://github.com/Glandos)
|
||||
* [GregThib](https://github.com/GregThib)
|
||||
* [Grummfy](https://github.com/Grummfy)
|
||||
* [JackNUMBER](https://github.com/JackNUMBER)
|
||||
* [JeremyRand](https://github.com/JeremyRand)
|
||||
* [Jocker666z](https://github.com/Jocker666z)
|
||||
* [LogMANOriginal](https://github.com/LogMANOriginal)
|
||||
* [MonsieurPoutounours](https://github.com/MonsieurPoutounours)
|
||||
* [Nono-m0le](https://github.com/Nono-m0le)
|
||||
* [ORelio](https://github.com/ORelio)
|
||||
* [PaulVayssiere](https://github.com/PaulVayssiere)
|
||||
* [Piranhaplant](https://github.com/Piranhaplant)
|
||||
* [Riduidel](https://github.com/Riduidel)
|
||||
* [Roliga](https://github.com/Roliga)
|
||||
* [Strubbl](https://github.com/Strubbl)
|
||||
* [TheRadialActive](https://github.com/TheRadialActive)
|
||||
* [TwizzyDizzy](https://github.com/TwizzyDizzy)
|
||||
* [WalterBarrett](https://github.com/WalterBarrett)
|
||||
* [ZeNairolf](https://github.com/ZeNairolf)
|
||||
* [adamchainz](https://github.com/adamchainz)
|
||||
* [aledeg](https://github.com/aledeg)
|
||||
* [alexAubin](https://github.com/alexAubin)
|
||||
* [az5he6ch](https://github.com/az5he6ch)
|
||||
* [b1nj](https://github.com/b1nj)
|
||||
* [benasse](https://github.com/benasse)
|
||||
@@ -156,20 +132,38 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
|
||||
* [corenting](https://github.com/corenting)
|
||||
* [couraudt](https://github.com/couraudt)
|
||||
* [da2x](https://github.com/da2x)
|
||||
* [Daiyousei](https://github.com/Daiyousei)
|
||||
* [disk0x](https://github.com/disk0x)
|
||||
* [eMerzh](https://github.com/eMerzh)
|
||||
* [Djuuu](https://github.com/Djuuu)
|
||||
* [Draeli](https://github.com/Draeli)
|
||||
* [em92](https://github.com/em92)
|
||||
* [eMerzh](https://github.com/eMerzh)
|
||||
* [EtienneM](https://github.com/EtienneM)
|
||||
* [fluffy-critter](https://github.com/fluffy-critter)
|
||||
* [Frenzie](https://github.com/Frenzie)
|
||||
* [fulmeek](https://github.com/fulmeek)
|
||||
* [Ginko-Aloe](https://github.com/Ginko-Aloe)
|
||||
* [Glandos](https://github.com/Glandos)
|
||||
* [GregThib](https://github.com/GregThib)
|
||||
* [griffaurel](https://github.com/griffaurel)
|
||||
* [Grummfy](https://github.com/Grummfy)
|
||||
* [hunhejj](https://github.com/hunhejj)
|
||||
* [j0k3r](https://github.com/j0k3r)
|
||||
* [JackNUMBER](https://github.com/JackNUMBER)
|
||||
* [jdigilio](https://github.com/jdigilio)
|
||||
* [JeremyRand](https://github.com/JeremyRand)
|
||||
* [Jocker666z](https://github.com/Jocker666z)
|
||||
* [klimplant](https://github.com/klimplant)
|
||||
* [kranack](https://github.com/kranack)
|
||||
* [kraoc](https://github.com/kraoc)
|
||||
* [l1n](https://github.com/l1n)
|
||||
* [laBecasse](https://github.com/laBecasse)
|
||||
* [lagaisse](https://github.com/lagaisse)
|
||||
* [lalannev](https://github.com/lalannev)
|
||||
* [ldidry](https://github.com/ldidry)
|
||||
* [Limero](https://github.com/Limero)
|
||||
* [LogMANOriginal](https://github.com/LogMANOriginal)
|
||||
* [lorenzos](https://github.com/lorenzos)
|
||||
* [m0zes](https://github.com/m0zes)
|
||||
* [matthewseal](https://github.com/matthewseal)
|
||||
* [mcbyte-it](https://github.com/mcbyte-it)
|
||||
@@ -178,28 +172,40 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
|
||||
* [metaMMA](https://github.com/metaMMA)
|
||||
* [mickael-bertrand](https://github.com/mickael-bertrand)
|
||||
* [mitsukarenai](https://github.com/mitsukarenai)
|
||||
* [MonsieurPoutounours](https://github.com/MonsieurPoutounours)
|
||||
* [mr-flibble](https://github.com/mr-flibble)
|
||||
* [mro](https://github.com/mro)
|
||||
* [mxmehl](https://github.com/mxmehl)
|
||||
* [nel50n](https://github.com/nel50n)
|
||||
* [niawag](https://github.com/niawag)
|
||||
* [Nono-m0le](https://github.com/Nono-m0le)
|
||||
* [ORelio](https://github.com/ORelio)
|
||||
* [PaulVayssiere](https://github.com/PaulVayssiere)
|
||||
* [pellaeon](https://github.com/pellaeon)
|
||||
* [Piranhaplant](https://github.com/Piranhaplant)
|
||||
* [pit-fgfjiudghdf](https://github.com/pit-fgfjiudghdf)
|
||||
* [pitchoule](https://github.com/pitchoule)
|
||||
* [pmaziere](https://github.com/pmaziere)
|
||||
* [prysme01](https://github.com/prysme01)
|
||||
* [quentinus95](https://github.com/quentinus95)
|
||||
* [qwertygc](https://github.com/qwertygc)
|
||||
* [regisenguehard](https://github.com/regisenguehard)
|
||||
* [Riduidel](https://github.com/Riduidel)
|
||||
* [rogerdc](https://github.com/rogerdc)
|
||||
* [Roliga](https://github.com/Roliga)
|
||||
* [sebsauvage](https://github.com/sebsauvage)
|
||||
* [somini](https://github.com/somini)
|
||||
* [squeek502](https://github.com/squeek502)
|
||||
* [Strubbl](https://github.com/Strubbl)
|
||||
* [sublimz](https://github.com/sublimz)
|
||||
* [sysadminstory](https://github.com/sysadminstory)
|
||||
* [tameroski](https://github.com/tameroski)
|
||||
* [teromene](https://github.com/teromene)
|
||||
* [TheRadialActive](https://github.com/TheRadialActive)
|
||||
* [triatic](https://github.com/triatic)
|
||||
* [WalterBarrett](https://github.com/WalterBarrett)
|
||||
* [wtuuju](https://github.com/wtuuju)
|
||||
* [yardenac](https://github.com/yardenac)
|
||||
* [ZeNairolf](https://github.com/ZeNairolf)
|
||||
|
||||
Licenses
|
||||
===
|
||||
|
50
actions/DetectAction.php
Normal file
50
actions/DetectAction.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
class DetectAction extends ActionAbstract {
|
||||
public function execute() {
|
||||
$targetURL = $this->userData['url']
|
||||
or returnClientError('You must specify a url!');
|
||||
|
||||
$format = $this->userData['format']
|
||||
or returnClientError('You must specify a format!');
|
||||
|
||||
foreach(Bridge::getBridgeNames() as $bridgeName) {
|
||||
|
||||
if(!Bridge::isWhitelisted($bridgeName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridge = Bridge::create($bridgeName);
|
||||
|
||||
if($bridge === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridgeParams = $bridge->detectParameters($targetURL);
|
||||
|
||||
if(is_null($bridgeParams)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridgeParams['bridge'] = $bridgeName;
|
||||
$bridgeParams['format'] = $format;
|
||||
|
||||
header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301);
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
returnClientError('No bridge found for given URL: ' . $targetURL);
|
||||
}
|
||||
}
|
234
actions/DisplayAction.php
Normal file
234
actions/DisplayAction.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
class DisplayAction extends ActionAbstract {
|
||||
public function execute() {
|
||||
$bridge = array_key_exists('bridge', $this->userData) ? $this->userData['bridge'] : null;
|
||||
|
||||
$format = $this->userData['format']
|
||||
or returnClientError('You must specify a format!');
|
||||
|
||||
// DEPRECATED: 'nameFormat' scheme is replaced by 'name' in format parameter values
|
||||
// this is to keep compatibility until futher complete removal
|
||||
if(($pos = strpos($format, 'Format')) === (strlen($format) - strlen('Format'))) {
|
||||
$format = substr($format, 0, $pos);
|
||||
}
|
||||
|
||||
// whitelist control
|
||||
if(!Bridge::isWhitelisted($bridge)) {
|
||||
throw new \Exception('This bridge is not whitelisted', 401);
|
||||
die;
|
||||
}
|
||||
|
||||
// Data retrieval
|
||||
$bridge = Bridge::create($bridge);
|
||||
|
||||
$noproxy = array_key_exists('_noproxy', $this->userData)
|
||||
&& filter_var($this->userData['_noproxy'], FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
if(defined('PROXY_URL') && PROXY_BYBRIDGE && $noproxy) {
|
||||
define('NOPROXY', true);
|
||||
}
|
||||
|
||||
// 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);
|
||||
header('Location: ' . $uri, true, 301);
|
||||
die();
|
||||
}
|
||||
|
||||
$cache_timeout = filter_var($this->userData['_cache_timeout'], FILTER_VALIDATE_INT);
|
||||
|
||||
} else {
|
||||
$cache_timeout = $bridge->getCacheTimeout();
|
||||
}
|
||||
|
||||
// Remove parameters that don't concern bridges
|
||||
$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
|
||||
$cache = Cache::create(Configuration::getConfig('cache', 'type'));
|
||||
$cache->setPath(PATH_CACHE);
|
||||
$cache->purgeCache(86400); // 24 hours
|
||||
$cache->setParameters($cache_params);
|
||||
|
||||
$items = array();
|
||||
$infos = array();
|
||||
$mtime = $cache->getTime();
|
||||
|
||||
if($mtime !== false
|
||||
&& (time() - $cache_timeout < $mtime)
|
||||
&& !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'])) {
|
||||
$stime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||
|
||||
if($mtime <= $stime) { // Cached data is older or same
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s ', $mtime) . 'GMT', true, 304);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
$cached = $cache->loadData();
|
||||
|
||||
if(isset($cached['items']) && isset($cached['extraInfos'])) {
|
||||
foreach($cached['items'] as $item) {
|
||||
$items[] = new \FeedItem($item);
|
||||
}
|
||||
|
||||
$infos = $cached['extraInfos'];
|
||||
}
|
||||
|
||||
} else { // Collect new data
|
||||
|
||||
try {
|
||||
$bridge->setDatas($bridge_params);
|
||||
$bridge->collectData();
|
||||
|
||||
$items = $bridge->getItems();
|
||||
|
||||
// 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();
|
||||
|
||||
foreach($items as $item) {
|
||||
$feedItems[] = new \FeedItem($item);
|
||||
}
|
||||
|
||||
$items = $feedItems;
|
||||
}
|
||||
|
||||
$infos = array(
|
||||
'name' => $bridge->getName(),
|
||||
'uri' => $bridge->getURI(),
|
||||
'icon' => $bridge->getIcon()
|
||||
);
|
||||
} catch(Error $e) {
|
||||
error_log($e);
|
||||
|
||||
$item = new \FeedItem();
|
||||
|
||||
// Create "new" error message every 24 hours
|
||||
$this->userData['_error_time'] = urlencode((int)(time() / 86400));
|
||||
|
||||
// Error 0 is a special case (i.e. "trying to get property of non-object")
|
||||
if($e->getCode() === 0) {
|
||||
$item->setTitle(
|
||||
'Bridge encountered an unexpected situation! ('
|
||||
. $this->userData['_error_time']
|
||||
. ')'
|
||||
);
|
||||
} else {
|
||||
$item->setTitle(
|
||||
'Bridge returned error '
|
||||
. $e->getCode()
|
||||
. '! ('
|
||||
. $this->userData['_error_time']
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
$item->setURI(
|
||||
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
|
||||
. '?'
|
||||
. http_build_query($this->userData)
|
||||
);
|
||||
|
||||
$item->setTimestamp(time());
|
||||
$item->setContent(buildBridgeException($e, $bridge));
|
||||
|
||||
$items[] = $item;
|
||||
} catch(Exception $e) {
|
||||
error_log($e);
|
||||
|
||||
$item = new \FeedItem();
|
||||
|
||||
// Create "new" error message every 24 hours
|
||||
$this->userData['_error_time'] = urlencode((int)(time() / 86400));
|
||||
|
||||
$item->setURI(
|
||||
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
|
||||
. '?'
|
||||
. http_build_query($this->userData)
|
||||
);
|
||||
|
||||
$item->setTitle(
|
||||
'Bridge returned error '
|
||||
. $e->getCode()
|
||||
. '! ('
|
||||
. $this->userData['_error_time']
|
||||
. ')'
|
||||
);
|
||||
$item->setTimestamp(time());
|
||||
$item->setContent(buildBridgeException($e, $bridge));
|
||||
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
// Store data in cache
|
||||
$cache->saveData(array(
|
||||
'items' => array_map(function($i){ return $i->toArray(); }, $items),
|
||||
'extraInfos' => $infos
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
// Data transformation
|
||||
try {
|
||||
$format = Format::create($format);
|
||||
$format->setItems($items);
|
||||
$format->setExtraInfos($infos);
|
||||
$format->setLastModified($cache->getTime());
|
||||
$format->display();
|
||||
} catch(Error $e) {
|
||||
error_log($e);
|
||||
header('Content-Type: text/html', true, $e->getCode());
|
||||
die(buildTransformException($e, $bridge));
|
||||
} catch(Exception $e) {
|
||||
error_log($e);
|
||||
header('Content-Type: text/html', true, $e->getCode());
|
||||
die(buildTransformException($e, $bridge));
|
||||
}
|
||||
}
|
||||
}
|
53
actions/ListAction.php
Normal file
53
actions/ListAction.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
class ListAction extends ActionAbstract {
|
||||
public function execute() {
|
||||
$list = new StdClass();
|
||||
$list->bridges = array();
|
||||
$list->total = 0;
|
||||
|
||||
foreach(Bridge::getBridgeNames() as $bridgeName) {
|
||||
|
||||
$bridge = Bridge::create($bridgeName);
|
||||
|
||||
if($bridge === false) { // Broken bridge, show as inactive
|
||||
|
||||
$list->bridges[$bridgeName] = array(
|
||||
'status' => 'inactive'
|
||||
);
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
$status = Bridge::isWhitelisted($bridgeName) ? 'active' : 'inactive';
|
||||
|
||||
$list->bridges[$bridgeName] = array(
|
||||
'status' => $status,
|
||||
'uri' => $bridge->getURI(),
|
||||
'name' => $bridge->getName(),
|
||||
'icon' => $bridge->getIcon(),
|
||||
'parameters' => $bridge->getParameters(),
|
||||
'maintainer' => $bridge->getMaintainer(),
|
||||
'description' => $bridge->getDescription()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$list->total = count($list->bridges);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($list, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
@@ -21,5 +21,4 @@ class AcrimedBridge extends FeedExpander {
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ class AllocineFRBridge extends BridgeAbstract {
|
||||
'category' => array(
|
||||
'name' => 'category',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'exampleValue' => 'Faux Raccord',
|
||||
'title' => 'Select your category',
|
||||
'values' => array(
|
||||
@@ -83,5 +82,4 @@ class AllocineFRBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ class AmazonBridge extends BridgeAbstract {
|
||||
'sort' => array(
|
||||
'name' => 'Sort by',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Relevance' => 'relevanceblender',
|
||||
'Price: Low to High' => 'price-asc-rank',
|
||||
@@ -29,7 +28,6 @@ class AmazonBridge extends BridgeAbstract {
|
||||
'tld' => array(
|
||||
'name' => 'Country',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Australia' => 'com.au',
|
||||
'Brazil' => 'com.br',
|
||||
@@ -72,6 +70,9 @@ class AmazonBridge extends BridgeAbstract {
|
||||
|
||||
// Title
|
||||
$title = $element->find('h2', 0);
|
||||
if (is_null($title)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['title'] = html_entity_decode($title->innertext, ENT_QUOTES);
|
||||
|
||||
|
@@ -19,7 +19,6 @@ class AmazonPriceTrackerBridge extends BridgeAbstract {
|
||||
'tld' => array(
|
||||
'name' => 'Country',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Australia' => 'com.au',
|
||||
'Brazil' => 'com.br',
|
||||
|
@@ -137,5 +137,4 @@ class AnimeUltimeBridge extends BridgeAbstract {
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
62
bridges/AppleMusicBridge.php
Normal file
62
bridges/AppleMusicBridge.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
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 = 'Limero';
|
||||
const PARAMETERS = [[
|
||||
'url' => [
|
||||
'name' => 'Artist URL',
|
||||
'exampleValue' => 'https://itunes.apple.com/us/artist/dunderpatrullen/329796274',
|
||||
'required' => true,
|
||||
],
|
||||
'imgSize' => [
|
||||
'name' => 'Image size for thumbnails (in px)',
|
||||
'type' => 'number',
|
||||
'defaultValue' => 512,
|
||||
'required' => true,
|
||||
]
|
||||
]];
|
||||
const CACHE_TIMEOUT = 21600; // 6 hours
|
||||
|
||||
public function collectData() {
|
||||
$url = $this->getInput('url');
|
||||
$html = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Could not request: ' . $url);
|
||||
|
||||
$imgSize = $this->getInput('imgSize');
|
||||
|
||||
// Grab the json data from the page
|
||||
$html = $html->find('script[id=shoebox-ember-data-store]', 0);
|
||||
$html = strstr($html, '{');
|
||||
$html = substr($html, 0, -9);
|
||||
$json = json_decode($html);
|
||||
|
||||
// Loop through each object
|
||||
foreach ($json->included as $obj) {
|
||||
if ($obj->type === 'lockup/album') {
|
||||
$this->items[] = [
|
||||
'title' => $obj->attributes->artistName . ' - ' . $obj->attributes->name,
|
||||
'uri' => $obj->attributes->url,
|
||||
'timestamp' => $obj->attributes->releaseDate,
|
||||
'enclosures' => $obj->relationships->artwork->data->id,
|
||||
];
|
||||
} elseif ($obj->type === 'image') {
|
||||
$images[$obj->id] = $obj->attributes->url;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the images to each item
|
||||
foreach ($this->items as &$item) {
|
||||
$item['enclosures'] = [
|
||||
str_replace('{w}x{h}bb.{f}', $imgSize . 'x0w.jpg', $images[$item['enclosures']]),
|
||||
];
|
||||
}
|
||||
|
||||
// Sort the order to put the latest albums first
|
||||
usort($this->items, function($a, $b){
|
||||
return $a['timestamp'] < $b['timestamp'];
|
||||
});
|
||||
}
|
||||
}
|
@@ -119,5 +119,4 @@ class Arte7Bridge extends BridgeAbstract {
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
72
bridges/AsahiShimbunAJWBridge.php
Normal file
72
bridges/AsahiShimbunAJWBridge.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
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(
|
||||
'type' => 'list',
|
||||
'name' => 'Section',
|
||||
'values' => array(
|
||||
'Japan » Social Affairs' => 'japan/social',
|
||||
'Japan » People' => 'japan/people',
|
||||
'Japan » 3/11 Disaster' => 'japan/0311disaster',
|
||||
'Japan » Sci & Tech' => 'japan/sci_tech',
|
||||
'Politics' => 'politics',
|
||||
'Business' => 'business',
|
||||
'Culture » Style' => 'culture/style',
|
||||
'Culture » Movies' => 'culture/movies',
|
||||
'Culture » Manga & Anime' => 'culture/manga_anime',
|
||||
'Asia » China' => 'asia/china',
|
||||
'Asia » Korean Peninsula' => 'asia/korean_peninsula',
|
||||
'Asia » Around Asia' => 'asia/around_asia',
|
||||
'Opinion » Editorial' => 'opinion/editorial',
|
||||
'Opinion » Vox Populi' => 'opinion/vox',
|
||||
),
|
||||
'defaultValue' => 'Politics',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private function getSectionURI($section) {
|
||||
return self::getURI() . $section . '/';
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
$html = getSimpleHTMLDOM($this->getSectionURI($this->getInput('section')))
|
||||
or returnServerError('Could not load content');
|
||||
|
||||
foreach($html->find('#MainInner li a') as $element) {
|
||||
if ($element->parent()->class == 'HeadlineTopImage-S') {
|
||||
Debug::log('Skip Headline, it is repeated below');
|
||||
continue;
|
||||
}
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = self::BASE_URI . $element->href;
|
||||
$e_lead = $element->find('span.Lead', 0);
|
||||
if ($e_lead) {
|
||||
$item['content'] = $e_lead->innertext;
|
||||
$e_lead->outertext = '';
|
||||
} else {
|
||||
$item['content'] = $element->innertext;
|
||||
}
|
||||
$e_date = $element->find('span.EnDate', 0);
|
||||
if ($e_date) {
|
||||
$item['timestamp'] = strtotime($e_date->innertext);
|
||||
$e_date->outertext = '';
|
||||
}
|
||||
$e_video = $element->find('span.EnVideo', 0);
|
||||
if ($e_video) {
|
||||
$e_video->outertext = '';
|
||||
$element->innertext = "VIDEO: $element->innertext";
|
||||
}
|
||||
$item['title'] = $element->innertext;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
99
bridges/BakaUpdatesMangaReleasesBridge.php
Normal file
99
bridges/BakaUpdatesMangaReleasesBridge.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
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';
|
||||
const PARAMETERS = array(array(
|
||||
'series_id' => array(
|
||||
'name' => 'Series ID',
|
||||
'type' => 'number',
|
||||
'required' => true,
|
||||
'exampleValue' => '12345'
|
||||
)
|
||||
));
|
||||
const LIMIT_COLS = 5;
|
||||
const LIMIT_ITEMS = 10;
|
||||
|
||||
private $feedName = '';
|
||||
|
||||
public function collectData() {
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Series not found');
|
||||
|
||||
// content is an unstructured pile of divs, ugly to parse
|
||||
$cols = $html->find('div#main_content div.row > div.text');
|
||||
if (!$cols)
|
||||
returnServerError('No releases');
|
||||
|
||||
$rows = array_slice(
|
||||
array_chunk($cols, self::LIMIT_COLS), 0, self::LIMIT_ITEMS
|
||||
);
|
||||
|
||||
if (isset($rows[0][1])) {
|
||||
$this->feedName = $this->filterHTML($rows[0][1]->plaintext);
|
||||
}
|
||||
|
||||
foreach($rows as $cols) {
|
||||
if (count($cols) < self::LIMIT_COLS) continue;
|
||||
|
||||
$item = array();
|
||||
$title = array();
|
||||
|
||||
$item['content'] = '';
|
||||
|
||||
$objDate = $cols[0];
|
||||
if ($objDate)
|
||||
$item['timestamp'] = strtotime($objDate->plaintext);
|
||||
|
||||
$objTitle = $cols[1];
|
||||
if ($objTitle) {
|
||||
$title[] = $this->filterHTML($objTitle->plaintext);
|
||||
$item['content'] .= '<p>Series: ' . $this->filterText($objTitle->innertext) . '</p>';
|
||||
}
|
||||
|
||||
$objVolume = $cols[2];
|
||||
if ($objVolume && !empty($objVolume->plaintext))
|
||||
$title[] = 'Vol.' . $objVolume->plaintext;
|
||||
|
||||
$objChapter = $cols[3];
|
||||
if ($objChapter && !empty($objChapter->plaintext))
|
||||
$title[] = 'Chp.' . $objChapter->plaintext;
|
||||
|
||||
$objAuthor = $cols[4];
|
||||
if ($objAuthor && !empty($objAuthor->plaintext)) {
|
||||
$item['author'] = $this->filterHTML($objAuthor->plaintext);
|
||||
$item['content'] .= '<p>Groups: ' . $this->filterText($objAuthor->innertext) . '</p>';
|
||||
}
|
||||
|
||||
$item['title'] = implode(' ', $title);
|
||||
$item['uri'] = $this->getURI();
|
||||
$item['uid'] = hash('sha1', $item['title']);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$series_id = $this->getInput('series_id');
|
||||
if (!empty($series_id)) {
|
||||
return self::URI . 'releases.html?search=' . $series_id . '&stype=series';
|
||||
}
|
||||
return self::URI;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!empty($this->feedName)) {
|
||||
return $this->feedName . ' - ' . self::NAME;
|
||||
}
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
private function filterText($text) {
|
||||
return rtrim($text, '*');
|
||||
}
|
||||
|
||||
private function filterHTML($text) {
|
||||
return $this->filterText(html_entity_decode($text));
|
||||
}
|
||||
}
|
@@ -13,48 +13,72 @@ class BandcampBridge extends BridgeAbstract {
|
||||
'required' => true
|
||||
)
|
||||
));
|
||||
const IMGURI = 'https://f4.bcbits.com/';
|
||||
const IMGSIZE_300PX = 23;
|
||||
const IMGSIZE_700PX = 16;
|
||||
|
||||
public function getIcon() {
|
||||
return 'https://s4.bcbits.com/img/bc_favicon.ico';
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('No results for this query.');
|
||||
$url = self::URI . 'api/hub/1/dig_deeper';
|
||||
$data = $this->buildRequestJson();
|
||||
$header = array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($data)
|
||||
);
|
||||
$opts = array(
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_POSTFIELDS => $data
|
||||
);
|
||||
$content = getContents($url, $header, $opts)
|
||||
or returnServerError('Could not complete request to: ' . $url);
|
||||
|
||||
foreach($html->find('li.item') as $release) {
|
||||
$script = $release->find('div.art', 0)->getAttribute('onclick');
|
||||
$uri = ltrim($script, "return 'url(");
|
||||
$uri = rtrim($uri, "')");
|
||||
$json = json_decode($content);
|
||||
|
||||
$item = array();
|
||||
$item['author'] = $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
if ($json->ok !== true) {
|
||||
returnServerError('Invalid response');
|
||||
}
|
||||
|
||||
$item['title'] = $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
foreach ($json->items as $entry) {
|
||||
$url = $entry->tralbum_url;
|
||||
$artist = $entry->artist;
|
||||
$title = $entry->title;
|
||||
// e.g. record label is the releaser, but not the artist
|
||||
$releaser = $entry->band_name !== $entry->artist ? $entry->band_name : null;
|
||||
|
||||
$item['content'] = '<img src="'
|
||||
. $uri
|
||||
. '"/><br/>'
|
||||
. $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
$full_title = $artist . ' - ' . $title;
|
||||
$full_artist = $artist;
|
||||
if (isset($releaser)) {
|
||||
$full_title .= ' (' . $releaser . ')';
|
||||
$full_artist .= ' (' . $releaser . ')';
|
||||
}
|
||||
$small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX);
|
||||
$img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX);
|
||||
|
||||
$item['id'] = $release->find('a', 0)->getAttribute('href');
|
||||
$item['uri'] = $release->find('a', 0)->getAttribute('href');
|
||||
$item = array(
|
||||
'uri' => $url,
|
||||
'author' => $full_artist,
|
||||
'title' => $full_title
|
||||
);
|
||||
$item['content'] = "<img src='$small_img' /><br/>$full_title";
|
||||
$item['enclosures'] = array($img);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('tag'))) {
|
||||
return self::URI . 'tag/' . urlencode($this->getInput('tag')) . '?sort_field=date';
|
||||
}
|
||||
private function buildRequestJson(){
|
||||
$requestJson = array(
|
||||
'tag' => $this->getInput('tag'),
|
||||
'page' => 1,
|
||||
'sort' => 'date'
|
||||
);
|
||||
return json_encode($requestJson);
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
private function getImageUrl($id, $size){
|
||||
return self::IMGURI . 'img/a' . $id . '_' . $size . '.jpg';
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
|
@@ -43,5 +43,4 @@ class BlaguesDeMerdeBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ class BundesbankBridge extends BridgeAbstract {
|
||||
self::PARAM_LANG => array(
|
||||
'name' => 'Language',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'defaultValue' => self::LANG_DE,
|
||||
'values' => array(
|
||||
'English' => self::LANG_EN,
|
||||
@@ -83,5 +82,4 @@ class BundesbankBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
134
bridges/CachetBridge.php
Normal file
134
bridges/CachetBridge.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
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(
|
||||
'name' => 'Cachet installation',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'The URL of the Cachet installation',
|
||||
'exampleValue' => 'https://demo.cachethq.io/',
|
||||
), 'additional_info' => array(
|
||||
'name' => 'Additional Timestamps',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Whether to include the given timestamps'
|
||||
)
|
||||
)
|
||||
);
|
||||
const CACHE_TIMEOUT = 300;
|
||||
|
||||
private $componentCache = [];
|
||||
|
||||
public function getURI() {
|
||||
return $this->getInput('host') === null ? 'https://cachethq.io/' : $this->getInput('host');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the ping request to the cache API
|
||||
*
|
||||
* @param string $ping
|
||||
* @return boolean
|
||||
*/
|
||||
private function validatePing($ping) {
|
||||
$ping = json_decode($ping);
|
||||
if ($ping === null) {
|
||||
return false;
|
||||
}
|
||||
return $ping->data === 'Pong!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component name of a cachat component
|
||||
*
|
||||
* @param integer $id
|
||||
* @return string
|
||||
*/
|
||||
private function getComponentName($id) {
|
||||
if ($id === 0) {
|
||||
return '';
|
||||
}
|
||||
if (array_key_exists($id, $this->componentCache)) {
|
||||
return $this->componentCache[$id];
|
||||
}
|
||||
|
||||
$component = getContents($this->getURI() . '/api/v1/components/' . $id);
|
||||
$component = json_decode($component);
|
||||
if ($component === null) {
|
||||
return '';
|
||||
}
|
||||
return $component->data->name;
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
$ping = getContents(urljoin($this->getURI(), '/api/v1/ping'));
|
||||
if (!$this->validatePing($ping)) {
|
||||
returnClientError('Provided URI is invalid!');
|
||||
}
|
||||
|
||||
$url = urljoin($this->getURI(), '/api/v1/incidents?sort=id&order=desc');
|
||||
$incidents = getContents($url);
|
||||
$incidents = json_decode($incidents);
|
||||
if ($incidents === null) {
|
||||
returnClientError('/api/v1/incidents returned no valid json');
|
||||
}
|
||||
|
||||
usort($incidents->data, function ($a, $b) {
|
||||
$timeA = strtotime($a->updated_at);
|
||||
$timeB = strtotime($b->updated_at);
|
||||
return $timeA > $timeB ? -1 : 1;
|
||||
});
|
||||
|
||||
foreach ($incidents->data as $incident) {
|
||||
|
||||
if (isset($incident->permalink)) {
|
||||
$permalink = $incident->permalink;
|
||||
} else {
|
||||
$permalink = urljoin($this->getURI(), '/incident/' . $incident->id);
|
||||
}
|
||||
|
||||
$title = $incident->human_status . ': ' . $incident->name;
|
||||
$message = '';
|
||||
if ($this->getInput('additional_info')) {
|
||||
if (isset($incident->occurred_at)) {
|
||||
$message .= 'Occurred at: ' . $incident->occurred_at . "\r\n";
|
||||
}
|
||||
if (isset($incident->scheduled_at)) {
|
||||
$message .= 'Scheduled at: ' . $incident->scheduled_at . "\r\n";
|
||||
}
|
||||
if (isset($incident->created_at)) {
|
||||
$message .= 'Created at: ' . $incident->created_at . "\r\n";
|
||||
}
|
||||
if (isset($incident->updated_at)) {
|
||||
$message .= 'Updated at: ' . $incident->updated_at . "\r\n\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$message .= $incident->message;
|
||||
$content = nl2br($message);
|
||||
$componentName = $this->getComponentName($incident->component_id);
|
||||
$uidOrig = $permalink . $incident->created_at;
|
||||
$uid = hash('sha512', $uidOrig);
|
||||
$timestamp = strtotime($incident->created_at);
|
||||
$categories = [];
|
||||
$categories[] = $incident->human_status;
|
||||
if ($componentName !== '') {
|
||||
$categories[] = $componentName;
|
||||
}
|
||||
|
||||
$item = [];
|
||||
$item['uri'] = $permalink;
|
||||
$item['title'] = $title;
|
||||
$item['timestamp'] = $timestamp;
|
||||
$item['content'] = $content;
|
||||
$item['uid'] = $uid;
|
||||
$item['categories'] = $categories;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
22
bridges/ComboiosDePortugalBridge.php
Normal file
22
bridges/ComboiosDePortugalBridge.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
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() {
|
||||
$html = getSimpleHTMLDOM($this->getURI() . '/consultar-horarios/avisos')
|
||||
or returnServerError('Could not load content');
|
||||
|
||||
foreach($html->find('.warnings-table a') as $element) {
|
||||
$item = array();
|
||||
|
||||
$item['title'] = $element->innertext;
|
||||
$item['uri'] = self::BASE_URI . $element->href;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,6 @@ class ContainerLinuxReleasesBridge extends BridgeAbstract {
|
||||
'channel' => [
|
||||
'name' => 'Release Channel',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'defaultValue' => self::STABLE,
|
||||
'values' => [
|
||||
'Stable' => self::STABLE,
|
||||
|
@@ -15,27 +15,23 @@ class DealabsBridge extends PepperBridgeAbstract {
|
||||
'hide_expired' => array(
|
||||
'name' => 'Masquer les éléments expirés',
|
||||
'type' => 'checkbox',
|
||||
'required' => 'true'
|
||||
),
|
||||
'hide_local' => array(
|
||||
'name' => 'Masquer les deals locaux',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Masquer les deals en magasins physiques',
|
||||
'required' => 'true'
|
||||
),
|
||||
'priceFrom' => array(
|
||||
'name' => 'Prix minimum',
|
||||
'type' => 'text',
|
||||
'title' => 'Prix mnimum en euros',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
'priceTo' => array(
|
||||
'name' => 'Prix maximum',
|
||||
'type' => 'text',
|
||||
'title' => 'Prix maximum en euros',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
),
|
||||
|
||||
@@ -43,7 +39,6 @@ class DealabsBridge extends PepperBridgeAbstract {
|
||||
'group' => array(
|
||||
'name' => 'Groupe',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Groupe dont il faut afficher les deals',
|
||||
'values' => array(
|
||||
'Abonnements internet' => 'abonnements-internet',
|
||||
@@ -959,7 +954,6 @@ class DealabsBridge extends PepperBridgeAbstract {
|
||||
'order' => array(
|
||||
'name' => 'Trier par',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Ordre de tri des deals',
|
||||
'values' => array(
|
||||
'Du deal le plus Hot au moins Hot' => '',
|
||||
@@ -1224,7 +1218,6 @@ class PepperBridgeAbstract extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Shipping costs from a Deal if it exists
|
||||
* @return string String of the deal shipping Cost
|
||||
@@ -1383,8 +1376,11 @@ class PepperBridgeAbstract extends BridgeAbstract {
|
||||
|
||||
// Add the Hour and minutes
|
||||
$date_str .= ' 00:00';
|
||||
|
||||
$date = DateTime::createFromFormat('j F Y H:i', $date_str);
|
||||
// In some case, the date is not recognized : as a workaround the actual date is taken
|
||||
if($date === false) {
|
||||
$date = new DateTime();
|
||||
}
|
||||
return $date->getTimestamp();
|
||||
}
|
||||
|
||||
@@ -1457,8 +1453,6 @@ class PepperBridgeAbstract extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is some "localisation" function that returns the needed content using
|
||||
* the "$lang" class variable in the local class
|
||||
@@ -1472,5 +1466,4 @@ class PepperBridgeAbstract extends BridgeAbstract {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -6,72 +6,75 @@ class DemonoidBridge extends BridgeAbstract {
|
||||
const URI = 'https://www.demonoid.pw/';
|
||||
const DESCRIPTION = 'Returns results from search';
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'q' => array(
|
||||
'name' => 'keywords',
|
||||
'exampleValue' => 'keyword1 keyword2…',
|
||||
'required' => true,
|
||||
const PARAMETERS = array(
|
||||
'Keywords' => array(
|
||||
'q' => array(
|
||||
'name' => 'keywords',
|
||||
'exampleValue' => 'keyword1 keyword2…',
|
||||
'required' => true,
|
||||
),
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
)
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
'Category Only' => array(
|
||||
'catOnly' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
)
|
||||
)
|
||||
)
|
||||
), array(
|
||||
'catOnly' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
)
|
||||
)
|
||||
), array(
|
||||
'userid' => array(
|
||||
'name' => 'user id',
|
||||
'exampleValue' => '00000',
|
||||
'required' => true,
|
||||
'type' => 'number'
|
||||
),
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
'User ID' => array(
|
||||
'userid' => array(
|
||||
'name' => 'user id',
|
||||
'exampleValue' => '00000',
|
||||
'required' => true,
|
||||
'type' => 'number'
|
||||
),
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'All' => 0,
|
||||
'Movies' => 1,
|
||||
'Music' => 2,
|
||||
'TV' => 3,
|
||||
'Games' => 4,
|
||||
'Applications' => 5,
|
||||
'Pictures' => 8,
|
||||
'Anime' => 9,
|
||||
'Comics' => 10,
|
||||
'Books' => 11,
|
||||
'Audiobooks' => 17
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData() {
|
||||
|
113
bridges/DerpibooruBridge.php
Normal file
113
bridges/DerpibooruBridge.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
class DerpibooruBridge extends BridgeAbstract {
|
||||
const NAME = 'Derpibooru Bridge';
|
||||
const URI = 'https://derpibooru.org/';
|
||||
const DESCRIPTION = 'Returns newest posts from a Derpibooru search';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const MAINTAINER = 'Roliga';
|
||||
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'f' => array(
|
||||
'name' => 'Filter',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'Everything' => 56027,
|
||||
'18+ R34' => 37432,
|
||||
'Legacy Default' => 37431,
|
||||
'18+ Dark' => 37429,
|
||||
'Maximum Spoilers' => 37430,
|
||||
'Default' => 100073
|
||||
),
|
||||
'defaultValue' => 56027
|
||||
|
||||
),
|
||||
'q' => array(
|
||||
'name' => 'Query',
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function detectParameters($url){
|
||||
$params = array();
|
||||
|
||||
// Search page e.g. https://derpibooru.org/search?q=cute
|
||||
$regex = '/^(https?:\/\/)?(www\.)?derpibooru.org\/search.+q=([^\/&?\n]+)/';
|
||||
if(preg_match($regex, $url, $matches) > 0) {
|
||||
$params['q'] = urldecode($matches[3]);
|
||||
return $params;
|
||||
}
|
||||
|
||||
// Tag page, e.g. https://derpibooru.org/tags/artist-colon-devinian
|
||||
$regex = '/^(https?:\/\/)?(www\.)?derpibooru.org\/tags\/([^\/&?\n]+)/';
|
||||
if(preg_match($regex, $url, $matches) > 0) {
|
||||
$params['q'] = str_replace('-colon-', ':', urldecode($matches[3]));
|
||||
return $params;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('q'))) {
|
||||
return 'Derpibooru search for: '
|
||||
. $this->getInput('q');
|
||||
} else {
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('f')) && !is_null($this->getInput('q'))) {
|
||||
return self::URI
|
||||
. 'search?filter_id='
|
||||
. urlencode($this->getInput('f'))
|
||||
. '&q='
|
||||
. urlencode($this->getInput('q'));
|
||||
} else {
|
||||
return parent::getURI();
|
||||
}
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$queryJson = json_decode(getContents(
|
||||
self::URI
|
||||
. 'search.json?filter_id='
|
||||
. urlencode($this->getInput('f'))
|
||||
. '&q='
|
||||
. urlencode($this->getInput('q'))
|
||||
)) or returnServerError('Failed to query Derpibooru');
|
||||
|
||||
foreach($queryJson->search as $post) {
|
||||
$item = array();
|
||||
|
||||
$postUri = self::URI . $post->id;
|
||||
|
||||
$item['uri'] = $postUri;
|
||||
$item['title'] = $post->id;
|
||||
$item['timestamp'] = strtotime($post->created_at);
|
||||
$item['author'] = $post->uploader;
|
||||
$item['enclosures'] = array('https:' . $post->image);
|
||||
$item['categories'] = explode(', ', $post->tags);
|
||||
|
||||
$item['content'] = '<p><a href="' // image preview
|
||||
. $postUri
|
||||
. '"><img src="https:'
|
||||
. $post->representations->medium
|
||||
. '"></a></p><p>' // description
|
||||
. $post->description
|
||||
. '</p><p><b>Size:</b> ' // image size
|
||||
. $post->width
|
||||
. 'x'
|
||||
. $post->height
|
||||
. '<br><b>Source:</b> <a href="' // source link
|
||||
. $post->source_url
|
||||
. '">'
|
||||
. $post->source_url
|
||||
. '</a></p>';
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,6 @@ class DesoutterBridge extends BridgeAbstract {
|
||||
'news_lang' => array(
|
||||
'name' => 'Language',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your language',
|
||||
'defaultValue' => 'Corporate',
|
||||
'values' => array(
|
||||
@@ -66,7 +65,6 @@ class DesoutterBridge extends BridgeAbstract {
|
||||
'industry_lang' => array(
|
||||
'name' => 'Language',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your language',
|
||||
'defaultValue' => 'Corporate',
|
||||
'values' => array(
|
||||
@@ -117,7 +115,6 @@ class DesoutterBridge extends BridgeAbstract {
|
||||
'full' => array(
|
||||
'name' => 'Load full articles',
|
||||
'type' => 'checkbox',
|
||||
'required' => false,
|
||||
'title' => 'Enable to load the full article for each item'
|
||||
)
|
||||
)
|
||||
@@ -236,5 +233,4 @@ class DesoutterBridge extends BridgeAbstract {
|
||||
|
||||
echo $list;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,8 +22,7 @@ class DevToBridge extends BridgeAbstract {
|
||||
'name' => 'Full article',
|
||||
'type' => 'checkbox',
|
||||
'required' => false,
|
||||
'title' => 'Enable to receive the full article for each item',
|
||||
'defaultValue' => false
|
||||
'title' => 'Enable to receive the full article for each item'
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -101,5 +100,4 @@ EOD;
|
||||
|
||||
return $html->find('[id="article-body"]', 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ class DilbertBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'kranack';
|
||||
const NAME = 'Dilbert Daily Strip';
|
||||
const URI = 'http://dilbert.com';
|
||||
const URI = 'https://dilbert.com';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = 'The Unofficial Dilbert Daily Comic Strip';
|
||||
|
||||
@@ -17,9 +17,9 @@ class DilbertBridge extends BridgeAbstract {
|
||||
$img = $element->find('img', 0);
|
||||
$link = $element->find('a', 0);
|
||||
$comic = $img->src;
|
||||
$title = $link->alt;
|
||||
$title = $img->alt;
|
||||
$url = $link->href;
|
||||
$date = substr($url, 25);
|
||||
$date = substr(strrchr($url, '/'), 1);
|
||||
if (empty($title))
|
||||
$title = 'Dilbert Comic Strip on ' . $date;
|
||||
$date = strtotime($date);
|
||||
|
@@ -62,7 +62,11 @@ class DiscogsBridge extends BridgeAbstract {
|
||||
$item['id'] = $release['id'];
|
||||
$resId = array_key_exists('main_release', $release) ? $release['main_release'] : $release['id'];
|
||||
$item['uri'] = self::URI . $this->getInput('artistid') . '/release/' . $resId;
|
||||
$item['timestamp'] = DateTime::createFromFormat('Y', $release['year'])->getTimestamp();
|
||||
|
||||
if(isset($release['year'])) {
|
||||
$item['timestamp'] = DateTime::createFromFormat('Y', $release['year'])->getTimestamp();
|
||||
}
|
||||
|
||||
$item['content'] = $item['author'] . ' - ' . $item['title'];
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
@@ -6,25 +6,36 @@ class EliteDangerousGalnetBridge extends BridgeAbstract {
|
||||
const URI = 'https://community.elitedangerous.com/galnet/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = 'Returns the latest page of news from Galnet';
|
||||
|
||||
public function getIcon() {
|
||||
return 'https://community.elitedangerous.com/sites/
|
||||
EDSITE_COMM/themes/bootstrap/bootstrap_community/favicon.ico';
|
||||
}
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'language' => array(
|
||||
'name' => 'Language',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'English' => 'en',
|
||||
'French' => 'fr',
|
||||
'German' => 'de'
|
||||
),
|
||||
'defaultValue' => 'en'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
$language = $this->getInput('language');
|
||||
$url = 'https://community.elitedangerous.com/';
|
||||
$url = $url . $language . '/galnet';
|
||||
$html = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
foreach($html->find('div.article') as $element) {
|
||||
$item = array();
|
||||
|
||||
$uri = $element->find('h3 a', 0)->href;
|
||||
$uri = self::URI . substr($uri, strlen('/galnet/'));
|
||||
$uri = 'https://community.elitedangerous.com/' . $language . $uri;
|
||||
$item['uri'] = $uri;
|
||||
|
||||
$title = $element->find('h3 a', 0)->plaintext;
|
||||
$item['title'] = substr($title, 1); //remove the space between icon and title
|
||||
$item['title'] = $element->find('h3 a', 0)->plaintext;
|
||||
|
||||
$content = $element->find('p', -1)->innertext;
|
||||
$item['content'] = $content;
|
||||
|
@@ -120,7 +120,7 @@ class ElloBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
private function getAPIKey() {
|
||||
$cache = Cache::create('FileCache');
|
||||
$cache = Cache::create(Configuration::getConfig('cache', 'type'));
|
||||
$cache->setPath(PATH_CACHE);
|
||||
$cache->setParameters(['key']);
|
||||
$key = $cache->loadData();
|
||||
@@ -143,5 +143,4 @@ class ElloBridge extends BridgeAbstract {
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,7 +15,6 @@ class ExtremeDownloadBridge extends BridgeAbstract {
|
||||
'filter' => array(
|
||||
'name' => 'Type de contenu',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Type de contenu à suivre : Téléchargement, Streaming ou les deux',
|
||||
'values' => array(
|
||||
'Streaming et Téléchargement' => 'both',
|
||||
@@ -100,5 +99,4 @@ class ExtremeDownloadBridge extends BridgeAbstract {
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -198,7 +198,6 @@ EOD;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Builds the HTML from the encoded JS that Facebook provides.
|
||||
private function buildContent($pageContent){
|
||||
// The html ends with:
|
||||
@@ -213,7 +212,6 @@ EOD;
|
||||
return str_get_html($htmlContent);
|
||||
}
|
||||
|
||||
|
||||
//Builds the cookie from the page, as Facebook sometimes refuses to give
|
||||
//the page if no cookie is provided.
|
||||
private function getCookies($pageURL){
|
||||
@@ -289,5 +287,4 @@ EOD;
|
||||
public function getURI(){
|
||||
return 'http://facebook.com';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ class FDroidBridge extends BridgeAbstract {
|
||||
'u' => array(
|
||||
'name' => 'Widget selection',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Latest added apps' => 'added',
|
||||
'Latest updated apps' => 'updated'
|
||||
|
@@ -179,8 +179,7 @@ class FacebookBridge extends BridgeAbstract {
|
||||
|
||||
if(filter_var(
|
||||
$group,
|
||||
FILTER_VALIDATE_URL,
|
||||
FILTER_FLAG_HOST_REQUIRED | FILTER_FLAG_PATH_REQUIRED)) {
|
||||
FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)) {
|
||||
// User provided a URL
|
||||
|
||||
$urlparts = parse_url($group);
|
||||
@@ -687,7 +686,6 @@ EOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion (User)
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ class FeedExpanderExampleBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'FeedExpander Example';
|
||||
const URI = '#';
|
||||
const URI = 'http://github.com/RSS-Bridge/rss-bridge/';
|
||||
const DESCRIPTION = 'Example bridge to test FeedExpander';
|
||||
|
||||
const PARAMETERS = array(
|
||||
@@ -11,7 +11,6 @@ class FeedExpanderExampleBridge extends FeedExpander {
|
||||
'version' => array(
|
||||
'name' => 'Version',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your feed format/version',
|
||||
'defaultValue' => 'RSS 2.0',
|
||||
'values' => array(
|
||||
|
@@ -182,5 +182,4 @@ class FlickrBridge extends BridgeAbstract {
|
||||
return $url;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -37,5 +37,4 @@ class ForGifsBridge extends FeedExpander {
|
||||
return $item;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ class GBAtempBridge extends BridgeAbstract {
|
||||
'type' => array(
|
||||
'name' => 'Type',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'News' => 'N',
|
||||
'Reviews' => 'R',
|
||||
|
@@ -62,5 +62,4 @@ class GOGBridge extends BridgeAbstract {
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
class GQMagazineBridge extends BridgeAbstract
|
||||
{
|
||||
|
||||
const MAINTAINER = 'Riduidel';
|
||||
|
||||
const NAME = 'GQMagazine';
|
||||
@@ -20,18 +19,18 @@ class GQMagazineBridge extends BridgeAbstract
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = 'GQMagazine section extractor bridge. This bridge allows you get only a specific section.';
|
||||
|
||||
const DEFAULT_DOMAIN = 'www.gqmagazine.fr';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'domain' => array(
|
||||
'name' => 'Domain to use',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'www.gqmagazine.fr' => 'www.gqmagazine.fr'
|
||||
),
|
||||
'defaultValue' => 'www.gqmagazine.fr'
|
||||
'defaultValue' => self::DEFAULT_DOMAIN
|
||||
),
|
||||
'page' => array(
|
||||
'name' => 'Initial page to load',
|
||||
'required' => true
|
||||
'required' => true,
|
||||
'exampleValue' => 'sexe/news'
|
||||
),
|
||||
));
|
||||
|
||||
@@ -42,7 +41,12 @@ class GQMagazineBridge extends BridgeAbstract
|
||||
);
|
||||
|
||||
private function getDomain() {
|
||||
return $this->getInput('domain');
|
||||
$domain = $this->getInput('domain');
|
||||
if (empty($domain))
|
||||
$domain = self::DEFAULT_DOMAIN;
|
||||
if (strpos($domain, '://') === false)
|
||||
$domain = 'https://' . $domain;
|
||||
return $domain;
|
||||
}
|
||||
|
||||
public function getURI()
|
||||
|
@@ -160,5 +160,4 @@ EOD;
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class GithubIssueBridge extends BridgeAbstract {
|
||||
'i' => array(
|
||||
'name' => 'Issue number',
|
||||
'type' => 'number',
|
||||
'required' => 'true'
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@@ -117,7 +117,7 @@ class GlassdoorBridge extends BridgeAbstract {
|
||||
$item['title'] = $post->find('header', 0)->plaintext;
|
||||
$item['content'] = $post->find('div[class="excerpt-content"]', 0)->plaintext;
|
||||
$item['enclosures'] = array(
|
||||
$this->getFullSizeImageURI($post->find('div[class="post-thumb"]', 0)->{'data-original'})
|
||||
$this->getFullSizeImageURI($post->find('div[class*="post-thumb"]', 0)->{'data-original'})
|
||||
);
|
||||
|
||||
// optionally load full articles
|
||||
@@ -186,8 +186,7 @@ class GlassdoorBridge extends BridgeAbstract {
|
||||
* redirection and strange naming conventions.
|
||||
*/
|
||||
if(!filter_var($uri,
|
||||
FILTER_VALIDATE_URL,
|
||||
FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED | FILTER_FLAG_PATH_REQUIRED)) {
|
||||
FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)) {
|
||||
returnClientError('The specified URL is invalid!');
|
||||
}
|
||||
|
||||
|
88
bridges/GlowficBridge.php
Normal file
88
bridges/GlowficBridge.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
class GlowficBridge extends BridgeAbstract {
|
||||
const MAINTAINER = 'l1n';
|
||||
const NAME = 'Glowfic Bridge';
|
||||
const URI = 'https://www.glowfic.com';
|
||||
const CACHE_TIMEOUT = 3600; // 1 hour
|
||||
const DESCRIPTION = 'Returns the latest replies on a glowfic post.';
|
||||
const PARAMETERS = array(
|
||||
'global' => array(),
|
||||
'Thread' => array(
|
||||
'post_id' => array(
|
||||
'name' => 'Post ID',
|
||||
'title' => 'https://www.glowfic.com/posts/<POST ID>',
|
||||
'type' => 'number'
|
||||
),
|
||||
'start_page' => array(
|
||||
'name' => 'Start Page',
|
||||
'title' => 'To start from an offset page',
|
||||
'type' => 'number'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData() {
|
||||
$url = $this->getAPIURI();
|
||||
$metadata = get_headers( $url . '/replies', true ) or returnClientError('Post did not return reply headers.');
|
||||
$metadata['Last-Page'] = ceil( $metadata['Total'] / $metadata['Per-Page'] );
|
||||
if(!is_null($this->getInput('start_page')) &&
|
||||
$this->getInput('start_page') < 1 && $metadata['Last-Page'] - $this->getInput('start_page') > 0) {
|
||||
$first_page = $metadata['Last-Page'] - $this->getInput('start_page');
|
||||
} else if(!is_null($this->getInput('start_page')) && $this->getInput('start_page') <= $metadata['Last-Page']) {
|
||||
$first_page = $this->getInput('start_page');
|
||||
} else {
|
||||
$first_page = 1;
|
||||
}
|
||||
for ($page_offset = $first_page; $page_offset <= $metadata['Last-Page']; $page_offset++) {
|
||||
$jsonContents = getContents($url . '/replies?page=' . $page_offset ) or
|
||||
returnClientError('Could not retrieve replies for page ' . $page_offset . '.');
|
||||
$replies = json_decode($jsonContents);
|
||||
foreach ($replies as $reply) {
|
||||
$item = array();
|
||||
|
||||
$item['content'] = $reply->{'content'};
|
||||
$item['uri'] = $this->getURI() . '?page=' . $page_offset . '#reply-' . $reply->{'id'};
|
||||
if ($reply->{'icon'}) {
|
||||
$item['enclosures'] = array($reply->{'icon'}->{'url'});
|
||||
}
|
||||
$item['author'] = $reply->{'character'}->{'screenname'} . ' (' . $reply->{'character'}->{'name'} . ')';
|
||||
$item['timestamp'] = date('r', strtotime($reply->{'created_at'}));
|
||||
$item['title'] = 'Tag by ' . $reply->{'user'}->{'username'} . ' updated at ' . $reply->{'updated_at'};
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getAPIURI() {
|
||||
$url = parent::getURI() . '/api/v1/posts/' . $this->getInput('post_id');
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
$url = parent::getURI() . '/posts/' . $this->getInput('post_id');
|
||||
return $url;
|
||||
}
|
||||
|
||||
private function getPost() {
|
||||
$url = $this->getAPIURI();
|
||||
$jsonPost = getContents( $url ) or returnClientError('Could not retrieve post metadata.');
|
||||
$post = json_decode($jsonPost);
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('post_id'))) {
|
||||
$post = $this->getPost();
|
||||
return $post->{'subject'} . ' - ' . parent::getName();
|
||||
}
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function getDescription(){
|
||||
if(!is_null($this->getInput('post_id'))) {
|
||||
$post = $this->getPost();
|
||||
return $post->{'content'};
|
||||
}
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
@@ -205,5 +205,4 @@ class GooglePlusPostBridge extends BridgeAbstract{
|
||||
return implode('', [$scheme, $user, $pass, $host, $port, $path, $query, $fragment]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,27 +17,23 @@ class HotUKDealsBridge extends PepperBridgeAbstract {
|
||||
'hide_expired' => array(
|
||||
'name' => 'Hide expired deals',
|
||||
'type' => 'checkbox',
|
||||
'required' => 'true'
|
||||
),
|
||||
'hide_local' => array(
|
||||
'name' => 'Hide local deals',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Hide deals in physical store',
|
||||
'required' => 'true'
|
||||
),
|
||||
'priceFrom' => array(
|
||||
'name' => 'Minimal Price',
|
||||
'type' => 'text',
|
||||
'title' => 'Minmal Price in Pounds',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
'priceTo' => array(
|
||||
'name' => 'Maximum Price',
|
||||
'type' => 'text',
|
||||
'title' => 'Maximum Price in Pounds',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
),
|
||||
|
||||
@@ -45,7 +41,6 @@ class HotUKDealsBridge extends PepperBridgeAbstract {
|
||||
'group' => array(
|
||||
'name' => 'Group',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Group whose deals must be displayed',
|
||||
'values' => array(
|
||||
'2DS' => '2ds',
|
||||
@@ -1319,7 +1314,6 @@ class HotUKDealsBridge extends PepperBridgeAbstract {
|
||||
'order' => array(
|
||||
'name' => 'Order by',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Sort order of deals',
|
||||
'values' => array(
|
||||
'From the most to the least hot deal' => '-hot',
|
||||
|
@@ -7,19 +7,19 @@ class InstagramBridge extends BridgeAbstract {
|
||||
const DESCRIPTION = 'Returns the newest images';
|
||||
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'Username' => array(
|
||||
'u' => array(
|
||||
'name' => 'username',
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
array(
|
||||
'Hashtag' => array(
|
||||
'h' => array(
|
||||
'name' => 'hashtag',
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
array(
|
||||
'Location' => array(
|
||||
'l' => array(
|
||||
'name' => 'location',
|
||||
'required' => true
|
||||
@@ -82,10 +82,20 @@ class InstagramBridge extends BridgeAbstract {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . 'p/' . $media->shortcode . '/';
|
||||
|
||||
if (isset($media->owner->username)) {
|
||||
$item['author'] = $media->owner->username;
|
||||
}
|
||||
|
||||
if (isset($media->edge_media_to_caption->edges[0]->node->text)) {
|
||||
$item['title'] = $media->edge_media_to_caption->edges[0]->node->text;
|
||||
$textContent = $media->edge_media_to_caption->edges[0]->node->text;
|
||||
} else {
|
||||
$item['title'] = basename($media->display_url);
|
||||
$textContent = basename($media->display_url);
|
||||
}
|
||||
|
||||
$item['title'] = ($media->is_video ? '▶ ' : '') . trim($textContent);
|
||||
$titleLinePos = strpos(wordwrap($item['title'], 120), "\n");
|
||||
if ($titleLinePos != false) {
|
||||
$item['title'] = substr($item['title'], 0, $titleLinePos) . '...';
|
||||
}
|
||||
|
||||
if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') {
|
||||
@@ -93,7 +103,9 @@ class InstagramBridge extends BridgeAbstract {
|
||||
$item['content'] = $data[0];
|
||||
$item['enclosures'] = $data[1];
|
||||
} else {
|
||||
$item['content'] = '<img src="' . htmlentities($media->display_url) . '" alt="' . $item['title'] . '" />';
|
||||
$item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">';
|
||||
$item['content'] .= '<img src="' . htmlentities($media->display_url) . '" alt="' . $item['title'] . '" />';
|
||||
$item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent));
|
||||
$item['enclosures'] = array($media->display_url);
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,6 @@ class InstructablesBridge extends BridgeAbstract {
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Play' => array(
|
||||
'All' => '/play/',
|
||||
@@ -240,7 +239,6 @@ class InstructablesBridge extends BridgeAbstract {
|
||||
'filter' => array(
|
||||
'name' => 'Filter',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Featured' => ' ',
|
||||
'Recent' => 'recent/',
|
||||
|
@@ -34,7 +34,6 @@ class JustETFBridge extends BridgeAbstract {
|
||||
'global' => array(
|
||||
'lang' => array(
|
||||
'name' => 'Language',
|
||||
'required' => true,
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'Englisch' => 'en',
|
||||
@@ -348,6 +347,5 @@ class JustETFBridge extends BridgeAbstract {
|
||||
|
||||
return $element->plaintext;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ class KATBridge extends BridgeAbstract {
|
||||
$guessedDate['tm_year'] + 1900);
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
$catBool = $this->getInput('cat_check');
|
||||
if($catBool) {
|
||||
$catNum = $this->getInput('cat');
|
||||
|
@@ -150,5 +150,4 @@ class KernelBugTrackerBridge extends BridgeAbstract {
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ class KununuBridge extends BridgeAbstract {
|
||||
'site' => array(
|
||||
'name' => 'Site',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your site',
|
||||
'values' => array(
|
||||
'Austria' => 'at',
|
||||
@@ -23,7 +22,6 @@ class KununuBridge extends BridgeAbstract {
|
||||
'full' => array(
|
||||
'name' => 'Load full article',
|
||||
'type' => 'checkbox',
|
||||
'required' => false,
|
||||
'exampleValue' => 'checked',
|
||||
'title' => 'Activate to load full article'
|
||||
)
|
||||
|
@@ -419,7 +419,6 @@ class LeBonCoinBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function buildRequestJson() {
|
||||
|
||||
$requestJson = new StdClass();
|
||||
@@ -534,5 +533,4 @@ class LeBonCoinBridge extends BridgeAbstract {
|
||||
return json_encode($requestJson);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,12 +20,13 @@ class LeMondeInformatiqueBridge extends FeedExpander {
|
||||
str_replace(
|
||||
'/grande/',
|
||||
'/petite/',
|
||||
$article_html->find('.article-image', 0)->find('img', 0)->src
|
||||
$article_html->find('.article-image > img, figure > img', 0)->src
|
||||
)
|
||||
);
|
||||
|
||||
//No response header sets the encoding, explicit conversion is needed or subsequent xml_encode() will fail
|
||||
$item['content'] = utf8_encode($this->cleanArticle($article_html->find('div.col-primary', 0)->innertext));
|
||||
$content_node = $article_html->find('div.col-primary, div.col-sm-9', 0);
|
||||
$item['content'] = utf8_encode($this->cleanArticle($content_node->innertext));
|
||||
$item['author'] = utf8_encode($article_html->find('div.author-infos', 0)->find('b', 0)->plaintext);
|
||||
|
||||
return $item;
|
||||
|
@@ -13,7 +13,6 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'All' => 'all',
|
||||
'Action' => 'action',
|
||||
|
102
bridges/ModelKarteiBridge.php
Normal file
102
bridges/ModelKarteiBridge.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
class ModelKarteiBridge extends BridgeAbstract {
|
||||
const NAME = 'model-kartei.de';
|
||||
const URI = 'https://www.model-kartei.de/';
|
||||
const DESCRIPTION = 'Get the public comp card gallery';
|
||||
const MAINTAINER = 'fulmeek';
|
||||
const PARAMETERS = array(array(
|
||||
'model_id' => array(
|
||||
'name' => 'Model ID',
|
||||
'exampleValue' => '123456'
|
||||
)
|
||||
));
|
||||
|
||||
const LIMIT_ITEMS = 10;
|
||||
|
||||
private $feedName = '';
|
||||
|
||||
public function collectData() {
|
||||
$model_id = preg_replace('/[^0-9]/', '', $this->getInput('model_id'));
|
||||
if (empty($model_id))
|
||||
returnServerError('Invalid model ID');
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI . 'sedcards/model/' . $model_id . '/')
|
||||
or returnServerError('Model not found');
|
||||
|
||||
$objTitle = $html->find('.sTitle', 0);
|
||||
if ($objTitle)
|
||||
$this->feedName = $objTitle->plaintext;
|
||||
|
||||
$itemlist = $html->find('#photoList .photoPreview');
|
||||
if (!$itemlist)
|
||||
returnServerError('No gallery');
|
||||
|
||||
foreach($itemlist as $idx => $element) {
|
||||
if ($idx >= self::LIMIT_ITEMS)
|
||||
break;
|
||||
|
||||
$item = array();
|
||||
|
||||
$title = $element->title;
|
||||
$date = $element->{'data-date'};
|
||||
$author = $this->feedName;
|
||||
$text = '';
|
||||
|
||||
$objImage = $element->find('a.photoLink img', 0);
|
||||
$objLink = $element->find('a.photoLink', 0);
|
||||
|
||||
if ($objLink) {
|
||||
$page = getSimpleHTMLDOMCached($objLink->href);
|
||||
|
||||
if (empty($title)) {
|
||||
$objTitle = $page->find('.p-title', 0);
|
||||
if ($objTitle)
|
||||
$title = $objTitle->plaintext;
|
||||
}
|
||||
if (empty($date)) {
|
||||
$objDate = $page->find('.cameraDetails .date', 0);
|
||||
if ($objDate)
|
||||
$date = strtotime($objDate->parent()->plaintext);
|
||||
}
|
||||
if (empty($author)) {
|
||||
$objAuthor = $page->find('.p-publisher a', 0);
|
||||
if ($objAuthor)
|
||||
$author = $objAuthor->plaintext;
|
||||
}
|
||||
|
||||
$objFullImage = $page->find('img#gofullscreen', 0);
|
||||
if ($objFullImage)
|
||||
$objImage = $objFullImage;
|
||||
|
||||
$objText = $page->find('.p-desc', 0);
|
||||
if ($objText)
|
||||
$text = $objText->plaintext;
|
||||
}
|
||||
|
||||
$item['title'] = $title;
|
||||
$item['timestamp'] = $date;
|
||||
$item['author'] = $author;
|
||||
|
||||
if ($objImage)
|
||||
$item['content'] = '<img src="' . $objImage->src . '"/>';
|
||||
if ($objLink) {
|
||||
$item['uri'] = $objLink->href;
|
||||
if (!empty($item['content']))
|
||||
$item['content'] = '<a href="' . $objLink->href . '" target="_blank">' . $item['content'] . '</a>';
|
||||
} else {
|
||||
$item['uri'] = 'urn:sha1:' . hash('sha1', $item['content']);
|
||||
}
|
||||
if (!empty($text))
|
||||
$item['content'] = '<p>' . $text . '</p>' . $item['content'];
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!empty($this->feedName)) {
|
||||
return $this->feedName . ' - ' . self::NAME;
|
||||
}
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
@@ -21,7 +21,8 @@ class MozillaSecurityBridge extends BridgeAbstract {
|
||||
$item['title'] = $element->innertext;
|
||||
$item['timestamp'] = strtotime($element->innertext);
|
||||
$item['content'] = $element->next_sibling()->innertext;
|
||||
$item['uri'] = self::URI;
|
||||
$item['uri'] = self::URI . '?' . $item['timestamp'];
|
||||
$item['uid'] = self::URI . '?' . $item['timestamp'];
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
@@ -17,27 +17,23 @@ class MydealsBridge extends PepperBridgeAbstract {
|
||||
'hide_expired' => array(
|
||||
'name' => 'Abgelaufenes ausblenden',
|
||||
'type' => 'checkbox',
|
||||
'required' => 'true'
|
||||
),
|
||||
'hide_local' => array(
|
||||
'name' => 'Lokales ausblenden',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Deals im physischen Geschäft ausblenden',
|
||||
'required' => 'true'
|
||||
),
|
||||
'priceFrom' => array(
|
||||
'name' => 'Minimaler Preis',
|
||||
'type' => 'text',
|
||||
'title' => 'Minmaler Preis in Euros',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
'priceTo' => array(
|
||||
'name' => 'Maximaler Preis',
|
||||
'type' => 'text',
|
||||
'title' => 'maximaler Preis in Euro',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
'required' => false
|
||||
),
|
||||
),
|
||||
|
||||
@@ -45,7 +41,6 @@ class MydealsBridge extends PepperBridgeAbstract {
|
||||
'group' => array(
|
||||
'name' => 'Gruppen',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Gruppe, deren Deals angezeigt werden müssen',
|
||||
'values' => array(
|
||||
'Elektronik' => 'elektronik',
|
||||
@@ -68,7 +63,6 @@ class MydealsBridge extends PepperBridgeAbstract {
|
||||
'order' => array(
|
||||
'name' => 'sortieren nach',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Sortierung der deals',
|
||||
'values' => array(
|
||||
'Vom heißesten zum kältesten Deal' => '',
|
||||
|
37
bridges/N26Bridge.php
Normal file
37
bridges/N26Bridge.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
class N26Bridge extends BridgeAbstract
|
||||
{
|
||||
const MAINTAINER = 'quentinus95';
|
||||
const NAME = 'N26 Blog';
|
||||
const URI = 'https://n26.com';
|
||||
const CACHE_TIMEOUT = 1800;
|
||||
const DESCRIPTION = 'Returns recent blog posts from N26.';
|
||||
|
||||
public function getIcon()
|
||||
{
|
||||
return 'https://n26.com/favicon.ico';
|
||||
}
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
$html = getSimpleHTMLDOM(self::URI . '/en-fr/blog-archive')
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
foreach($html->find('div.ga') as $article) {
|
||||
$item = [];
|
||||
|
||||
$item['uri'] = self::URI . $article->find('h2 a', 0)->href;
|
||||
$item['title'] = $article->find('h2 a', 0)->plaintext;
|
||||
|
||||
$fullArticle = getSimpleHTMLDOM($item['uri'])
|
||||
or returnServerError('Error while downloading the full article');
|
||||
|
||||
$dateElement = $fullArticle->find('span[class="fk fl de ch fm by"]', 0);
|
||||
$item['timestamp'] = strtotime($dateElement->plaintext);
|
||||
$item['content'] = $fullArticle->find('main article', 0)->innertext;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@ class NineGagBridge extends BridgeAbstract {
|
||||
'd' => array(
|
||||
'name' => 'Section',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Hot' => 'hot',
|
||||
'Trending' => 'trending',
|
||||
@@ -28,7 +27,6 @@ class NineGagBridge extends BridgeAbstract {
|
||||
'g' => array(
|
||||
'name' => 'Section',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Animals' => 'cute',
|
||||
'Anime & Manga' => 'anime-manga',
|
||||
@@ -88,7 +86,6 @@ class NineGagBridge extends BridgeAbstract {
|
||||
't' => array(
|
||||
'name' => 'Type',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Hot' => 'hot',
|
||||
'Fresh' => 'fresh',
|
||||
|
@@ -21,8 +21,7 @@ class NotAlwaysBridge extends BridgeAbstract {
|
||||
'Friendly' => 'friendly',
|
||||
'Hopeless' => 'hopeless',
|
||||
'Unfiltered' => 'unfiltered'
|
||||
),
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
|
@@ -9,7 +9,6 @@ class OnVaSortirBridge extends FeedExpander {
|
||||
'city' => array(
|
||||
'name' => 'City',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Agen' => 'Agen',
|
||||
'Ajaccio' => 'Ajaccio',
|
||||
@@ -111,11 +110,11 @@ class OnVaSortirBridge extends FeedExpander {
|
||||
'Valence' => 'valence',
|
||||
'Vannes' => 'vannes',
|
||||
'Zurich' => 'zurich',
|
||||
),
|
||||
'defaultValue' => ''
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
$html = getSimpleHTMLDOMCached($item['uri']);
|
||||
@@ -123,6 +122,7 @@ class OnVaSortirBridge extends FeedExpander {
|
||||
$item['content'] = utf8_encode($text);
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('https://' .
|
||||
$this->getInput('city') . '.onvasortir.com/rss.php');
|
||||
|
962
bridges/OneFortuneADayBridge.php
Normal file
962
bridges/OneFortuneADayBridge.php
Normal file
@@ -0,0 +1,962 @@
|
||||
<?php
|
||||
class OneFortuneADayBridge extends BridgeAbstract {
|
||||
const NAME = 'One Fortune a Day';
|
||||
const URI = 'https://github.com/fulmeek';
|
||||
const DESCRIPTION = 'Get a fortune quote every single day.';
|
||||
const MAINTAINER = 'fulmeek';
|
||||
const PARAMETERS = array(array(
|
||||
'time' => array(
|
||||
'name' => 'Time in UTC',
|
||||
'type' => 'list',
|
||||
'values' => array(
|
||||
'0:00' => 0,
|
||||
'1:00' => 1,
|
||||
'2:00' => 2,
|
||||
'3:00' => 3,
|
||||
'4:00' => 4,
|
||||
'5:00' => 5,
|
||||
'6:00' => 6,
|
||||
'7:00' => 7,
|
||||
'8:00' => 8,
|
||||
'9:00' => 9,
|
||||
'10:00' => 10,
|
||||
'11:00' => 11,
|
||||
'12:00' => 12,
|
||||
'13:00' => 13,
|
||||
'14:00' => 14,
|
||||
'15:00' => 15,
|
||||
'16:00' => 16,
|
||||
'17:00' => 17,
|
||||
'18:00' => 18,
|
||||
'19:00' => 19,
|
||||
'20:00' => 20,
|
||||
'21:00' => 21,
|
||||
'22:00' => 22,
|
||||
'23:00' => 23,
|
||||
),
|
||||
'defaultValue' => 5
|
||||
),
|
||||
'lucky' => array(
|
||||
'name' => 'Lucky number (optional)',
|
||||
'type' => 'text'
|
||||
)
|
||||
));
|
||||
|
||||
const LIMIT_ITEMS = 7;
|
||||
const DAY_SECS = 86400;
|
||||
|
||||
public function getDescription(){
|
||||
return self::DESCRIPTION . '<br/>Set a lucky number to get your personal quotes, like ' . mt_rand();
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
$time = gmmktime((int)$this->getInput('time'), 0, 0);
|
||||
if ($time > time())
|
||||
$time -= self::DAY_SECS;
|
||||
|
||||
for ($i = self::LIMIT_ITEMS; $i > 0; --$i) {
|
||||
$seed = gmdate('Ymd', $time) . $this->getInput('lucky');
|
||||
$quote = $this->getQuote($seed);
|
||||
|
||||
$item['title'] = strftime('%A, %x', $time);
|
||||
$item['content'] = htmlentities($quote, ENT_QUOTES, 'UTF-8');
|
||||
$item['timestamp'] = $time;
|
||||
$item['uid'] = hash('sha1', $seed);
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
$time -= self::DAY_SECS;
|
||||
}
|
||||
}
|
||||
|
||||
private function getQuote($seed) {
|
||||
$quotes = explode('//', <<<QUOTES
|
||||
People are naturally attracted to you.
|
||||
//You learn from your mistakes... You will learn a lot today.
|
||||
//If you have something good in your life, don't let it go!
|
||||
//What ever you're goal is in life, embrace it visualize it, and for it will be
|
||||
yours.
|
||||
//Your shoes will make you happy today.
|
||||
//You cannot love life until you live the life you love.
|
||||
//Be on the lookout for coming events; They cast their shadows beforehand.
|
||||
//Land is always on the mind of a flying bird.
|
||||
//The man or woman you desire feels the same about you.
|
||||
//Meeting adversity well is the source of your strength.
|
||||
//A dream you have will come true.
|
||||
//Our deeds determine us, as much as we determine our deeds.
|
||||
//Never give up. You're not a failure if you don't give up.
|
||||
//You will become great if you believe in yourself.
|
||||
//There is no greater pleasure than seeing your loved ones prosper.
|
||||
//You will marry your lover.
|
||||
//A very attractive person has a message for you.
|
||||
//You already know the answer to the questions lingering inside your head.
|
||||
//It is now, and in this world, that we must live.
|
||||
//You must try, or hate yourself for not trying.
|
||||
//You can make your own happiness.
|
||||
//The greatest risk is not taking one.
|
||||
//The love of your life is stepping into your planet this summer.
|
||||
//Love can last a lifetime, if you want it to.
|
||||
//Adversity is the parent of virtue.
|
||||
//Serious trouble will bypass you.
|
||||
//A short stranger will soon enter your life with blessings to share.
|
||||
//Now is the time to try something new.
|
||||
//Wealth awaits you very soon.
|
||||
//If you feel you are right, stand firmly by your convictions.
|
||||
//If winter comes, can spring be far behind?
|
||||
//Keep your eye out for someone special.
|
||||
//You are very talented in many ways.
|
||||
//A stranger, is a friend you have not spoken to yet.
|
||||
//A new voyage will fill your life with untold memories.
|
||||
//You will travel to many exotic places in your lifetime.
|
||||
//Your ability for accomplishment will follow with success.
|
||||
//Nothing astonishes men so much as common sense and plain dealing.
|
||||
//Its amazing how much good you can do if you dont care who gets the credit.
|
||||
//Everyone agrees. You are the best.
|
||||
//LIFE CONSIST NOT IN HOLDING GOOD CARDS, BUT IN PLAYING THOSE YOU HOLD WELL.
|
||||
//Jealousy doesn't open doors, it closes them!
|
||||
//It's better to be alone sometimes.
|
||||
//When fear hurts you, conquer it and defeat it!
|
||||
//Let the deeds speak.
|
||||
//You will be called in to fulfill a position of high honor and responsibility.
|
||||
//The man on the top of the mountain did not fall there.
|
||||
//You will conquer obstacles to achieve success.
|
||||
//Joys are often the shadows, cast by sorrows.
|
||||
//Fortune favors the brave.
|
||||
//An upward movement initiated in time can counteract fate.
|
||||
//A journey of a thousand miles begins with a single step.
|
||||
//Sometimes you just need to lay on the floor.
|
||||
//Never give up. Always find a reason to keep trying.
|
||||
//If you have something worth fighting for, then fight for it.
|
||||
//Stop wishing. Start doing.
|
||||
//Accept your past without regrets. Handle your present with confidence. Face
|
||||
your future without fear.
|
||||
//Stay true to those who would do the same for you.
|
||||
//Ask yourself if what you are doing today is getting you closer to where you
|
||||
want to be tomorrow.
|
||||
//Happiness is an activity.
|
||||
//Help is always needed but not always appreciated. Stay true to your heart and
|
||||
help those in need weather they appreciate it or not.
|
||||
//Hone your competitive instincts.
|
||||
//Finish your work on hand don't be greedy.
|
||||
//For success today, look first to yourself.
|
||||
//Your fortune is as sweet as a cookie.
|
||||
//Integrity is the essence of everything successful.
|
||||
//If you're happy, you're successful.
|
||||
//You will always be surrounded by true friends
|
||||
//Believing that you are beautiful will make you appear beautiful to others
|
||||
around you.
|
||||
//Happinees comes from a good life.
|
||||
//Before trying to please others think of what makes you happy.
|
||||
//When hungry, order more Chinese food.
|
||||
//Your golden opportunity is coming shortly.
|
||||
//For hate is never conquered by hate. Hate is conquered by love .
|
||||
//You will make many changes before settling down happily.
|
||||
//A man is born to live and not prepare to live.
|
||||
//You cannot become rich except by enriching others.
|
||||
//Don't pursue happiness - create it.
|
||||
//You will be successful in love.
|
||||
//All your fingers can't be of the same length.
|
||||
//Wise sayings often fall on barren ground, but a kind word is never thrown away.
|
||||
//A lifetime of happiness is in store for you.
|
||||
//It is very possible that you will achieve greatness in your lifetime.
|
||||
//Be tactful; overlook your own opportunity.
|
||||
//You are the controller of your destiny.
|
||||
//Everything happens for a reson.
|
||||
//How can you have a beutiful ending without making beautiful mistakes.
|
||||
//You can open doors with your charm and patience.
|
||||
//Welcome the change coming into your life.
|
||||
//There will be a happy romance for you shortly.
|
||||
//Your fondest dream will come true within this year.
|
||||
//You have a deep interest in all that is artistic.
|
||||
//Your emotional nature is strong and sensitive.
|
||||
//A letter of great importance may reach you any day now.
|
||||
//Good health will be yours for a long time.
|
||||
//You will become better acquainted with a coworker.
|
||||
//To be old and wise, you must first be young and stupid.
|
||||
//Failure is only the opportunity to begin again more intelligently.
|
||||
//Integrity is doing the right thing, even if nobody is watching.
|
||||
//Conquer your fears or they will conquer you.
|
||||
//You are a lover of words; One day you will write a book.
|
||||
//In this life it is not what we take up, but what we give up, that makes us
|
||||
rich.
|
||||
//Fear can keep us up all night long, but faith makes one fine pillow.
|
||||
//Seek out the significance of your problem at this time. Try to understand.
|
||||
//Never upset the driver of the car you're in; they're the master of your
|
||||
destiny until you get home.
|
||||
//He who slithers among the ground is not always a foe.
|
||||
//You learn from your mistakes, you will learn a lot today.
|
||||
//You only need look to your own reflection for inspiration. Because you are
|
||||
Beautiful!
|
||||
//You are not judged by your efforts you put in; you are judged on your
|
||||
performance.
|
||||
//Rivers need springs.
|
||||
//Good news from afar may bring you a welcome visitor.
|
||||
//When all else seems to fail, smile for today and just love someone.
|
||||
//Patience is a virtue, unless its against a brick wall.
|
||||
//When you look down, all you see is dirt, so keep looking up.
|
||||
//If you are afraid to shake the dice, you will never throw a six.
|
||||
//Even if the person who appears most wrong, is also quite often right.
|
||||
//A single conversation with a wise man is better than ten years of study.
|
||||
//Happiness is often a rebound from hard work.
|
||||
//The world may be your oyster, but that doesn't mean you'll get it's pearl.
|
||||
//Your life will be filled with magical moments.
|
||||
//You're true love will show himself to you under the moonlight.
|
||||
//Do not follow where the path may lead. Go where there is no path...and leave a
|
||||
trail
|
||||
//Do not fear what you don't know
|
||||
//The object of your desire comes closer.
|
||||
//You have a flair for adding a fanciful dimension to any story.
|
||||
//If you wish to know the mind of a man, listen to his words
|
||||
//The most useless energy is trying to change what and who God so carefully
|
||||
created.
|
||||
//Do not be covered in sadness or be fooled in happiness they both must exist
|
||||
//You will have unexpected great good luck.
|
||||
//You will have a pleasant surprise
|
||||
//All progress occurs because people dare to be different.
|
||||
//Your ability for accomplishment will be followed by success.
|
||||
//The world is always ready to receive talent with open arms.
|
||||
//Things may come to those who wait, but only the things left by those who
|
||||
hustle.
|
||||
//We can't help everyone. But everyone can help someone.
|
||||
//Every day is a new day. But tomorrow is never promised.
|
||||
//Express yourself: Don't hold back!
|
||||
//It is not necessary to show others you have change; the change will be obvious.
|
||||
//You have a deep appreciation of the arts and music.
|
||||
//If your desires are not extravagant, they will be rewarded.
|
||||
//You try hard, never to fail. You don't, never to win.
|
||||
//Never give up on someone that you don't go a day without thinking about.
|
||||
//It never pays to kick a skunk.
|
||||
//In case of fire, keep calm, pay bill and run.
|
||||
//Next full moon brings an enchanting evening.
|
||||
//Not all closed eye is sleeping nor open eye is seeing.
|
||||
//Impossible is a word only to be found in the dictionary of fools.
|
||||
//You will soon witness a miracle.
|
||||
//The time is alway right to do what is right.
|
||||
//Love is as necessary to human beings as food and shelter.
|
||||
//You will make heads turn.
|
||||
//You are extremely loved. Don't worry :)
|
||||
//If you are never patient, you will never get anything done. If you believe you
|
||||
can do it, you will be rewarded with success.
|
||||
//You will soon embark on a business venture.
|
||||
//You believe in the goodness of man kind.
|
||||
//You will have a long and wealthy life.
|
||||
//You will take a pleasant journey to a place far away.
|
||||
//You are a person of culture.
|
||||
//Keep it simple. The more you say, the less people remember.
|
||||
//Life is like a dogsled team. If you ain't the lead dog, the scenery never
|
||||
changes.
|
||||
//Prosperity makes friends and adversity tries them.
|
||||
//Nothing seems impossible to you.
|
||||
//Patience is bitter, but its fruit is sweet.
|
||||
//The only certainty is that nothing is certain.
|
||||
//Success is the sum of my unique visions realized by the sweat of perseverance.
|
||||
//When you expect your opponent to yield, you also should avoid hurting him.
|
||||
//Human evolution: “wider freeway but narrower viewpoints.
|
||||
//Intelligence is the door to freedom and alert attention is the mother of
|
||||
intelligence.
|
||||
//Back away from individuals who are impulsive.
|
||||
//Enjoyed the meal? Buy one to go too.
|
||||
//You believe in the goodness of mankind.
|
||||
//A big fortune will descend upon you this year.
|
||||
//Now these three remain, faith, hope, and love. The greatest of these is love.
|
||||
//For success today look first to yourself.
|
||||
//Determination is the wake-up call to the human will.
|
||||
//There are no limitations to the mind except those we aknowledge.
|
||||
//A merry heart does good like a medicine.
|
||||
//Whenever possible, keep it simple.
|
||||
//Your dearest wish will come true.
|
||||
//Poverty is no disgrace.
|
||||
//If you don’t do it excellently, don’t do it at all.
|
||||
//You have an unusual equipment for success, use it properly.
|
||||
//Emotion is energy in motion.
|
||||
//You will soon be honored by someone you respect.
|
||||
//Punctuality is the politeness of kings and the duty of gentle people
|
||||
everywhere.
|
||||
//Your happiness is intertwined with your outlook on life.
|
||||
//Elegant surroundings will soon be yours.
|
||||
//If you feel you are right, stand firmly by your convictions.
|
||||
//Your smile brings happiness to everyone you meet.
|
||||
//Instead of worrying and agonizing, move ahead constructively.
|
||||
//Do you believe? Endurance and persistence will be rewarded.
|
||||
//A new business venture is on the horizon.
|
||||
//Never underestimate the power of the human touch.
|
||||
//Hold on to the past but eventually, let the times go and keep the memories
|
||||
into the present.
|
||||
//Truth is an unpopular subject. Because it is unquestionably correct.
|
||||
//The most important thing in communication is to hear what isn’t being said.
|
||||
//You are broad minded and socially active.
|
||||
//Your dearest dream is coming true. God looks after you especially.
|
||||
//You will recieve some high prize or award.
|
||||
//Your present question marks are going to succeed.
|
||||
//You have a fine capacity for the enjoyment of life.
|
||||
//You will live long and enjoy life.
|
||||
//An admirer is concealing his/her affection for you.
|
||||
//A wish is what makes life happen when you dream of rose petals.
|
||||
//Love can turn cottage into a golden palace.
|
||||
//Lend your money and lose your freind.
|
||||
//You will kiss your crush ohhh lalahh
|
||||
//You will be rewarded for being a good listener in the next week.
|
||||
//If you never give up on love, It will never give up on you.
|
||||
//Unleash your life force.
|
||||
//Your wish will come true.
|
||||
//There is a prospect of a thrilling time ahead for you.
|
||||
//No distance is too far, if two hearts are tied together.
|
||||
//Land is always in the mind of the flying birds.
|
||||
//Try? No! Do or do not, there is no try.
|
||||
//Do not worry, you will have great peace.
|
||||
//It's about time you asked that special someone on a date.
|
||||
//You create your own stage ... the audience is waiting.
|
||||
//It is never too late. Just as it is never too early.
|
||||
//Discover the power within yourself.
|
||||
//Good things take time.
|
||||
//Stop thinking about the road not taken and pave over the one you did.
|
||||
//Put your unhappiness aside. Life is beautiful, be happy.
|
||||
//You can still love what you can not have in life.
|
||||
//Make a wise choice everyday.
|
||||
//Circumstance does not make the man; it reveals him to himself.
|
||||
//The man who waits till tomorrow, misses the opportunities of today.
|
||||
//Life does not get better by chance. It gets better by change.
|
||||
//If you never expect anything you can never be disappointed.
|
||||
//People in your surroundings will be more cooperative than usual.
|
||||
//True wisdom is found in happiness.
|
||||
//Ones always regrets what could have done. Remember for next time.
|
||||
//Follow your bliss and the Universe will open doors where there were once only
|
||||
walls.
|
||||
//Find a peaceful place where you can make plans for the future.
|
||||
//All the water in the world can't sink a ship unless it gets inside.
|
||||
//The earth is a school learn in it.
|
||||
//In music, one must think with his heart and feel with his brain.
|
||||
//If you speak honestly, everyone will listen.
|
||||
//Ganerosity will repay itself sooner than you imagine.
|
||||
//good things take time
|
||||
//Do what is right, not what you should.
|
||||
//To effect the quality of the day is no small achievement.
|
||||
//Simplicity and clearity should be the theme in your dress.
|
||||
//Virtuous find joy while Wrongdoers find grieve in their actions.
|
||||
//Not all closed eye is sleeping, nor open eye is seeing.
|
||||
//Bread today is better than cake tomorrow.
|
||||
//In evrything there is a piece of truth.But a piece.
|
||||
//A feeling is an idea with roots.
|
||||
//Man is born to live and not prepare to live
|
||||
//It's all right to have butterflies in your stomach. Just get them to fly in
|
||||
formation.
|
||||
//If you don t give something, you will not get anything
|
||||
//The harder you try to not be like your parents, the more likely you will
|
||||
become them
|
||||
//Someday everything will all make perfect sense
|
||||
//you will think for yourself when you stop letting others think for you
|
||||
//Everything will be ok. Don't obsess. Time will prove you right, you must stay
|
||||
where you are.
|
||||
//Let's finish this up now, someone is waiting for you on that
|
||||
//The finest men like the finest steels have been tempered in the hottest
|
||||
furnace.
|
||||
//A dream you have will come true
|
||||
//The worst of friends may become the best of enemies, but you will always find
|
||||
yourself hanging on.
|
||||
//I think, you ate your fortune while you were eating your cookie
|
||||
//If u love someone keep fighting for them
|
||||
//Do what you want, when you want, and you will be rewarded
|
||||
//Let your fantasies unwind...
|
||||
//The cooler you think you are the dumber you look
|
||||
//Expect great things and great things will come
|
||||
//The Wheel of Good Fortune is finally turning in your direction!
|
||||
//Don't lead if you won't lead.
|
||||
//You will always be successful in your professional career
|
||||
//Share your hapiness with others today.
|
||||
//It's up to you to clearify.
|
||||
//Your future will be happy and productive.
|
||||
//Seize every second of your life and savor it.
|
||||
//Those who walk in other's tracks leave no footprints.
|
||||
//Failure is the mother of all success.
|
||||
//Difficulty at the beginning useually means ease at the end.
|
||||
//Do not seek so much to find the answer as much as to understand the question
|
||||
better.
|
||||
//Your way of doing what other people do their way is what makes you special.
|
||||
//A beautiful, smart, and loving person will be coming into your life.
|
||||
//Friendship is an ocean that you cannot see bottom.
|
||||
//Your life does not get better by chance, it gets better by change.
|
||||
//Our duty,as men and women,is to proceed as if limits to our ability did not
|
||||
exist.
|
||||
//A pleasant expeience is ahead:don't pass it by.
|
||||
//Our perception and attitude toward any situation will determine the outcome
|
||||
//They say you are stubborn; you call it persistence.
|
||||
//Two small jumps are sometimes better than one big leap.
|
||||
//A new wardrobe brings great joy and change to your life.
|
||||
//The cure for grief is motion.
|
||||
//It's a good thing that life is not as serious as it seems to the waiter
|
||||
//I hear and I forget. I see and I remember. I do and I understand.
|
||||
//I have a dream....Time to go to bed.
|
||||
//Ideas you believe are absurd ultimately lead to success!
|
||||
//A human being is a deciding being.
|
||||
//Today is an ideal time to water your parsonal garden.
|
||||
//Some men dream of fortunes, others dream of cookies.
|
||||
//Things are never quite the way they seem.
|
||||
//the project on your mind will soon gain momentum
|
||||
//YOUR FAILURES WILL LEAD YOU TO YOUR SUCCESS.
|
||||
//IN ORDER TO GET THE RAINBOW, YOU MUST ENDURE THE RAIN.
|
||||
//Beauty is simply beauty. originality is magical.
|
||||
//Your dream will come true when you least expect it.
|
||||
//Let not your hand be stretched out to receive and shut when you should repay.
|
||||
//Don't worry, half the people you know are below average.
|
||||
//Vision is the art of seeing what is invisible to others.
|
||||
//You don't need talent to gain experience.
|
||||
//A focused mind is one of the most powerful forces in the universe.
|
||||
//Today you shed your last tear. Tomorrow fortune knocks at your door.
|
||||
//Be patient! The Great Wall didn't got build in one day.
|
||||
//Think you can. Think you can't. Either way, you'll be right.
|
||||
//Wisdom is on her way to you.
|
||||
//Digital circuits are made from analog parts.
|
||||
//If you eat a box of fortune cookies, anything is possible.
|
||||
//The best is yet to come.
|
||||
//I'm with you.
|
||||
//Be direct,usually one can accomplish more that way.
|
||||
//A single kind work will keep one warm for years.
|
||||
//Ask a friend to join you on your next voyage.
|
||||
//In God we trust.
|
||||
//Love is free. Lust will cost you everything you have.
|
||||
//Stop searching forever, happiness is just next to you.
|
||||
//You don't need the answers to all of life's questions. Just ask your father
|
||||
what to do.
|
||||
//Jealousy is a useless emotion.
|
||||
//You are not a ghost.
|
||||
//There is someone rather annoying in your life that you need to listen to.
|
||||
//You will plant the smallest seed and it will become the greatest and most
|
||||
mighty tree in the world.
|
||||
//The dream you've been dreaming all your life isn't worth it. Find a new dream,
|
||||
and once you're sure you've found it, fight for it.
|
||||
//See if you can learn anything from the children.
|
||||
//It's Never Too Late For Good Things To Happen!
|
||||
//A clear conscience is usually the sign of a bad memory.
|
||||
//Aim high, time flies.
|
||||
//One is not sleeping, does not mean they are awake.
|
||||
//A great pleasure in life is doing what others say you can't.
|
||||
//Isn't there something else you should be working on right now?
|
||||
//Your father still loves and is in always with you. Remember that.
|
||||
//Before you can be reborn you must die.
|
||||
//It better to be the hammer than the nail.
|
||||
//You are admired by everyone for your talent and ability.
|
||||
//Save the whales. Collect the whole set.
|
||||
//You will soon discover a major truth about the one you love most.
|
||||
//Your life will prosper only if you acknowledge your faults and work to reduce
|
||||
them.
|
||||
//Pray to God, but row towards shore.
|
||||
//You will soon witness a miracle.
|
||||
//The early bird gets the worm, but the second mouse gets the cheese
|
||||
//Help, I'm being held prisoner in a Chinese cookie factory.
|
||||
//Alas! The onion you are eating is someone else’s water lily.
|
||||
//You are a persoon with a good sense of justice, now it's time to act like it.
|
||||
//You create enthusiasm around you.
|
||||
//There are big changes ahead for you. They will be good ones!
|
||||
//You will have many happy days soon.
|
||||
//Out of confusion comes new patterns.
|
||||
//If you love someone enough and they break your heart, you can't stop yourself
|
||||
from still loving them again even after all that pain.
|
||||
//Look right...Now look left...Now look forward (do this really fast) do you
|
||||
feel any different? good you should feel dizzy.
|
||||
//Live like you are on the bottom, even if you are on the top.
|
||||
//You will soon emerge victorious from the maze you've been traveling in.
|
||||
//Do not judge a book by it's color.
|
||||
//Everything will come your way.
|
||||
//There is a time to be practical now.
|
||||
//Bend the rod while it is still hot.
|
||||
//Darkness is only succesful when there is no light. Don't forget about light!
|
||||
//Acting is not lying. It is findind someone hiding inside you and letting that
|
||||
person run free.
|
||||
//You will be forced to face fear, but if you do not run, fear will be afraid of
|
||||
you.
|
||||
//You are thinking about doing something. Don't do it, it won't help anything.
|
||||
//Your worst enemy has a crush on you!
|
||||
//Love Conquers all.
|
||||
//The phrase is follow your dreams. Not dream period.
|
||||
//stop nagging to your partner and take it day by day.
|
||||
//Do not think that me or my brothers have supreme control over what will happen
|
||||
to you.
|
||||
//Bad luck and misfortune will follow you all your days.
|
||||
//Remember the fate of the early Worm.
|
||||
//Begin your life anew with strength, grace and wonder.
|
||||
//Be a good friend and a fair enemy.
|
||||
//What goes around comes around.
|
||||
//Bad luck and misfortune will infest your pathetic soul for all eternity.
|
||||
//The best prophet of the future is the past
|
||||
//Movies have pause buttons, friends do not
|
||||
//Use the force.
|
||||
//Trust your intuition.
|
||||
//Encourage your peers.
|
||||
//Let your imagination wander.
|
||||
//Your pain is the breaking of the shell that encloses your understanding.
|
||||
//Patience is key, a wait short or long will have its reward.
|
||||
//Tell them before it's too late...
|
||||
//A bird in the hand is worth three in the bush!!
|
||||
//Be assertive when decisive action is needed.
|
||||
//To determine whether someone is beautiful is not by looking at his/her
|
||||
appearance, but his/her heart.
|
||||
//Hope brings about a better future
|
||||
//While you have this day, fill it with life. While you're in this moment, give
|
||||
it your own special meaning and purpose and joy.
|
||||
//Even though it will often be difficult and complicated, you know you have what
|
||||
it takes to get it done.
|
||||
//You can choose, right now and in every moment, to put your powerful and
|
||||
effective abilities to purposeful use. There is always something you can do, no
|
||||
matter what the situation may be, that will move your life forward.
|
||||
//IT IS NOT GOOD TO BE A USER BLESSINGS COME FROM BEING A GIVER NOT A TAKER.
|
||||
//Cookie says, You crack me up
|
||||
//You will prosper in the field of wacky inventions.
|
||||
//Your tongue is your ambassador.
|
||||
//The cure for grief is movement.
|
||||
//Love Is At Your Hands Be Glad And Hold On To It.
|
||||
//You are often asked if it is in yet.
|
||||
//Life to you is a bold and dashing responsibility.
|
||||
//Patience is a key to joy.
|
||||
//A bargain is something you don't need at a price you can't resist.
|
||||
//Today is going to be a disasterous day, be prepared!
|
||||
//Stay to your inner-self, you will benefit in many ways.
|
||||
//Rarely do great beauty and great virtue dwell together as they do in you.
|
||||
//You are talented in many ways.
|
||||
//You are the master of every situation.
|
||||
//Your problem just got bigger. Think, what have you done.
|
||||
//If your cookie still in one piece, buy lotto.
|
||||
//Go with the flow will make your transition ever so much easier.
|
||||
//Tomorrow Morning,Take a Left Turn As Soon As You Leave Home
|
||||
//A metaphor could save your life.
|
||||
//Don't wait for your ship to come in, swim out to it
|
||||
//There are lessons to be learned by listening to others.
|
||||
//If you want the rainbow, you have to tolerate the rain.
|
||||
//Volition, Strength, Languages, Freedom and Power rests in you.
|
||||
//TOO MANY PEOPLE VOLUNTEER TO CARRY THE STOOL WHEN ITS TIME TO MOVE THE PIANO
|
||||
//It takes more than a good memory to have good memories.
|
||||
//You are what you are; understand yourself before you react
|
||||
//Word to the wise: Don't play leapfrog with a unicorn.........
|
||||
//Forgive your enemies, but never forget them.
|
||||
//Everything will now come your way
|
||||
//Don't worry about the stock market. Invest in family.
|
||||
//Your fortune is as sweet as a cookie.
|
||||
//It is much easier to look for the bad, than it is to find the good
|
||||
//If a person who has caused you pain and suffering has brought you, reconsider
|
||||
that person's value in your life
|
||||
//You are worth loving, you are also worth the effort it takes to love you
|
||||
//Never trouble trouble till trouble troubles you.
|
||||
//Get off to a new start - come out of your shell.
|
||||
//Life is a dancefloor,you are the DJ!
|
||||
//Cooperate with those who have both know how and integrith.
|
||||
//Minor aches today are likely to pay off handsomely tomorrow.
|
||||
//You are about to become $8.95 poorer. ($6.95 if you had the buffet)
|
||||
//Your mouth may be moving, but nobody is listening.
|
||||
//Focus in on the color yellow tomorrow for good luck!
|
||||
//The problem with resisting temptation is that it may never come again.
|
||||
//All your sorrows will vanish.
|
||||
//About time I got out of that cookie.
|
||||
//Love will lead the way.
|
||||
//The ads revenge is massive success
|
||||
//It is best to act with confidence, no matter how little right you have to it.
|
||||
//Soon, a visitor shall delight you.
|
||||
//What breaks in a moment may take years to mend.
|
||||
//Someone stole your fortune and replaced it with this one. Your luck sucks.
|
||||
Have a good day!
|
||||
//Take control of your life rather than letting things happen just like that!
|
||||
//You will be rewarded for your patience and understanding.
|
||||
//You will achieve all your desires and pleasures.
|
||||
//Never miss a chance to keep your mouth shut.
|
||||
//Nothing Shows A Man's Character More Than What He Laughs At.
|
||||
//Never regret anything that made you smile.
|
||||
//Love Takes Pratice.
|
||||
//Don't take yourself so seriously, no one else does.
|
||||
//You've got what it takes, but it will take everything you've got!
|
||||
//At this very moment you can change the rest of your life.
|
||||
//Become who you are.
|
||||
//All comes at the proper time to him who knows how to wait.
|
||||
//The energy is within you. Money is Coming!
|
||||
//The quotes that you do not understand, are not meant for you.
|
||||
//You have an important new business development shaping up.
|
||||
//if love someone a lot tell it before it's too late
|
||||
//Birds are entangled by their feet and men by their tongues.
|
||||
//Benefit by doing things that others give up on.
|
||||
//Rest has a peaceful effect on your physical and emotional health.
|
||||
//One of the best ways to persuade others is with your ears--by listening to
|
||||
them.
|
||||
//Plan your work and work your plan.
|
||||
//Over self-confidence is equal to being blind.
|
||||
//Those who bring sunshine to the lives of others cannot keep it from themselves.
|
||||
//Love or money, or neither?
|
||||
//Before the beginning of great brilliance, there must be chaos.
|
||||
//Old friends make best friends.
|
||||
//Stop searching forever. Happiness is just next to you.
|
||||
//Accept something that you cannot change, and you will feel better.
|
||||
//Kiss is not a kiss without the heart.
|
||||
//Enhance your karma by engaging in various charitable activities.
|
||||
//You will have good luck and overcome many hardships.
|
||||
//You never hesitate to tackle the most difficult problems.
|
||||
//Hope is like food. You will starve without it.
|
||||
//WHEN FIRE AND WATER GO TO WAR WATER ALWAYS WINS.
|
||||
//An angry man opens his mouth and shuts up his eyes.
|
||||
//Make the system work for you, not the other way around.
|
||||
//You will be hungry soon, order takeout now.
|
||||
//Be prepared for extra energy.
|
||||
//An unexpected relationship will become permanent.
|
||||
//The love of your life is sitting across from you.
|
||||
//Better be the head of a chicken than the tail of an ox.
|
||||
//To forgive others one more time is to create one more blessing for yourself.
|
||||
//Enjoy yourself while you can.
|
||||
//The ultimate test of a relationship is to disagree but to hold hands.
|
||||
//Excellence is the difference between what I do and what I am capable of.
|
||||
//Do not let what you do not have prevent you from using what you do have.
|
||||
//What ends on hope does not end at all.
|
||||
//People enjoy having you around. Appreciate this.
|
||||
//You are admired for your adventuous ways.
|
||||
//It's never crowded along the extra mile
|
||||
//You are blessed, today is the day to bless others.
|
||||
//The Greatest War Sometimes Isn't On The Battlefield But Against Oneself.
|
||||
//People in your background will be more co-operative than usual.
|
||||
//A good way to stay healthy is to eat more Chinese food.
|
||||
//Anyone who dares to be, can never be weak.
|
||||
//Affirm it, visualize it, believe it, and it`will actualize itself.
|
||||
//The measure of time to your next goal is the measure of your discipline.
|
||||
//Help, I'm prisoner in a Chinese bakery!!!
|
||||
//Take a minute and let it ride, then take a minute to let it breeze.
|
||||
//We are here to love each other, serve each other and uplift each other.
|
||||
//If everybody is a worm you should be a glow worm
|
||||
//To affirm is to make firm.
|
||||
//Remember this: duct tape can fix anything, so don't worry about messing things
|
||||
up.
|
||||
//You broke my cookie!
|
||||
//Failure is not defeat until you stop trying.
|
||||
//The days that make us happy make us wise.
|
||||
//Men do not fail... they give up trying.
|
||||
//Time may fly by. But Memories don't.
|
||||
//You will win success in whatever you adopt.
|
||||
//You will outdistance all your competitors.
|
||||
//You have a great capability to break cookies - use it wisely!
|
||||
//AT TIMES IT IS BETTER TO KNOW WHEN EXIT THAN ENTER
|
||||
//Money will come to you when you are doing the right thing.
|
||||
//When you get something for nothing, you just haven't been billed for it yet.
|
||||
//You will discover your hidden talents.
|
||||
//You'll advance for with your abilities.
|
||||
//When you can't naturally feel upbeat it can sometimes help you to act as if
|
||||
you did.
|
||||
//You will overcome difficult times.
|
||||
//Your problem just became your stepping stone. Catch the moment.
|
||||
//I am a fortune. You just broke my little house. Where will i live now?
|
||||
//The majority of the word can't is can.
|
||||
//The secret of getting ahead is getting started.
|
||||
//Be most affectionate today.
|
||||
//Change your thoughts and you change the world.
|
||||
//Sing and rejoice, fortune is smiling on you.
|
||||
//All the preparation you've done will finally be paying off!
|
||||
//A truly great person never puts away the simplicity of a child.
|
||||
//Customer service is like taking a bath you have to keep doing it.
|
||||
//The expanse of your intelligence is a void no universe could ever fill.
|
||||
//Those grapes you cannot taste are always sour.
|
||||
//An unexpected aquaintance will resurface.
|
||||
//If you want the rainbow, then you have to tolerate the rain.
|
||||
//You don't get harmony when everyone sings the same note.
|
||||
//The race is not always to the swift, but to those who keep on running.
|
||||
//The early bird gets the worm, but the second mouse gets the cheese.
|
||||
//The best things in life aren't things.
|
||||
//Don't bother looking for fault. The reward for finding it is low.
|
||||
//Everything has beauty but not everyone sees it.
|
||||
//Nothing is as good or bad as it appears.
|
||||
//Never cut what you can untie.
|
||||
//Meet your opponent half way. You need the exercise.
|
||||
//Laughter is the shortest distance between two people.
|
||||
//We cannot change the direction of the wind, but we can adjust our sails.
|
||||
//We could learn a lot from crayons: Some of are sharp, some are pretty, some
|
||||
have weird names, and all are different colors. But they all have to learn to
|
||||
live in the same box.
|
||||
//Use your instincts now.
|
||||
//If you take a single step to your journey, you'll succeed; it's not best to
|
||||
fail.
|
||||
//In the eyes of lovers, everything is beautiful.
|
||||
//Warning, do not eat your fortune.
|
||||
//Demonstrate refinement in everything you do.
|
||||
//Impossible standards just make life difficult.
|
||||
//A different world cannot be build by indifferent people.
|
||||
//Q. What is H2O? A. Caring, 2 parts Hug and 1 part Open-mind.
|
||||
//All troubles you have can pass away very quickly.
|
||||
//Integrity is the essense of everything successful.
|
||||
//For true love? Send real roses preserved in 24kt gold!
|
||||
//Sometimes the object of the journey is not the end, but the journey itself.
|
||||
//Fear is just excitement in need of an attitude adjustment.
|
||||
//The food here taste so good, even a cave man likes it.
|
||||
//Perhaps you've been focusing too much on spending.
|
||||
//Happiness isn't something you remember, it's something you experience.
|
||||
//Oops... Wrong cookie.
|
||||
//The dream is within you.
|
||||
//Love is on its way.
|
||||
//Be direct, usually one can accomplish more that way.
|
||||
//Use your talents. That's what they are intended for.
|
||||
//The troubles you have now will pass away quickly.
|
||||
//See the light at the end of the tunnel.
|
||||
//Your dream will come true when you least expect it.
|
||||
//Don't 'face' reality, let it be the place from which you leap.
|
||||
//Fortune smiles upon you today.
|
||||
//Believing is doing.
|
||||
//Your dynamic eyes have attracted a secret admirer.
|
||||
//You know where you are going and how to get there.
|
||||
//Go confidently in the direction of your dreams.
|
||||
//Your ability to pick a winner will bring you success.
|
||||
//Humor usually works at the moment of awkwardness.
|
||||
//A good time to finish up old tasks.
|
||||
//Stop procrastinating - starting tomorrow
|
||||
//Enthusiastic leadership gets you a promotion when you least expect it.
|
||||
//You love Chinese food.
|
||||
//You are far more influential than you think.
|
||||
//Adjust finances, make budgets, to improve your standing.
|
||||
//Happiness is not the absence of conflict, but the ability to cope with it.
|
||||
//An understanding heart warms all that are graced with it's presense.
|
||||
//Your co-workers take pleasure in your great sense of creativity.
|
||||
//You are one of the people who goes places in life.
|
||||
//Others enjoy your company.
|
||||
//When in doubt, let your instincts guide you.
|
||||
//A cheerful message is on its way to you.
|
||||
//A pleasant surprise is in store for you tonight.
|
||||
//you cant go down the right path with out first discovering the path to go down
|
||||
//To courageously shoulder the responsibility of one's mistake is character.
|
||||
//The joyful energy of the day will have a positive affect on you.
|
||||
//You have a strong desire for a home and your family interests come first.
|
||||
//Dogs have owners, cats have staff.
|
||||
//Be patient: in time, even an egg will walk.
|
||||
//You are not a person who can be ignored.
|
||||
//You always know the right times to be assertive or to simply wait.
|
||||
//Reading to the mind is what exercise is to the body.
|
||||
//Eat something you never tried before.
|
||||
//Your life becomes more and more of an adventure!
|
||||
//You need to live authentically, and you can't ignore that.
|
||||
//Make all you can, save all you can, give all you can.
|
||||
//A well-aimed spear is worth three.
|
||||
//To build a better world, start in your community.
|
||||
//When you can't naturally feel upbeat, it can sometimes help to act a if you
|
||||
did.
|
||||
//May you have great luck.
|
||||
//A kind word will keep someone warm for years.
|
||||
//Nothing in the world is accomplished without passion.
|
||||
//Human invented language to satisfy the need to complain.
|
||||
//Accept what comes to you each day.
|
||||
//A small lucky package is on its way to you soon.
|
||||
//In human endeavor, chance favors the prepared mind.
|
||||
//Do not upset the penguin today.
|
||||
//Don't cry.
|
||||
//The best way to give credit is to give it away.
|
||||
//Anything you do, do it well. The last thing you want is to be sorry for what
|
||||
you didn't do.
|
||||
//It takes more then good memory to have good memories.
|
||||
//Grant yourself a wish this year only you can do it.
|
||||
//love thy neighbour, just don't get caught
|
||||
//You will be selected for a promotion because of your accomplishments.
|
||||
//There are many new opportunities that are being presented to you.
|
||||
//You will inherit a large sum of money.
|
||||
//You will recieve a gift from someone that cares about you.
|
||||
//You are not illiterate.
|
||||
//Love because it is the only true adventure.
|
||||
//You are contemplating some action which will bring credit upon you
|
||||
//Keep true to the dreams of your youth.
|
||||
//Treasure what you have.
|
||||
//The greatest precept is continual awareness.
|
||||
//A new friend helps you break out of an old routine.
|
||||
//I have a dream.... Time to go to bed.
|
||||
//Your skill will accomplish what the force of many cannot.
|
||||
//You will soon be surrounded by good friends and laughter.
|
||||
//The best is yet to come.
|
||||
//It is better to be the hammer then the anvil.
|
||||
//He who climbs a ladder must begin at the first step.
|
||||
//Action speaks nothing, without the Motive.
|
||||
//Give yourself some peace and quiet for at least a few hours.
|
||||
//Live each day well and wisely
|
||||
//Old dreams never die they just get filed away.
|
||||
//You can fix it with a little extra energy and a positive attitude.
|
||||
//Life is a verb
|
||||
//A man without aim is like a clock without hands, as useless if it turns as if
|
||||
it stands.
|
||||
//Many folks are about as happy as they make up their minds to be.
|
||||
//It's kind of fun to do the impossible
|
||||
//Wow! A secret message from you teeth!
|
||||
//You should be able to make money and hold on to it.
|
||||
//The human spirit is stronger than anything that can happen to it.
|
||||
//Your succeess will astonish everyone.
|
||||
//It is better to have a hen tomorrow than an egg today.
|
||||
//Judge each day not by the harvest you reap but by the seeds you plant.
|
||||
//You like Chinese food.
|
||||
//Your hard work will get payoff today.
|
||||
//Today is the tomorrow we worried about yesterday
|
||||
//There are no shortcuts to any place worth going
|
||||
//No matter what your past has been, you have a spotless future.
|
||||
//Your secret desire to completely change your life will manifest.
|
||||
//Soon you will be sitting on top of the world.
|
||||
//You are never selfish with your advice or your help.
|
||||
//A thrilling time is in store for you.
|
||||
//It's tough to be fascinating.
|
||||
//Soon life will become more interesting
|
||||
//Luck sometimes visits a fool, but it never sits down with him.
|
||||
//Keep your plans secret for now.
|
||||
//Aren't you glad you just had a great meal?
|
||||
//Traveling this year will bring your life into greater perspective.
|
||||
//Only talent people get help from others.
|
||||
//Constant grinding can turn an iron nod into a needle.
|
||||
//You will be successful in your work
|
||||
//you will spend old age in confort and material wealth
|
||||
//When you're about to turn your heart into a stone remember: you do not walk
|
||||
alone.
|
||||
//I am a bad luck person since I was born
|
||||
//You are vigorous in words and action.
|
||||
//The one who snores will always fall asleep first.
|
||||
//An alien of some sort will be appearing to you shortly!
|
||||
//Rest is a good thing, but boredom is its brother.
|
||||
//Do not be overly judgemental of your loved one's intentions or actions.
|
||||
//Think of how you can assist on a problem, not who to blame.
|
||||
//The life of every woman or man - the heart of it - is pure and holy joy.
|
||||
//Take it easy
|
||||
//Trust your intuition. The universe is guiding your life.
|
||||
//Use your head, but live in your heart.
|
||||
//Don't find fault, find a remedy
|
||||
//It may be those who do most, dream most
|
||||
//Your passions sweep you away.
|
||||
//Listen to yourself more often
|
||||
//Think of mother's exhortations more.
|
||||
//The gambler is like the fisherman both have beginners luck.
|
||||
//You are given the chance to take part in an exciting adventure.
|
||||
//The simplest answer is to act.
|
||||
//You will always be surrounded by true friends.
|
||||
//Keep your feet on the ground even though friends flatter you.
|
||||
//You are the man of righteousness and integrity.
|
||||
//He who seeks will find.
|
||||
//The smart thing to do is to begin trusting your intuitions.
|
||||
//Your many hidden talents will become obvious to those around you.
|
||||
//Pick a path with heart.
|
||||
//The human spirit is stronger then anything that can happen to it.
|
||||
//It takes more than good memory to have good memories.
|
||||
//Face facts with dignity.
|
||||
//Be calm when confronting an emergency crisis.
|
||||
//Do you believe? Endurance and persistence will be rewarded.
|
||||
//A new wardrobe brings great joy and change in your life.
|
||||
//Everyone agrees you are the best.
|
||||
//A new outlook brightens your image and brings new friends.
|
||||
//Everything will now come your way.
|
||||
//You will be called to fill a position of high honor and responsibility.
|
||||
//The eyes believe themselves; the ears believe other people.
|
||||
//Good beginning is half done.
|
||||
//Some pursue happiness; you create it.
|
||||
//It's the worst of times, you need to summon your optimism.
|
||||
//You are cautious in showing your true self to others.
|
||||
//Your ability to accomplish tasks will follow with success.
|
||||
//We all have extraordinary coded within us, waiting to be released.
|
||||
//You will have a bright future.
|
||||
//Compassion is a way of being.
|
||||
//You will always have good luck in your personal affairs.
|
||||
//The pleasure of what we enjoy is lost by wanting more
|
||||
//Did you remember to order your take out also?
|
||||
//Perhaps you've been focusing too much on that one thing..
|
||||
//Right now there's an energy pushing you in a new direction.
|
||||
//Everybody feels lucky for having you as a friend.
|
||||
//When the moment comes, take the top one.
|
||||
//Sometimes travel to new places leads to great transformation.
|
||||
//There is always a way - if you are committed.
|
||||
//Life is too short to waste time hating anyone.
|
||||
//All the world may not love a lover but they will be watching him.
|
||||
//Don't just spend time, invest it.
|
||||
//Life always gets harder near the summit.
|
||||
//Take the chance while you still have the choice.
|
||||
//It is much easier to be cirtical than to be correct.
|
||||
//Enjoy life! It is better to be happy than wise.
|
||||
//To make the cart go, you must grease the wheels.
|
||||
//You are contemplating some action which will bring credit upon you.
|
||||
//Before you wonder Am I doing things right, ask Am I doing the right things?
|
||||
//You may be disappointed if you fail, but you are doomed if you don't try.
|
||||
//You will always get what you want through your charm and personality.
|
||||
//The big issues are work, career, or status right now.
|
||||
//Your emotional currents are flowing powerfully now.
|
||||
//Any decision you have to make tomorrow is a good decsion.
|
||||
//Consume less. Share more. Enjoy life.
|
||||
//The secret of staying young is good health and lying about your age.
|
||||
//Spring has sprung. Life is blooming.
|
||||
//Go ask your mom.
|
||||
//The possibility of a career change is near.
|
||||
//The important thing is to never stop questioning.
|
||||
//Compassion will cure more then condemnation.
|
||||
//Excuses are easy to manufacture, and hard to sell.
|
||||
//Put your mind into planning today. Look into the future.
|
||||
//Listen to life, and you will hear the voice of life crying, Be!
|
||||
//Broke is only temporaryl poor is a state of mind.
|
||||
//Here we go. Moo Shu Cereal for breakfast with duck sauce.
|
||||
//Teamwork: the fuel that allows common people attain uncommon results.
|
||||
//Hard words break no bones, fine words butter no parsnips.
|
||||
//We cannot direct the wind but we can adjust the sails.
|
||||
//You are offered the dream of a lifetime. Say yes!
|
||||
//Working out the kinks today will make for a better tomorrow.
|
||||
//You have a curious smile and a mysterious nature.
|
||||
//Questions provide the key to unlocking our unlimited potential.
|
||||
//You will enjoy razon-sharp spiritual vision today.
|
||||
//The wise are aware of their treasure, while fools follow their vanity
|
||||
//Well-arranged time is the surest sign of a well-arranged mind.
|
||||
//Never bring unhappy feelings into your home.
|
||||
//This is really a lovely day. Congratulations!
|
||||
//Bad luck and ill misfortune will infest your pathetic soul for all eternity.
|
||||
//A golden egg of opportunity falls into your lap this month.
|
||||
//You are very grateful for the small pleasures of life.
|
||||
//today you should be a passenger. Stay close to a driver for a day.
|
||||
//For hate is never conquered by hate. Hate is conquered by love.
|
||||
//Service is the rent we pay for the privilege of living on this planet.
|
||||
//Good clothes open many doors. Go shopping.
|
||||
//The leader seeks to communicate his vision to his followers.
|
||||
//Great works are performed not by strength, but by perseverance.
|
||||
//People who are late are often happier than those who have to wait for them
|
||||
//Present your best ideas today to an eager and welcoming audience.
|
||||
//Friends long absent are coming back to you.
|
||||
//The time is right to make new friends.
|
||||
//Life to you is a dashing and bold adventure
|
||||
//You may be hungry soon: order a takeout now.
|
||||
//Do not hesitate to look for help, an extra hand should always be welcomed.
|
||||
//How can you have a beautiful ending without making beautiful mistakes?
|
||||
//Humor is an affirmation of dignity
|
||||
//He who climbs a ladder must begin at the first step
|
||||
//What's vice today may be virtue tomorow.
|
||||
//You have an unusually magnetic personality.
|
||||
//You will travel to many places.
|
||||
//Accept yourself
|
||||
//Be a generous friend and a fair enemy
|
||||
//Never quit!
|
||||
//Old friends, old wines and old gold are best
|
||||
//If your desires are not extravagant, they will be granted
|
||||
//Every Friend Joys in your Success
|
||||
//You should be able to undertake and complete anything
|
||||
//You will enjoy good health, you will be surrounded by luxury
|
||||
//You are a person of strong sense of duty
|
||||
//Dream lofty dreams, and as you dream, so shall you become.
|
||||
//You have a quiet and unobtrusive nature.
|
||||
//Great thoughts come from the heart.
|
||||
//You love peace
|
||||
//Judge not according to the appearance.
|
||||
//One who admires you greatly is hidden before your eyes.
|
||||
//Traveling more often is important for your health and happiness.
|
||||
//You will be sharing great news with all people you love
|
||||
//You have a reputation for being straightforward and honest.
|
||||
//You are always welcome in any gathering.
|
||||
//You will be traveling and coming into a fortune.
|
||||
//Open up your heart - it can always be closed again.
|
||||
//Being happy is not always being perfect.
|
||||
//Next time you have the opportunity, go on a rollercoaster.
|
||||
//Try everything once, even the things you don't think you will like.
|
||||
//Life is too short to hold grudges.
|
||||
//Dream your dream and your dream will dream of you.
|
||||
//Being alone and being lonely are two different things.
|
||||
//Don't worry about things in the past, there is nothing you can do about them
|
||||
now. Don't worry about things that are happening now, make the best of a bad
|
||||
situation. Don't worry about things in the future, they may never happen.
|
||||
//Tomorrow, take a moment to do something just for yourself.
|
||||
//Someone close to you is waiting for you to call.
|
||||
//A virtual fortune cookie will not satisfy your hunger like that of a home made
|
||||
one.
|
||||
//Smile. Tomorrow is another day.
|
||||
//You can never been certain of success, but you can be certain of failure if
|
||||
you never try.
|
||||
//It takes ten times as many muscles to frown as it does to smile.
|
||||
//Shoot for the moon! If you miss you will still be amongst the stars.
|
||||
//Keep your eyes open. You never know what you might see.
|
||||
//Tell them what you really think. Otherwise, nothing will change.
|
||||
//Let your heart make your decisions - it does not get as confused as your head.
|
||||
//Working hard will make you live a happy life.
|
||||
//A pleasant surprise is waiting for you.
|
||||
QUOTES
|
||||
);
|
||||
|
||||
$i = round(fmod(hexdec(hash('crc32', $seed)), count($quotes)), 0);
|
||||
return trim(str_replace(array("\r\n", "\n", "\r"), ' ', $quotes[$i]));
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@ class OpenClassroomsBridge extends BridgeAbstract {
|
||||
'u' => array(
|
||||
'name' => 'Catégorie',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Arts & Culture' => 'arts',
|
||||
'Code' => 'code',
|
||||
|
64
bridges/OsmAndBlogBridge.php
Normal file
64
bridges/OsmAndBlogBridge.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
class OsmAndBlogBridge extends BridgeAbstract {
|
||||
const NAME = 'OsmAnd Blog';
|
||||
const URI = 'https://osmand.net/';
|
||||
const DESCRIPTION = 'Get the latest news from OsmAnd.net';
|
||||
const MAINTAINER = 'fulmeek';
|
||||
|
||||
public function collectData() {
|
||||
$html = getSimpleHTMLDOM(self::URI . 'blog')
|
||||
or returnServerError('Could not load content');
|
||||
|
||||
foreach($html->find('div.article') as $element) {
|
||||
$item = array();
|
||||
|
||||
$objTitle = $element->find('h1', 0);
|
||||
if (!$objTitle)
|
||||
$objTitle = $element->find('h2', 0);
|
||||
if (!$objTitle)
|
||||
$objTitle = $element->find('h3', 0);
|
||||
if ($objTitle)
|
||||
$item['title'] = $objTitle->plaintext;
|
||||
|
||||
$objDate = $element->find('meta[pubdate]', 0);
|
||||
if ($objDate) {
|
||||
$item['timestamp'] = strtotime($objDate->pubdate);
|
||||
} else {
|
||||
$objDate = $element->find('.date', 0);
|
||||
if ($objDate)
|
||||
$item['timestamp'] = strtotime($objDate->plaintext);
|
||||
}
|
||||
|
||||
$this->cleanupContent($element, $objTitle, $objDate, $element->find('.date', 0));
|
||||
$item['content'] = $element->innertext;
|
||||
|
||||
$objLink = $html->find('.articlelinklist a', 0);
|
||||
if ($objLink) {
|
||||
$item['uri'] = $this->filterURL($objLink->href);
|
||||
} else {
|
||||
$item['uri'] = 'urn:sha1:' . hash('sha1', $item['content']);
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function filterURL($url) {
|
||||
if (strpos($url, '://') === false)
|
||||
return self::URI . ltrim($url, '/');
|
||||
return $url;
|
||||
}
|
||||
|
||||
private function cleanupContent($content, ...$removeItems) {
|
||||
foreach ($removeItems as $obj) {
|
||||
if ($obj) $obj->outertext = '';
|
||||
}
|
||||
foreach ($content->find('img') as $obj) {
|
||||
$obj->src = $this->filterURL($obj->src);
|
||||
}
|
||||
foreach ($content->find('a') as $obj) {
|
||||
$obj->href = $this->filterURL($obj->href);
|
||||
$obj->target = '_blank';
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,6 @@ class PixivBridge extends BridgeAbstract {
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getContents(static::URI . 'search.php?word=' . urlencode($this->getInput('tag')))
|
||||
@@ -70,5 +69,4 @@ class PixivBridge extends BridgeAbstract {
|
||||
return 'cache/pixiv_img/' . $illustId . '.jpeg';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
106
bridges/RoadAndTrackBridge.php
Normal file
106
bridges/RoadAndTrackBridge.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
class RoadAndTrackBridge extends BridgeAbstract {
|
||||
const MAINTAINER = 'teromene';
|
||||
const NAME = 'Road And Track Bridge';
|
||||
const URI = 'https://www.roadandtrack.com/';
|
||||
const CACHE_TIMEOUT = 86400; // 24h
|
||||
const DESCRIPTION = 'Returns the latest news from Road & Track.';
|
||||
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'new-cars' => array(
|
||||
'name' => 'New Cars',
|
||||
'type' => 'checkbox',
|
||||
'exampleValue' => 'checked',
|
||||
'title' => 'Activate to load New Cars articles'
|
||||
),
|
||||
'motorsports' => array(
|
||||
'name' => 'Motorsports',
|
||||
'type' => 'checkbox',
|
||||
'exampleValue' => 'checked',
|
||||
'title' => 'Activate to load Motorsports articles'
|
||||
),
|
||||
'car-culture' => array(
|
||||
'name' => 'Car Culture',
|
||||
'type' => 'checkbox',
|
||||
'exampleValue' => 'checked',
|
||||
'title' => 'Activate to load Car Culture articles'
|
||||
),
|
||||
'car-shows' => array(
|
||||
'name' => 'Car shows',
|
||||
'type' => 'checkbox',
|
||||
'exampleValue' => 'checked',
|
||||
'title' => 'Activate to load Car shows articles'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const SIG_URL = 'https://cloud.mazdigital.com/feeds/production/comboapp/204/api/v3/';
|
||||
|
||||
public function collectData() {
|
||||
|
||||
//Magic
|
||||
$signVal = '?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9jbG91ZC5tYXpkaWd';
|
||||
$signVal .= 'pdGFsLmNvbS9mZWVkcy9wcm9kdWN0aW9uL2NvbWJvYXBwLzIwNC8qIiwiQ29uZGl0aW9uIj';
|
||||
$signVal .= 'p7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNTUyNTU5MDUzfSwiSXBBZGRyZ';
|
||||
$signVal .= 'XNzIjp7IkFXUzpTb3VyY2VJcCI6IjAuMC4wLjAvMCJ9fX1dfQ__&Signature=jgS~Jccjs';
|
||||
$signVal .= 'lXMMywWesmwDpUbHvEmrADRP7iBRzT~OiP-O~zI-8TtQzqTP7GUrpB9~v69CvhO7-JVtw94';
|
||||
$signVal .= 'VC3N6lQrwsxTTIhpS57YGeV~MbZx~P653yUV7jb3jpJE2yUawfXnEkD-XzOIn8-caMo~14i';
|
||||
$signVal .= 'KuWV9KNDkTJaRgOMy0rrVpWqiuBjCu5s5B8Ylt2qwcpOvHjXSqG9IY5c7GUIXKsk8yXzGFi';
|
||||
$signVal .= 'yzy8hfuGgdx0n7fgl7c4-EoDgQaz~U76g0epejPxV5Csj16rCCfAqBU5kZJnACZ1vvOvRcV';
|
||||
$signVal .= 'Wiu8KUuUuCS04SPmJ73Y5XoY8~uXRScxZG1kAFTIAhT4nYVlg__&Key-Pair-Id=APKAIZB';
|
||||
$signVal .= 'QNNSW4WGIFP4Q';
|
||||
|
||||
$newsElements = array();
|
||||
if($this->getInput('new-cars')) {
|
||||
$newsElements = array_merge($newsElements,
|
||||
json_decode(getContents(self::SIG_URL . '7591/item_feed' . $signVal))
|
||||
);
|
||||
}
|
||||
if($this->getInput('motorsports')) {
|
||||
$newsElements = array_merge($newsElements,
|
||||
json_decode(getContents(self::SIG_URL . '7590/item_feed' . $signVal))
|
||||
);
|
||||
}
|
||||
if($this->getInput('car-culture')) {
|
||||
$newsElements = array_merge($newsElements,
|
||||
json_decode(getContents(self::SIG_URL . '7588/item_feed' . $signVal))
|
||||
);
|
||||
}
|
||||
if($this->getInput('car-shows')) {
|
||||
$newsElements = array_merge($newsElements,
|
||||
json_decode(getContents(self::SIG_URL . '7589/item_feed' . $signVal))
|
||||
);
|
||||
}
|
||||
|
||||
usort($newsElements, function($a, $b) {
|
||||
return $b->published - $a->published;
|
||||
});
|
||||
|
||||
$limit = 19;
|
||||
foreach($newsElements as $element) {
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $element->sourceUrl;
|
||||
$item['timestamp'] = $element->published;
|
||||
$item['enclosures'] = array($element->cover->url);
|
||||
$item['title'] = $element->title;
|
||||
$item['content'] = $this->getArticleContent($element);
|
||||
$this->items[] = $item;
|
||||
|
||||
if($limit > 0) {
|
||||
$limit--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getArticleContent($article) {
|
||||
|
||||
return getContents($article->contentUrl);
|
||||
|
||||
}
|
||||
}
|
@@ -6,7 +6,6 @@ class Rue89Bridge extends BridgeAbstract {
|
||||
const URI = 'https://www.nouvelobs.com/rue89/';
|
||||
const DESCRIPTION = 'Returns the newest posts from Rue89';
|
||||
|
||||
|
||||
public function collectData() {
|
||||
|
||||
$jsonArticles = getContents('https://appdata.nouvelobs.com/rue89/feed.json')
|
||||
@@ -46,5 +45,4 @@ class Rue89Bridge extends BridgeAbstract {
|
||||
return $item;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -35,5 +35,4 @@ class Shimmie2Bridge extends DanbooruBridge {
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ class SkimfeedBridge extends BridgeAbstract {
|
||||
'box_channel' => array(
|
||||
'name' => 'Channel',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your channel',
|
||||
'values' => array(
|
||||
'Hacker News' => '/news/hacker-news.html',
|
||||
@@ -68,7 +67,6 @@ class SkimfeedBridge extends BridgeAbstract {
|
||||
'tech_channel' => array(
|
||||
'name' => 'Tech channel',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your tech channel',
|
||||
'values' => array(
|
||||
'Agg' => array(
|
||||
@@ -804,7 +802,6 @@ EOD;
|
||||
EOD;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the reported skimfeed version is compatible
|
||||
*/
|
||||
@@ -821,5 +818,4 @@ EOD;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ class SoundCloudBridge extends BridgeAbstract {
|
||||
)
|
||||
));
|
||||
|
||||
const CLIENT_ID = '4jkoEFmZEDaqjwJ9Eih4ATNhcH3vMVfp';
|
||||
const CLIENT_ID = 'W0KEWWILAjDiRH89X0jpwzuq6rbSK08R';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
@@ -32,7 +32,8 @@ class SoundCloudBridge extends BridgeAbstract {
|
||||
. self::CLIENT_ID
|
||||
)) or returnServerError('No results for this user');
|
||||
|
||||
for($i = 0; $i < 10; $i++) {
|
||||
$numTracks = min(count($tracks), 10);
|
||||
for($i = 0; $i < $numTracks; $i++) {
|
||||
$item = array();
|
||||
$item['author'] = $tracks[$i]->user->username;
|
||||
$item['title'] = $tracks[$i]->user->username . ' - ' . $tracks[$i]->title;
|
||||
@@ -54,6 +55,7 @@ class SoundCloudBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return self::NAME . ' - ' . $this->getInput('u');
|
||||
|
@@ -57,5 +57,4 @@ class SupInfoBridge extends BridgeAbstract {
|
||||
return $item;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -16,13 +16,13 @@ class TheHackerNewsBridge extends BridgeAbstract {
|
||||
if($limit < 5) {
|
||||
|
||||
$article_url = $element->find('a.story-link', 0)->href;
|
||||
$article_author = trim($element->find('i.fa-user', 0)->parent()->plaintext);
|
||||
$article_author = trim($element->find('i.icon-user', 0)->parent()->plaintext);
|
||||
$article_title = $element->find('h2.home-title', 0)->plaintext;
|
||||
|
||||
//Date without time
|
||||
$article_timestamp = strtotime(
|
||||
extractFromDelimiters(
|
||||
$element->find('i.fa-calendar', 0)->parent()->outertext,
|
||||
$element->find('i.icon-calendar', 0)->parent()->outertext,
|
||||
'</i>',
|
||||
'<span>'
|
||||
)
|
||||
|
@@ -112,8 +112,7 @@ class ThingiverseBridge extends BridgeAbstract {
|
||||
'3D Printer Parts' => '128',
|
||||
'3D Printers' => '126',
|
||||
'3D Printing Tests' => '129',
|
||||
),
|
||||
'defaultValue' => ''
|
||||
)
|
||||
),
|
||||
'showimage' => array(
|
||||
'name' => 'Show image in content',
|
||||
@@ -163,5 +162,4 @@ class ThingiverseBridge extends BridgeAbstract {
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
}
|
||||
|
687
bridges/TrelloBridge.php
Normal file
687
bridges/TrelloBridge.php
Normal file
@@ -0,0 +1,687 @@
|
||||
<?php
|
||||
class TrelloBridge extends BridgeAbstract {
|
||||
const NAME = 'Trello Bridge';
|
||||
const URI = 'https://trello.com/';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = 'Returns activity on Trello boards or cards';
|
||||
const MAINTAINER = 'Roliga';
|
||||
const PARAMETERS = array(
|
||||
'Board' => array(
|
||||
'b' => array(
|
||||
'name' => 'Board ID',
|
||||
'required' => true,
|
||||
'exampleValue' => 'g9mdhdzg',
|
||||
'title' => 'Taken from Trello URL, e.g. trello.com/b/[Board ID]'
|
||||
)
|
||||
),
|
||||
'Card' => array(
|
||||
'c' => array(
|
||||
'name' => 'Card ID',
|
||||
'required' => true,
|
||||
'exampleValue' => '8vddc9pE',
|
||||
'title' => 'Taken from Trello URL, e.g. trello.com/c/[Card ID]'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
* This was extracted from webpack on a Trello page, e.g. trello.com/b/g9mdhdzg
|
||||
* In the browser's inspector/debugger go to the Debugger (Firefox) or
|
||||
* Sources (Chromium) tab, these values can be found at:
|
||||
* webpack:///resources/strings/actions/en.json
|
||||
*/
|
||||
const ACTION_TEXTS = array(
|
||||
'action_accept_enterprise_join_request'
|
||||
=> '{memberCreator} added team {organization} to the enterprise {enterprise}',
|
||||
'action_add_attachment_to_card'
|
||||
=> '{memberCreator} attached {attachment} to {card} {attachmentPreview}',
|
||||
'action_add_attachment_to_card@card'
|
||||
=> '{memberCreator} attached {attachment} to this card {attachmentPreview}',
|
||||
'action_add_checklist_to_card'
|
||||
=> '{memberCreator} added {checklist} to {card}',
|
||||
'action_add_checklist_to_card@card'
|
||||
=> '{memberCreator} added {checklist} to this card',
|
||||
'action_add_label_to_card'
|
||||
=> '{memberCreator} added the {label} label to {card}',
|
||||
'action_add_label_to_card@card'
|
||||
=> '{memberCreator} added the {label} label to this card',
|
||||
'action_add_organization_to_enterprise'
|
||||
=> '{memberCreator} added team {organization} to the enterprise {enterprise}',
|
||||
'action_add_to_organization_board'
|
||||
=> '{memberCreator} added {board} to {organization}',
|
||||
'action_add_to_organization_board@board'
|
||||
=> '{memberCreator} added this board to {organization}',
|
||||
'action_added_a_due_date'
|
||||
=> '{memberCreator} set {card} to be due {date}',
|
||||
'action_added_a_due_date@card'
|
||||
=> '{memberCreator} set this card to be due {date}',
|
||||
'action_added_list_to_board'
|
||||
=> '{memberCreator} added list {list} to {board}',
|
||||
'action_added_list_to_board@board'
|
||||
=> '{memberCreator} added {list} to this board',
|
||||
'action_added_member_to_board'
|
||||
=> '{memberCreator} added {member} to {board}',
|
||||
'action_added_member_to_board@board'
|
||||
=> '{memberCreator} added {member} to this board',
|
||||
'action_added_member_to_board_as_admin'
|
||||
=> '{memberCreator} added {member} to {board} as an admin',
|
||||
'action_added_member_to_board_as_admin@board'
|
||||
=> '{memberCreator} added {member} to this board as an admin',
|
||||
'action_added_member_to_board_as_observer'
|
||||
=> '{memberCreator} added {member} to {board} as an observer',
|
||||
'action_added_member_to_board_as_observer@board'
|
||||
=> '{memberCreator} added {member} to this board as an observer',
|
||||
'action_added_member_to_card'
|
||||
=> '{memberCreator} added {member} to {card}',
|
||||
'action_added_member_to_card@card'
|
||||
=> '{memberCreator} added {member} to this card',
|
||||
'action_added_member_to_organization'
|
||||
=> '{memberCreator} added {member} to {organization}',
|
||||
'action_added_member_to_organization_as_admin'
|
||||
=> '{memberCreator} added {member} to {organization} as an admin',
|
||||
'action_admins_visibility'
|
||||
=> 'its admins',
|
||||
'action_another_board'
|
||||
=> 'another board',
|
||||
'action_archived_card'
|
||||
=> '{memberCreator} archived {card}',
|
||||
'action_archived_card@card'
|
||||
=> '{memberCreator} archived this card',
|
||||
'action_archived_list'
|
||||
=> '{memberCreator} archived list {list}',
|
||||
'action_became_a_normal_user_in_organization'
|
||||
=> '{memberCreator} became a normal user in {organization}',
|
||||
'action_became_a_normal_user_on'
|
||||
=> '{memberCreator} became a normal user on {board}',
|
||||
'action_became_a_normal_user_on@board'
|
||||
=> '{memberCreator} became a normal user on this board',
|
||||
'action_became_an_admin_of_organization'
|
||||
=> '{memberCreator} became an admin of {organization}',
|
||||
'action_board_perm_level'
|
||||
=> '{memberCreator} made {board} visible to {level}',
|
||||
'action_board_perm_level@board'
|
||||
=> '{memberCreator} made this board visible to {level}',
|
||||
'action_calendar'
|
||||
=> 'calendar',
|
||||
'action_cardAging'
|
||||
=> 'card aging',
|
||||
'action_changed_a_due_date'
|
||||
=> '{memberCreator} changed the due date of {card} to {date}',
|
||||
'action_changed_a_due_date@card'
|
||||
=> '{memberCreator} changed the due date of this card to {date}',
|
||||
'action_changed_board_background'
|
||||
=> '{memberCreator} changed the background of {board}',
|
||||
'action_changed_board_background@board'
|
||||
=> '{memberCreator} changed the background of this board',
|
||||
'action_changed_description_of_card'
|
||||
=> '{memberCreator} changed description of {card}',
|
||||
'action_changed_description_of_card@card'
|
||||
=> '{memberCreator} changed description of this card',
|
||||
'action_changed_description_of_organization'
|
||||
=> '{memberCreator} changed description of {organization}',
|
||||
'action_changed_display_name_of_organization'
|
||||
=> '{memberCreator} changed display name of {organization}',
|
||||
'action_changed_name_of_organization'
|
||||
=> '{memberCreator} changed name of {organization}',
|
||||
'action_changed_website_of_organization'
|
||||
=> '{memberCreator} changed website of {organization}',
|
||||
'action_closed_board'
|
||||
=> '{memberCreator} closed {board}',
|
||||
'action_closed_board@board'
|
||||
=> '{memberCreator} closed this board',
|
||||
'action_comment_on_card'
|
||||
=> '{memberCreator} {contextOn} {card} {comment}',
|
||||
'action_comment_on_card@card'
|
||||
=> '{memberCreator} {comment}',
|
||||
'action_completed_checkitem'
|
||||
=> '{memberCreator} completed {checkitem} on {card}',
|
||||
'action_completed_checkitem@card'
|
||||
=> '{memberCreator} completed {checkitem} on this card',
|
||||
'action_convert_to_card_from_checkitem'
|
||||
=> '{memberCreator} converted {card} from a checklist item on {cardSource}',
|
||||
'action_convert_to_card_from_checkitem@card'
|
||||
=> '{memberCreator} converted this card from a checklist item on {cardSource}',
|
||||
'action_convert_to_card_from_checkitem@cardSource'
|
||||
=> '{memberCreator} converted {card} from a checklist item on this card',
|
||||
'action_copy_board'
|
||||
=> '{memberCreator} copied this board from {board}',
|
||||
'action_copy_card'
|
||||
=> '{memberCreator} copied {card} from {cardSource} in list {list}',
|
||||
'action_copy_card@card'
|
||||
=> '{memberCreator} copied this card from {cardSource} in list {list}',
|
||||
'action_copy_comment_from_card'
|
||||
=> '{memberCreator} copied comment by {member} from card {card} {comment}',
|
||||
'action_create_board'
|
||||
=> '{memberCreator} created {board}',
|
||||
'action_create_board@board'
|
||||
=> '{memberCreator} created this board',
|
||||
'action_create_card'
|
||||
=> '{memberCreator} added {card} to {list}',
|
||||
'action_create_card@card'
|
||||
=> '{memberCreator} added this card to {list}',
|
||||
'action_create_custom_field'
|
||||
=> '{memberCreator} created the {customField} custom field on {board}',
|
||||
'action_create_custom_field@board'
|
||||
=> '{memberCreator} created the {customField} custom field on this board',
|
||||
'action_create_enterprise_join_request'
|
||||
=> '{memberCreator} requested to add team {organization} to the enterprise {enterprise}',
|
||||
'action_created_an_invitation_to_board'
|
||||
=> '{memberCreator} created an invitation to {board}',
|
||||
'action_created_an_invitation_to_board@board'
|
||||
=> '{memberCreator} created an invitation to this board',
|
||||
'action_created_an_invitation_to_organization'
|
||||
=> '{memberCreator} created an invitation to {organization}',
|
||||
'action_created_checklist_on_board'
|
||||
=> '{memberCreator} created {checklist} on {board}',
|
||||
'action_created_checklist_on_board@board'
|
||||
=> '{memberCreator} created {checklist} on this board',
|
||||
'action_created_organization'
|
||||
=> '{memberCreator} created {organization}',
|
||||
'action_decline_enterprise_join_request'
|
||||
=> '{memberCreator} declined the request to add team {organization} to the enterprise {enterprise}',
|
||||
'action_delete_attachment_from_card'
|
||||
=> '{memberCreator} deleted the {attachment} attachment from {card}',
|
||||
'action_delete_attachment_from_card@card'
|
||||
=> '{memberCreator} deleted the {attachment} attachment from this card',
|
||||
'action_delete_card'
|
||||
=> '{memberCreator} deleted card #{idCard} from {list}',
|
||||
'action_delete_custom_field'
|
||||
=> '{memberCreator} deleted the {customField} custom field from {board}',
|
||||
'action_delete_custom_field@board'
|
||||
=> '{memberCreator} deleted the {customField} custom field from this board',
|
||||
'action_deleted_account'
|
||||
=> '[deleted account]',
|
||||
'action_deleted_an_invitation_to_board'
|
||||
=> '{memberCreator} deleted an invitation to {board}',
|
||||
'action_deleted_an_invitation_to_board@board'
|
||||
=> '{memberCreator} deleted an invitation to this board',
|
||||
'action_deleted_an_invitation_to_organization'
|
||||
=> '{memberCreator} deleted an invitation to {organization}',
|
||||
'action_deleted_checkitem'
|
||||
=> '{memberCreator} deleted task {checkitem} on {checklist}',
|
||||
'action_disabled_calendar_feed'
|
||||
=> '{memberCreator} disabled the iCalendar feed on {board}',
|
||||
'action_disabled_calendar_feed@board'
|
||||
=> '{memberCreator} disabled the iCalendar feed on this board',
|
||||
'action_disabled_card_covers'
|
||||
=> '{memberCreator} disabled card cover images on {board}',
|
||||
'action_disabled_card_covers@board'
|
||||
=> '{memberCreator} disabled card cover images on this board',
|
||||
'action_disabled_commenting'
|
||||
=> '{memberCreator} disabled commenting on {board}',
|
||||
'action_disabled_commenting@board'
|
||||
=> '{memberCreator} disabled commenting on this board',
|
||||
'action_disabled_inviting'
|
||||
=> '{memberCreator} disabled inviting on {board}',
|
||||
'action_disabled_inviting@board'
|
||||
=> '{memberCreator} disabled inviting on this board',
|
||||
'action_disabled_plugin'
|
||||
=> '{memberCreator} disabled the {plugin} Power-Up',
|
||||
'action_disabled_powerup'
|
||||
=> '{memberCreator} disabled the {powerup} Power-Up',
|
||||
'action_disabled_self_join'
|
||||
=> '{memberCreator} disabled self join on {board}',
|
||||
'action_disabled_self_join@board'
|
||||
=> '{memberCreator} disabled self join on this board',
|
||||
'action_disabled_voting'
|
||||
=> '{memberCreator} disabled voting on {board}',
|
||||
'action_disabled_voting@board'
|
||||
=> '{memberCreator} disabled voting on this board',
|
||||
'action_due_date_change'
|
||||
=> '{memberCreator}',
|
||||
'action_email_card'
|
||||
=> '{memberCreator} emailed {card} to {list}',
|
||||
'action_email_card@card'
|
||||
=> '{memberCreator} emailed this card to {list}',
|
||||
'action_email_card_from'
|
||||
=> '{memberCreator} emailed {card} to {list} from {from}',
|
||||
'action_email_card_from@card'
|
||||
=> '{memberCreator} emailed this card to {list} from {from}',
|
||||
'action_enabled_calendar_feed'
|
||||
=> '{memberCreator} enabled the iCalendar feed on {board}',
|
||||
'action_enabled_calendar_feed@board'
|
||||
=> '{memberCreator} enabled the iCalendar feed on this board',
|
||||
'action_enabled_card_covers'
|
||||
=> '{memberCreator} enabled card cover images on {board}',
|
||||
'action_enabled_card_covers@board'
|
||||
=> '{memberCreator} enabled card cover images on this board',
|
||||
'action_enabled_plugin'
|
||||
=> '{memberCreator} enabled the {plugin} Power-Up',
|
||||
'action_enabled_powerup'
|
||||
=> '{memberCreator} enabled the {powerup} Power-Up',
|
||||
'action_enabled_self_join'
|
||||
=> '{memberCreator} enabled self join on {board}',
|
||||
'action_enabled_self_join@board'
|
||||
=> '{memberCreator} enabled self join on this board',
|
||||
'action_hid_board'
|
||||
=> '{memberCreator} hid {board}',
|
||||
'action_hid_board@board'
|
||||
=> '{memberCreator} hid this board',
|
||||
'action_invited_an_unconfirmed_member_to_board'
|
||||
=> '{memberCreator} invited an unconfirmed member to {board}',
|
||||
'action_invited_an_unconfirmed_member_to_board@board'
|
||||
=> '{memberCreator} invited an unconfirmed member to this board',
|
||||
'action_invited_an_unconfirmed_member_to_organization'
|
||||
=> '{memberCreator} invited an unconfirmed member to {organization}',
|
||||
'action_joined_board'
|
||||
=> '{memberCreator} joined {board}',
|
||||
'action_joined_board@board'
|
||||
=> '{memberCreator} joined this board',
|
||||
'action_joined_board_by_invitation_link'
|
||||
=> '{memberCreator} joined {board} with an invitation link from {memberInviter}',
|
||||
'action_joined_board_by_invitation_link@board'
|
||||
=> '{memberCreator} joined this board with an invitation link from {memberInviter}',
|
||||
'action_joined_organization'
|
||||
=> '{memberCreator} joined {organization}',
|
||||
'action_joined_organization_by_invitation_link'
|
||||
=> '{memberCreator} joined {organization} with an invitation link from {memberInviter}',
|
||||
'action_left_board'
|
||||
=> '{memberCreator} left {board}',
|
||||
'action_left_board@board'
|
||||
=> '{memberCreator} left this board',
|
||||
'action_left_organization'
|
||||
=> '{memberCreator} left {organization}',
|
||||
'action_made_a_normal_user_in_organization'
|
||||
=> '{memberCreator} made {member} a normal user in {organization}',
|
||||
'action_made_a_normal_user_on'
|
||||
=> '{memberCreator} made {member} a normal user on {board}',
|
||||
'action_made_a_normal_user_on@board'
|
||||
=> '{memberCreator} made {member} a normal user on this board',
|
||||
'action_made_admin_of_board'
|
||||
=> '{memberCreator} made {member} an admin of {board}',
|
||||
'action_made_admin_of_board@board'
|
||||
=> '{memberCreator} made {member} an admin of this board',
|
||||
'action_made_an_admin_of_organization'
|
||||
=> '{memberCreator} made {member} an admin of {organization}',
|
||||
'action_made_commenting_on'
|
||||
=> '{memberCreator} made commenting on {board} available to {level}',
|
||||
'action_made_commenting_on@board'
|
||||
=> '{memberCreator} made commenting on this board available to {level}',
|
||||
'action_made_inviting_on'
|
||||
=> '{memberCreator} made inviting on {board} available to {level}',
|
||||
'action_made_inviting_on@board'
|
||||
=> '{memberCreator} made inviting on this board available to {level}',
|
||||
'action_made_observer_of_board'
|
||||
=> '{memberCreator} made {member} an observer of {board}',
|
||||
'action_made_observer_of_board@board'
|
||||
=> '{memberCreator} made {member} an observer of this board',
|
||||
'action_made_self_admin_of_board'
|
||||
=> '{memberCreator} made themselves an admin of {board}',
|
||||
'action_made_self_admin_of_board@board'
|
||||
=> '{memberCreator} made themselves an admin of this board',
|
||||
'action_made_self_observer_of_board'
|
||||
=> '{memberCreator} became an observer of {board}',
|
||||
'action_made_self_observer_of_board@board'
|
||||
=> '{memberCreator} became an observer of this board',
|
||||
'action_made_voting_on'
|
||||
=> '{memberCreator} made voting on {board} available to {level}',
|
||||
'action_made_voting_on@board'
|
||||
=> '{memberCreator} made voting on this board available to {level}',
|
||||
'action_marked_checkitem_incomplete'
|
||||
=> '{memberCreator} marked {checkitem} incomplete on {card}',
|
||||
'action_marked_checkitem_incomplete@card'
|
||||
=> '{memberCreator} marked {checkitem} incomplete on this card',
|
||||
'action_marked_the_due_date_complete'
|
||||
=> '{memberCreator} marked the due date on {card} complete',
|
||||
'action_marked_the_due_date_complete@card'
|
||||
=> '{memberCreator} marked the due date complete',
|
||||
'action_marked_the_due_date_incomplete'
|
||||
=> '{memberCreator} marked the due date on {card} incomplete',
|
||||
'action_marked_the_due_date_incomplete@card'
|
||||
=> '{memberCreator} marked the due date incomplete',
|
||||
'action_member_joined_card'
|
||||
=> '{memberCreator} joined {card}',
|
||||
'action_member_joined_card@card'
|
||||
=> '{memberCreator} joined this card',
|
||||
'action_member_left_card'
|
||||
=> '{memberCreator} left {card}',
|
||||
'action_member_left_card@card'
|
||||
=> '{memberCreator} left this card',
|
||||
'action_members_visibility'
|
||||
=> 'its members',
|
||||
'action_move_card_from_board'
|
||||
=> '{memberCreator} transferred {card} to {board}',
|
||||
'action_move_card_from_board@card'
|
||||
=> '{memberCreator} transferred this card to {board}',
|
||||
'action_move_card_from_list_to_list'
|
||||
=> '{memberCreator} moved {card} from {listBefore} to {listAfter}',
|
||||
'action_move_card_from_list_to_list@card'
|
||||
=> '{memberCreator} moved this card from {listBefore} to {listAfter}',
|
||||
'action_move_card_to_board'
|
||||
=> '{memberCreator} transferred {card} from {board}',
|
||||
'action_move_card_to_board@card'
|
||||
=> '{memberCreator} transferred this card from {board}',
|
||||
'action_move_list_from_board'
|
||||
=> '{memberCreator} transferred {list} to {board}',
|
||||
'action_move_list_to_board'
|
||||
=> '{memberCreator} transferred {list} from {board}',
|
||||
'action_moved_card_higher'
|
||||
=> '{memberCreator} moved {card} higher',
|
||||
'action_moved_card_higher@card'
|
||||
=> '{memberCreator} moved this card higher',
|
||||
'action_moved_card_lower'
|
||||
=> '{memberCreator} moved {card} lower',
|
||||
'action_moved_card_lower@card'
|
||||
=> '{memberCreator} moved this card lower',
|
||||
'action_moved_checkitem_higher'
|
||||
=> '{memberCreator} moved {checkitem} higher in the checklist {checklist}',
|
||||
'action_moved_checkitem_lower'
|
||||
=> '{memberCreator} moved {checkitem} higher in the checklist {checklist}',
|
||||
'action_moved_list_left'
|
||||
=> '{memberCreator} moved list {list} left on {board}',
|
||||
'action_moved_list_left@board'
|
||||
=> '{memberCreator} moved {list} left on this board',
|
||||
'action_moved_list_right'
|
||||
=> '{memberCreator} moved list {list} right on {board}',
|
||||
'action_moved_list_right@board'
|
||||
=> '{memberCreator} moved {list} right on this board',
|
||||
'action_observers_visibility'
|
||||
=> 'members and observers',
|
||||
'action_on'
|
||||
=> 'on',
|
||||
'action_org_visibility'
|
||||
=> 'members of its team',
|
||||
'action_public_visibility'
|
||||
=> 'the public',
|
||||
'action_remove_checklist_from_card'
|
||||
=> '{memberCreator} removed {checklist} from {card}',
|
||||
'action_remove_checklist_from_card@card'
|
||||
=> '{memberCreator} removed {checklist} from this card',
|
||||
'action_remove_from_organization_board'
|
||||
=> '{memberCreator} removed {board} from {organization}',
|
||||
'action_remove_from_organization_board@board'
|
||||
=> '{memberCreator} removed this board from {organization}',
|
||||
'action_remove_label_from_card'
|
||||
=> '{memberCreator} removed the {label} label from {card}',
|
||||
'action_remove_label_from_card@card'
|
||||
=> '{memberCreator} removed the {label} label from this card',
|
||||
'action_remove_organization_from_enterprise'
|
||||
=> '{memberCreator} removed team {organization} from the enterprise {enterprise}',
|
||||
'action_removed_a_due_date'
|
||||
=> '{memberCreator} removed the due date from {card}',
|
||||
'action_removed_a_due_date@card'
|
||||
=> '{memberCreator} removed the due date from this card',
|
||||
'action_removed_from_board'
|
||||
=> '{memberCreator} removed {member} from {board}',
|
||||
'action_removed_from_board@board'
|
||||
=> '{memberCreator} removed {member} from this board',
|
||||
'action_removed_member_from_card'
|
||||
=> '{memberCreator} removed {member} from {card}',
|
||||
'action_removed_member_from_card@card'
|
||||
=> '{memberCreator} removed {member} from this card',
|
||||
'action_removed_member_from_organization'
|
||||
=> '{memberCreator} removed {member} from {organization}',
|
||||
'action_removed_vote_for_card'
|
||||
=> '{memberCreator} removed vote for {card}',
|
||||
'action_removed_vote_for_card@card'
|
||||
=> '{memberCreator} removed vote for this card',
|
||||
'action_rename_custom_field'
|
||||
=> '{memberCreator} renamed the {customField} custom field on {board} (from {name})',
|
||||
'action_rename_custom_field@board'
|
||||
=> '{memberCreator} renamed the {customField} custom field on this board (from {name})',
|
||||
'action_renamed_card'
|
||||
=> '{memberCreator} renamed {card} (from {name})',
|
||||
'action_renamed_card@card'
|
||||
=> '{memberCreator} renamed this card (from {name})',
|
||||
'action_renamed_checkitem'
|
||||
=> '{memberCreator} renamed {checkitem} (from {name})',
|
||||
'action_renamed_checklist'
|
||||
=> '{memberCreator} renamed {checklist} (from {name})',
|
||||
'action_renamed_list'
|
||||
=> '{memberCreator} renamed list {list} (from {name})',
|
||||
'action_reopened_board'
|
||||
=> '{memberCreator} re-opened {board}',
|
||||
'action_reopened_board@board'
|
||||
=> '{memberCreator} re-opened this board',
|
||||
'action_sent_card_to_board'
|
||||
=> '{memberCreator} sent {card} to the board',
|
||||
'action_sent_card_to_board@card'
|
||||
=> '{memberCreator} sent this card to the board',
|
||||
'action_sent_list_to_board'
|
||||
=> '{memberCreator} sent list {list} to the board',
|
||||
'action_set_card_aging_mode_pirate'
|
||||
=> '{memberCreator} changed card aging to pirate mode',
|
||||
'action_set_card_aging_mode_regular'
|
||||
=> '{memberCreator} changed card aging to regular mode',
|
||||
'action_update_board_desc'
|
||||
=> '{memberCreator} changed description of {board}',
|
||||
'action_update_board_desc@board'
|
||||
=> '{memberCreator} changed description of this board',
|
||||
'action_update_board_name'
|
||||
=> '{memberCreator} renamed {board} (from {name})',
|
||||
'action_update_board_name@board'
|
||||
=> '{memberCreator} renamed this board (from {name})',
|
||||
'action_update_custom_field'
|
||||
=> '{memberCreator} updated the {customField} custom field on {board}',
|
||||
'action_update_custom_field@board'
|
||||
=> '{memberCreator} updated the {customField} custom field on this board',
|
||||
'action_update_custom_field_item'
|
||||
=> '{memberCreator} updated the value for the {customFieldItem} custom field on {card}',
|
||||
'action_update_custom_field_item@card'
|
||||
=> '{memberCreator} updated the value for the {customFieldItem} custom field on this card',
|
||||
'action_updated_their_bio'
|
||||
=> '{memberCreator} updated their bio',
|
||||
'action_updated_their_display_name'
|
||||
=> '{memberCreator} updated their display name',
|
||||
'action_updated_their_initials'
|
||||
=> '{memberCreator} updated their initials',
|
||||
'action_updated_their_username'
|
||||
=> '{memberCreator} updated their username',
|
||||
'action_vote_on_card'
|
||||
=> '{memberCreator} voted for {card}',
|
||||
'action_vote_on_card@card'
|
||||
=> '{memberCreator} voted for this card',
|
||||
'action_voting'
|
||||
=> 'voting',
|
||||
'action_withdraw_enterprise_join_request'
|
||||
=> '{memberCreator} withdrew a request to add team {organization} to the enterprise {enterprise}'
|
||||
);
|
||||
|
||||
const REQUEST_ACTIONS_BOARDS = array(
|
||||
'addAttachmentToCard',
|
||||
'addChecklistToCard',
|
||||
'addMemberToCard',
|
||||
'commentCard',
|
||||
'copyCommentCard',
|
||||
'convertToCardFromCheckItem',
|
||||
'createCard',
|
||||
'copyCard',
|
||||
'deleteAttachmentFromCard',
|
||||
'emailCard',
|
||||
'moveCardFromBoard',
|
||||
'moveCardToBoard',
|
||||
'removeChecklistFromCard',
|
||||
'removeMemberFromCard',
|
||||
'updateCard:idList',
|
||||
'updateCard:closed',
|
||||
'updateCard:due',
|
||||
'updateCard:dueComplete',
|
||||
'updateCheckItemStateOnCard',
|
||||
'updateCustomFieldItem',
|
||||
'addMemberToBoard',
|
||||
'addToOrganizationBoard',
|
||||
'copyBoard',
|
||||
'createBoard',
|
||||
'createCustomField',
|
||||
'createList',
|
||||
'deleteCard',
|
||||
'deleteCustomField',
|
||||
'disablePlugin',
|
||||
'disablePowerUp',
|
||||
'enablePlugin',
|
||||
'enablePowerUp',
|
||||
'makeAdminOfBoard',
|
||||
'makeNormalMemberOfBoard',
|
||||
'makeObserverOfBoard',
|
||||
'moveListFromBoard',
|
||||
'moveListToBoard',
|
||||
'removeFromOrganizationBoard',
|
||||
'unconfirmedBoardInvitation',
|
||||
'unconfirmedOrganizationInvitation',
|
||||
'updateBoard',
|
||||
'updateCustomField',
|
||||
'updateList:closed'
|
||||
);
|
||||
|
||||
const REQUEST_ACTIONS_CARDS = array(
|
||||
'addAttachmentToCard',
|
||||
'addChecklistToCard',
|
||||
'addMemberToCard',
|
||||
'commentCard',
|
||||
'copyCommentCard',
|
||||
'convertToCardFromCheckItem',
|
||||
'createCard',
|
||||
'copyCard',
|
||||
'deleteAttachmentFromCard',
|
||||
'emailCard',
|
||||
'moveCardFromBoard',
|
||||
'moveCardToBoard',
|
||||
'removeChecklistFromCard',
|
||||
'removeMemberFromCard',
|
||||
'updateCard:idList',
|
||||
'updateCard:closed',
|
||||
'updateCard:due',
|
||||
'updateCard:dueComplete',
|
||||
'updateCheckItemStateOnCard',
|
||||
'updateCustomFieldItem'
|
||||
);
|
||||
|
||||
private $feedName = '';
|
||||
private $feedURI = '';
|
||||
|
||||
private function queryAPI($path, $params = array()) {
|
||||
$data = json_decode(getContents('https://trello.com/1/'
|
||||
. $path
|
||||
. '?'
|
||||
. http_build_query($params)))
|
||||
or returnServerError('Failed to query trello API');
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function renderAction($action, $textOnly = false) {
|
||||
if(!array_key_exists($action->display->translationKey, self::ACTION_TEXTS)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$strings = array();
|
||||
$entities = (array)$action->display->entities;
|
||||
|
||||
foreach($entities as $entity_name => $entity) {
|
||||
$type = $entity->type;
|
||||
if($type === 'attachmentPreview'
|
||||
&& !$textOnly
|
||||
&& isset($entity->originalUrl)) {
|
||||
$string = '<p><a href="'
|
||||
. $entity->originalUrl
|
||||
. '"><img src="'
|
||||
. $entity->previewUrl
|
||||
. '"></a></p>';
|
||||
} elseif($type === 'card' && !$textOnly) {
|
||||
$string = '<a href="https://trello.com/c/'
|
||||
. $entity->shortLink
|
||||
. '">'
|
||||
. $entity->text
|
||||
. '</a>';
|
||||
} elseif($type === 'member' && !$textOnly) {
|
||||
$string = '<a href="https://trello.com/'
|
||||
. $entity->username
|
||||
. '">'
|
||||
. $entity->text
|
||||
. '</a>';
|
||||
} elseif($type === 'date') {
|
||||
$string = gmdate('M j, Y \a\t g:i A T', strtotime($entity->date));
|
||||
} elseif($type === 'translatable') {
|
||||
$string = self::ACTION_TEXTS[$entity->translationKey];
|
||||
} else {
|
||||
if(isset($entity->text)) {
|
||||
$string = $entity->text;
|
||||
} else {
|
||||
$string = '';
|
||||
}
|
||||
}
|
||||
$strings['{' . $entity_name . '}'] = $string;
|
||||
}
|
||||
|
||||
return str_replace(array_keys($strings),
|
||||
array_values($strings),
|
||||
self::ACTION_TEXTS[$action->display->translationKey]);
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
$apiParams = array(
|
||||
'actions_display' => 'true',
|
||||
'fields' => 'name,url'
|
||||
);
|
||||
switch($this->queriedContext) {
|
||||
case 'Board':
|
||||
$apiParams['actions'] = implode(',', self::REQUEST_ACTIONS_BOARDS);
|
||||
$data = $this->queryAPI('boards/' . $this->getInput('b'), $apiParams);
|
||||
break;
|
||||
case 'Card':
|
||||
$apiParams['actions'] = implode(',', self::REQUEST_ACTIONS_CARDS);
|
||||
$data = $this->queryAPI('cards/' . $this->getInput('c'), $apiParams);
|
||||
break;
|
||||
default:
|
||||
returnClientError('Invalid context');
|
||||
}
|
||||
|
||||
$this->feedName = $data->name;
|
||||
$this->feedURI = $data->url;
|
||||
|
||||
foreach($data->actions as $action) {
|
||||
$item = array();
|
||||
|
||||
$item['title'] = $this->renderAction($action, true);
|
||||
$item['timestamp'] = strtotime($action->date);
|
||||
$item['author'] = $action->memberCreator->fullName;
|
||||
$item['categories'] = array(
|
||||
'trello',
|
||||
$action->data->board->name,
|
||||
$action->type
|
||||
);
|
||||
if(isset($action->data->card)) {
|
||||
$item['categories'][] = $action->data->card->name;
|
||||
$item['uri'] = 'https://trello.com/c/'
|
||||
. $action->data->card->shortLink
|
||||
. '#action-'
|
||||
. $action->id;
|
||||
} else {
|
||||
$item['uri'] = 'https://trello.com/b/'
|
||||
. $action->data->board->shortLink;
|
||||
}
|
||||
$item['content'] = $this->renderAction($action, false);
|
||||
if(isset($action->data->attachment->url)) {
|
||||
$item['enclosures'] = array($action->data->attachment->url);
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function detectParameters($url) {
|
||||
$regex = '/^(https?:\/\/)?trello\.com\/([bc])\/([^\/?\n]+)/';
|
||||
if(preg_match($regex, $url, $matches) > 0) {
|
||||
return array($matches[2] => $matches[3]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
switch($this->queriedContext) {
|
||||
case 'Board':
|
||||
case 'Card':
|
||||
return $this->feedURI;
|
||||
default: return parent::getURI();
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
switch($this->queriedContext) {
|
||||
case 'Board':
|
||||
case 'Card':
|
||||
return $this->feedName;
|
||||
default: return parent::getName();
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,6 +16,11 @@ class TwitterBridge extends BridgeAbstract {
|
||||
'name' => 'Hide images in tweets',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Activate to hide images in tweets'
|
||||
),
|
||||
'noimgscaling' => array(
|
||||
'name' => 'Disable image scaling',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Activate to disable image scaling in tweets (keeps original image)'
|
||||
)
|
||||
),
|
||||
'By keyword or hashtag' => array(
|
||||
@@ -160,7 +165,7 @@ class TwitterBridge extends BridgeAbstract {
|
||||
|
||||
// Skip retweets?
|
||||
if($this->getInput('noretweet')
|
||||
&& $tweet->getAttribute('data-screen-name') !== $this->getInput('u')) {
|
||||
&& strcasecmp($tweet->getAttribute('data-screen-name'), $this->getInput('u'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -184,6 +189,9 @@ class TwitterBridge extends BridgeAbstract {
|
||||
$item['fullname'] = htmlspecialchars_decode($tweet->getAttribute('data-name'), ENT_QUOTES);
|
||||
// get author
|
||||
$item['author'] = $item['fullname'] . ' (@' . $item['username'] . ')';
|
||||
if(strcasecmp($tweet->getAttribute('data-screen-name'), $this->getInput('u'))) {
|
||||
$item['author'] .= ' RT: @' . $this->getInput('u');
|
||||
}
|
||||
// get avatar link
|
||||
$item['avatar'] = $tweet->find('img', 0)->src;
|
||||
// get TweetID
|
||||
@@ -239,14 +247,18 @@ EOD;
|
||||
$image_html = '';
|
||||
$image = $this->getImageURI($tweet);
|
||||
if(!$this->getInput('noimg') && !is_null($image)) {
|
||||
// Set image scaling
|
||||
$image_orig = $this->getInput('noimgscaling') ? $image : $image . ':orig';
|
||||
$image_thumb = $this->getInput('noimgscaling') ? $image : $image . ':thumb';
|
||||
|
||||
// add enclosures
|
||||
$item['enclosures'] = array($image . ':orig');
|
||||
$item['enclosures'] = array($image_orig);
|
||||
|
||||
$image_html = <<<EOD
|
||||
<a href="{$image}:orig">
|
||||
<a href="{$image_orig}">
|
||||
<img
|
||||
style="align:top; max-width:558px; border:1px solid black;"
|
||||
src="{$image}:thumb" />
|
||||
src="{$image_thumb}" />
|
||||
</a>
|
||||
EOD;
|
||||
}
|
||||
@@ -281,14 +293,18 @@ EOD;
|
||||
$quotedImage_html = '';
|
||||
$quotedImage = $this->getQuotedImageURI($tweet);
|
||||
if(!$this->getInput('noimg') && !is_null($quotedImage)) {
|
||||
// Set image scaling
|
||||
$quotedImage_orig = $this->getInput('noimgscaling') ? $quotedImage : $quotedImage . ':orig';
|
||||
$quotedImage_thumb = $this->getInput('noimgscaling') ? $quotedImage : $quotedImage . ':thumb';
|
||||
|
||||
// add enclosures
|
||||
$item['enclosures'] = array($quotedImage . ':orig');
|
||||
$item['enclosures'] = array($quotedImage_orig);
|
||||
|
||||
$quotedImage_html = <<<EOD
|
||||
<a href="{$quotedImage}:orig">
|
||||
<a href="{$quotedImage_orig}">
|
||||
<img
|
||||
style="align:top; max-width:558px; border:1px solid black;"
|
||||
src="{$quotedImage}:thumb" />
|
||||
src="{$quotedImage_thumb}" />
|
||||
</a>
|
||||
EOD;
|
||||
}
|
||||
|
@@ -106,5 +106,4 @@ class UsbekEtRicaBridge extends BridgeAbstract {
|
||||
private function replaceUriInHtmlElement($element){
|
||||
return str_replace('href="/', 'href="' . $this->getURI() . '/', $element->innertext);
|
||||
}
|
||||
|
||||
}
|
||||
|
31
bridges/VMwareSecurityBridge.php
Normal file
31
bridges/VMwareSecurityBridge.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
class VMwareSecurityBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'm0le.net';
|
||||
const NAME = 'VMware Security Advisories';
|
||||
const URI = 'https://www.vmware.com/security/advisories.html';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = 'VMware Security Advisories';
|
||||
const WEBROOT = 'https://www.vmware.com';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request VSA.');
|
||||
|
||||
$html = defaultLinkTo($html, self::WEBROOT);
|
||||
|
||||
$item = array();
|
||||
$articles = $html->find('div[class="news_block"]');
|
||||
|
||||
foreach ($articles as $element) {
|
||||
$item['uri'] = $element->find('a', 0)->getAttribute('href');
|
||||
$title = $element->find('a', 0)->innertext;
|
||||
$item['title'] = $title;
|
||||
$item['timestamp'] = strtotime($element->find('p', 0)->innertext);
|
||||
$item['content'] = $element->find('p', 1)->innertext;
|
||||
$item['uid'] = $title;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -55,6 +55,7 @@ class WhydBridge extends BridgeAbstract {
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return (!empty($this->userName) ? $this->userName . ' - ' : '') . 'Whyd Bridge';
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@ class WikiLeaksBridge extends BridgeAbstract {
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your category',
|
||||
'values' => array(
|
||||
'News' => '-News-',
|
||||
@@ -28,7 +27,6 @@ class WikiLeaksBridge extends BridgeAbstract {
|
||||
'teaser' => array(
|
||||
'name' => 'Show teaser',
|
||||
'type' => 'checkbox',
|
||||
'required' => false,
|
||||
'title' => 'If checked feeds will display the teaser',
|
||||
'defaultValue' => true
|
||||
)
|
||||
|
@@ -13,7 +13,6 @@ class WikipediaBridge extends BridgeAbstract {
|
||||
'language' => array(
|
||||
'name' => 'Language',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your language',
|
||||
'exampleValue' => 'English',
|
||||
'values' => array(
|
||||
@@ -27,7 +26,6 @@ class WikipediaBridge extends BridgeAbstract {
|
||||
'subject' => array(
|
||||
'name' => 'Subject',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'What subject are you interested in?',
|
||||
'exampleValue' => 'Today\'s featured article',
|
||||
'values' => array(
|
||||
|
@@ -64,7 +64,6 @@ class WordPressPluginUpdateBridge extends BridgeAbstract {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('q'))) {
|
||||
return $this->getInput('q') . ' : ' . self::NAME;
|
||||
@@ -76,7 +75,7 @@ class WordPressPluginUpdateBridge extends BridgeAbstract {
|
||||
private function getCachedDate($url){
|
||||
Debug::log('getting pubdate from url ' . $url . '');
|
||||
// Initialize cache
|
||||
$cache = Cache::create('FileCache');
|
||||
$cache = Cache::create(Configuration::getConfig('cache', 'type'));
|
||||
$cache->setPath(PATH_CACHE . 'pages/');
|
||||
$params = [$url];
|
||||
$cache->setParameters($params);
|
||||
|
@@ -75,8 +75,7 @@ class XenForoBridge extends BridgeAbstract {
|
||||
|
||||
$this->threadurl = filter_var(
|
||||
$this->getInput('url'),
|
||||
FILTER_VALIDATE_URL,
|
||||
FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED | FILTER_FLAG_PATH_REQUIRED);
|
||||
FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED);
|
||||
|
||||
if($this->threadurl === false) {
|
||||
returnClientError('The URL you provided is invalid!');
|
||||
@@ -458,5 +457,4 @@ class XenForoBridge extends BridgeAbstract {
|
||||
return date_format($df, 'U');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
99
caches/SQLiteCache.php
Normal file
99
caches/SQLiteCache.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Cache based on SQLite 3 <https://www.sqlite.org>
|
||||
*/
|
||||
class SQLiteCache implements CacheInterface {
|
||||
protected $path;
|
||||
protected $param;
|
||||
|
||||
private $db = null;
|
||||
|
||||
public function __construct() {
|
||||
if (!extension_loaded('sqlite3'))
|
||||
die('"sqlite3" extension not loaded. Please check "php.ini"');
|
||||
|
||||
$file = PATH_CACHE . 'cache.sqlite';
|
||||
|
||||
if (!is_file($file)) {
|
||||
$this->db = new SQLite3($file);
|
||||
$this->db->enableExceptions(true);
|
||||
$this->db->exec("CREATE TABLE storage ('key' BLOB PRIMARY KEY, 'value' BLOB, 'updated' INTEGER)");
|
||||
} else {
|
||||
$this->db = new SQLite3($file);
|
||||
$this->db->enableExceptions(true);
|
||||
}
|
||||
$this->db->busyTimeout(5000);
|
||||
}
|
||||
|
||||
public function loadData(){
|
||||
$Qselect = $this->db->prepare('SELECT value FROM storage WHERE key = :key');
|
||||
$Qselect->bindValue(':key', $this->getCacheKey());
|
||||
$result = $Qselect->execute();
|
||||
if ($result instanceof SQLite3Result) {
|
||||
$data = $result->fetchArray(SQLITE3_ASSOC);
|
||||
if (isset($data['value'])) {
|
||||
return unserialize($data['value']);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function saveData($datas){
|
||||
$Qupdate = $this->db->prepare('INSERT OR REPLACE INTO storage (key, value, updated) VALUES (:key, :value, :updated)');
|
||||
$Qupdate->bindValue(':key', $this->getCacheKey());
|
||||
$Qupdate->bindValue(':value', serialize($datas));
|
||||
$Qupdate->bindValue(':updated', time());
|
||||
$Qupdate->execute();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTime(){
|
||||
$Qselect = $this->db->prepare('SELECT updated FROM storage WHERE key = :key');
|
||||
$Qselect->bindValue(':key', $this->getCacheKey());
|
||||
$result = $Qselect->execute();
|
||||
if ($result instanceof SQLite3Result) {
|
||||
$data = $result->fetchArray(SQLITE3_ASSOC);
|
||||
if (isset($data['updated'])) {
|
||||
return $data['updated'];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function purgeCache($duration){
|
||||
$Qdelete = $this->db->prepare('DELETE FROM storage WHERE updated < :expired');
|
||||
$Qdelete->bindValue(':expired', time() - $duration);
|
||||
$Qdelete->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache path
|
||||
* @return self
|
||||
*/
|
||||
public function setPath($path){
|
||||
$this->path = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP GET parameters
|
||||
* @return self
|
||||
*/
|
||||
public function setParameters(array $param){
|
||||
$this->param = array_map('strtolower', $param);
|
||||
return $this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected function getCacheKey(){
|
||||
if(is_null($this->param)) {
|
||||
throw new \Exception('Call "setParameters" first!');
|
||||
}
|
||||
|
||||
return hash('sha1', $this->path . http_build_query($this->param), true);
|
||||
}
|
||||
}
|
@@ -6,6 +6,10 @@
|
||||
|
||||
[cache]
|
||||
|
||||
; Defines the cache type used by RSS-Bridge
|
||||
; "file" = FileCache (default)
|
||||
type = "file"
|
||||
|
||||
; Allow users to specify custom timeout for specific requests.
|
||||
; true = enabled
|
||||
; false = disabled (default)
|
||||
|
@@ -1,22 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Atom
|
||||
* Documentation Source http://en.wikipedia.org/wiki/Atom_%28standard%29 and
|
||||
* http://tools.ietf.org/html/rfc4287
|
||||
*/
|
||||
* AtomFormat - RFC 4287: The Atom Syndication Format
|
||||
* https://tools.ietf.org/html/rfc4287
|
||||
*
|
||||
* Validator:
|
||||
* https://validator.w3.org/feed/
|
||||
*/
|
||||
class AtomFormat extends FormatAbstract{
|
||||
const LIMIT_TITLE = 140;
|
||||
|
||||
public function stringify(){
|
||||
$https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 's' : '';
|
||||
$httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$httpInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
|
||||
$urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
|
||||
$urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : '';
|
||||
$urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
|
||||
|
||||
$serverRequestUri = isset($_SERVER['REQUEST_URI']) ? $this->xml_encode($_SERVER['REQUEST_URI']) : '';
|
||||
$feedUrl = $this->xml_encode($urlPrefix . $urlHost . $urlRequest);
|
||||
|
||||
$extraInfos = $this->getExtraInfos();
|
||||
$title = $this->xml_encode($extraInfos['name']);
|
||||
$uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY;
|
||||
|
||||
// since we can't guarantee that all items have an author,
|
||||
// a global feed author is mandatory
|
||||
$feedAuthor = 'RSS-Bridge';
|
||||
|
||||
$uriparts = parse_url($uri);
|
||||
if(!empty($extraInfos['icon'])) {
|
||||
$icon = $extraInfos['icon'];
|
||||
@@ -28,42 +36,79 @@ class AtomFormat extends FormatAbstract{
|
||||
|
||||
$entries = '';
|
||||
foreach($this->getItems() as $item) {
|
||||
$entryAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : '';
|
||||
$entryTitle = isset($item['title']) ? $this->xml_encode($item['title']) : '';
|
||||
$entryUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : '';
|
||||
$entryTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_ATOM, $item['timestamp'])) : '';
|
||||
$entryContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : '';
|
||||
$entryTimestamp = $item->getTimestamp();
|
||||
$entryTitle = $this->xml_encode($item->getTitle());
|
||||
$entryContent = $item->getContent();
|
||||
$entryUri = $item->getURI();
|
||||
$entryID = '';
|
||||
|
||||
$entryEnclosures = '';
|
||||
if(isset($item['enclosures'])) {
|
||||
foreach($item['enclosures'] as $enclosure) {
|
||||
$entryEnclosures .= '<link rel="enclosure" href="'
|
||||
. $this->xml_encode($enclosure)
|
||||
. '" type="' . getMimeType($enclosure) . '" />'
|
||||
. PHP_EOL;
|
||||
if (!empty($item->getUid()))
|
||||
$entryID = 'urn:sha1:' . $item->getUid();
|
||||
|
||||
if (empty($entryID)) // Fallback to provided URI
|
||||
$entryID = $this->xml_encode($entryUri);
|
||||
|
||||
if (empty($entryID)) // Fallback to title and content
|
||||
$entryID = 'urn:sha1:' . hash('sha1', $entryTitle . $entryContent);
|
||||
|
||||
if (empty($entryTimestamp))
|
||||
$entryTimestamp = $this->lastModified;
|
||||
|
||||
if (empty($entryTitle)) {
|
||||
$entryTitle = str_replace("\n", ' ', strip_tags($entryContent));
|
||||
if (strlen($entryTitle) > self::LIMIT_TITLE) {
|
||||
$wrapPos = strpos(wordwrap($entryTitle, self::LIMIT_TITLE), "\n");
|
||||
$entryTitle = substr($entryTitle, 0, $wrapPos) . '...';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($entryContent))
|
||||
$entryContent = $entryTitle;
|
||||
|
||||
$entryAuthor = $this->xml_encode($item->getAuthor());
|
||||
$entryTitle = $this->xml_encode($entryTitle);
|
||||
$entryUri = $this->xml_encode($entryUri);
|
||||
$entryTimestamp = $this->xml_encode(gmdate(DATE_ATOM, $entryTimestamp));
|
||||
$entryContent = $this->xml_encode($this->sanitizeHtml($entryContent));
|
||||
|
||||
$entryEnclosures = '';
|
||||
foreach($item->getEnclosures() as $enclosure) {
|
||||
$entryEnclosures .= '<link rel="enclosure" href="'
|
||||
. $this->xml_encode($enclosure)
|
||||
. '" type="' . getMimeType($enclosure) . '" />'
|
||||
. PHP_EOL;
|
||||
}
|
||||
|
||||
$entryCategories = '';
|
||||
if(isset($item['categories'])) {
|
||||
foreach($item['categories'] as $category) {
|
||||
$entryCategories .= '<category term="'
|
||||
. $this->xml_encode($category)
|
||||
. '"/>'
|
||||
. PHP_EOL;
|
||||
}
|
||||
foreach($item->getCategories() as $category) {
|
||||
$entryCategories .= '<category term="'
|
||||
. $this->xml_encode($category)
|
||||
. '"/>'
|
||||
. PHP_EOL;
|
||||
}
|
||||
|
||||
$entryLinkAlternate = '';
|
||||
if (!empty($entryUri)) {
|
||||
$entryLinkAlternate = '<link rel="alternate" type="text/html" href="'
|
||||
. $entryUri
|
||||
. '"/>';
|
||||
}
|
||||
|
||||
if (!empty($entryAuthor)) {
|
||||
$entryAuthor = '<author><name>'
|
||||
. $entryAuthor
|
||||
. '</name></author>';
|
||||
}
|
||||
|
||||
$entries .= <<<EOD
|
||||
|
||||
<entry>
|
||||
<author>
|
||||
<name>{$entryAuthor}</name>
|
||||
</author>
|
||||
<title type="html">{$entryTitle}</title>
|
||||
<link rel="alternate" type="text/html" href="{$entryUri}" />
|
||||
<id>{$entryUri}</id>
|
||||
<published>{$entryTimestamp}</published>
|
||||
<updated>{$entryTimestamp}</updated>
|
||||
<id>{$entryID}</id>
|
||||
{$entryLinkAlternate}
|
||||
{$entryAuthor}
|
||||
<content type="html">{$entryContent}</content>
|
||||
{$entryEnclosures}
|
||||
{$entryCategories}
|
||||
@@ -72,21 +117,24 @@ class AtomFormat extends FormatAbstract{
|
||||
EOD;
|
||||
}
|
||||
|
||||
$feedTimestamp = date(DATE_ATOM, time());
|
||||
$charset = $this->getCharset();
|
||||
$feedTimestamp = gmdate(DATE_ATOM, $this->lastModified);
|
||||
$charset = $this->getCharset();
|
||||
|
||||
/* Data are prepared, now let's begin the "MAGIE !!!" */
|
||||
$toReturn = <<<EOD
|
||||
<?xml version="1.0" encoding="{$charset}"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<title type="text">{$title}</title>
|
||||
<id>http{$https}://{$httpHost}{$httpInfo}/</id>
|
||||
<id>{$feedUrl}</id>
|
||||
<icon>{$icon}</icon>
|
||||
<logo>{$icon}</logo>
|
||||
<updated>{$feedTimestamp}</updated>
|
||||
<author>
|
||||
<name>{$feedAuthor}</name>
|
||||
</author>
|
||||
<link rel="alternate" type="text/html" href="{$uri}" />
|
||||
<link rel="self" href="http{$https}://{$httpHost}{$serverRequestUri}" />
|
||||
<link rel="self" type="application/atom+xml" href="{$feedUrl}" />
|
||||
{$entries}
|
||||
</feed>
|
||||
EOD;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
class HtmlFormat extends FormatAbstract {
|
||||
|
||||
public function stringify(){
|
||||
$extraInfos = $this->getExtraInfos();
|
||||
$title = htmlspecialchars($extraInfos['name']);
|
||||
@@ -10,31 +9,31 @@ class HtmlFormat extends FormatAbstract {
|
||||
|
||||
$entries = '';
|
||||
foreach($this->getItems() as $item) {
|
||||
$entryAuthor = isset($item['author']) ? '<br /><p class="author">by: ' . $item['author'] . '</p>' : '';
|
||||
$entryTitle = isset($item['title']) ? $this->sanitizeHtml(strip_tags($item['title'])) : '';
|
||||
$entryUri = isset($item['uri']) ? $item['uri'] : $uri;
|
||||
$entryAuthor = $item->getAuthor() ? '<br /><p class="author">by: ' . $item->getAuthor() . '</p>' : '';
|
||||
$entryTitle = $this->sanitizeHtml(strip_tags($item->getTitle()));
|
||||
$entryUri = $item->getURI() ?: $uri;
|
||||
|
||||
$entryTimestamp = '';
|
||||
if(isset($item['timestamp'])) {
|
||||
if($item->getTimestamp()) {
|
||||
$entryTimestamp = '<time datetime="'
|
||||
. date(DATE_ATOM, $item['timestamp'])
|
||||
. date(DATE_ATOM, $item->getTimestamp())
|
||||
. '">'
|
||||
. date(DATE_ATOM, $item['timestamp'])
|
||||
. date(DATE_ATOM, $item->getTimestamp())
|
||||
. '</time>';
|
||||
}
|
||||
|
||||
$entryContent = '';
|
||||
if(isset($item['content'])) {
|
||||
if($item->getContent()) {
|
||||
$entryContent = '<div class="content">'
|
||||
. $this->sanitizeHtml($item['content'])
|
||||
. $this->sanitizeHtml($item->getContent())
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
$entryEnclosures = '';
|
||||
if(isset($item['enclosures'])) {
|
||||
if(!empty($item->getEnclosures())) {
|
||||
$entryEnclosures = '<div class="attachments"><p>Attachments:</p>';
|
||||
|
||||
foreach($item['enclosures'] as $enclosure) {
|
||||
foreach($item->getEnclosures() as $enclosure) {
|
||||
$url = $this->sanitizeHtml($enclosure);
|
||||
|
||||
$entryEnclosures .= '<li class="enclosure"><a href="'
|
||||
@@ -48,10 +47,10 @@ class HtmlFormat extends FormatAbstract {
|
||||
}
|
||||
|
||||
$entryCategories = '';
|
||||
if(isset($item['categories']) && count($item['categories']) > 0) {
|
||||
if(!empty($item->getCategories())) {
|
||||
$entryCategories = '<div class="categories"><p>Categories:</p>';
|
||||
|
||||
foreach($item['categories'] as $category) {
|
||||
foreach($item->getCategories() as $category) {
|
||||
|
||||
$entryCategories .= '<li class="category">'
|
||||
. $this->sanitizeHtml($category)
|
||||
|
@@ -1,13 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* Json
|
||||
* Builds a JSON string from $this->items and return it to browser.
|
||||
*/
|
||||
* JsonFormat - JSON Feed Version 1
|
||||
* https://jsonfeed.org/version/1
|
||||
*
|
||||
* Validators:
|
||||
* https://validator.jsonfeed.org
|
||||
* https://github.com/vigetlabs/json-feed-validator
|
||||
*/
|
||||
class JsonFormat extends FormatAbstract {
|
||||
const VENDOR_EXCLUDES = array(
|
||||
'author',
|
||||
'title',
|
||||
'uri',
|
||||
'timestamp',
|
||||
'content',
|
||||
'enclosures',
|
||||
'categories',
|
||||
'uid',
|
||||
);
|
||||
|
||||
public function stringify(){
|
||||
$items = $this->getItems();
|
||||
$toReturn = json_encode($items, JSON_PRETTY_PRINT);
|
||||
$urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
|
||||
$urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : '';
|
||||
$urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
|
||||
|
||||
$extraInfos = $this->getExtraInfos();
|
||||
|
||||
$data = array(
|
||||
'version' => 'https://jsonfeed.org/version/1',
|
||||
'title' => (!empty($extraInfos['name'])) ? $extraInfos['name'] : $urlHost,
|
||||
'home_page_url' => (!empty($extraInfos['uri'])) ? $extraInfos['uri'] : REPOSITORY,
|
||||
'feed_url' => $urlPrefix . $urlHost . $urlRequest
|
||||
);
|
||||
|
||||
if (!empty($extraInfos['icon'])) {
|
||||
$data['icon'] = $extraInfos['icon'];
|
||||
$data['favicon'] = $extraInfos['icon'];
|
||||
}
|
||||
|
||||
$items = array();
|
||||
foreach ($this->getItems() as $item) {
|
||||
$entry = array();
|
||||
|
||||
$entryAuthor = $item->getAuthor();
|
||||
$entryTitle = $item->getTitle();
|
||||
$entryUri = $item->getURI();
|
||||
$entryTimestamp = $item->getTimestamp();
|
||||
$entryContent = $this->sanitizeHtml($item->getContent());
|
||||
$entryEnclosures = $item->getEnclosures();
|
||||
$entryCategories = $item->getCategories();
|
||||
|
||||
$vendorFields = $item->toArray();
|
||||
foreach (self::VENDOR_EXCLUDES as $key) {
|
||||
unset($vendorFields[$key]);
|
||||
}
|
||||
|
||||
$entry['id'] = $item->getUid();
|
||||
|
||||
if (empty($entry['id'])) {
|
||||
$entry['id'] = $entryUri;
|
||||
}
|
||||
|
||||
if (!empty($entryTitle)) {
|
||||
$entry['title'] = $entryTitle;
|
||||
}
|
||||
if (!empty($entryAuthor)) {
|
||||
$entry['author'] = array(
|
||||
'name' => $entryAuthor
|
||||
);
|
||||
}
|
||||
if (!empty($entryTimestamp)) {
|
||||
$entry['date_modified'] = gmdate(DATE_ATOM, $entryTimestamp);
|
||||
}
|
||||
if (!empty($entryUri)) {
|
||||
$entry['url'] = $entryUri;
|
||||
}
|
||||
if (!empty($entryContent)) {
|
||||
if ($this->isHTML($entryContent)) {
|
||||
$entry['content_html'] = $entryContent;
|
||||
} else {
|
||||
$entry['content_text'] = $entryContent;
|
||||
}
|
||||
}
|
||||
if (!empty($entryEnclosures)) {
|
||||
$entry['attachments'] = array();
|
||||
foreach ($entryEnclosures as $enclosure) {
|
||||
$entry['attachments'][] = array(
|
||||
'url' => $enclosure,
|
||||
'mime_type' => getMimeType($enclosure)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($entryCategories)) {
|
||||
$entry['tags'] = array();
|
||||
foreach ($entryCategories as $category) {
|
||||
$entry['tags'][] = $category;
|
||||
}
|
||||
}
|
||||
if (!empty($vendorFields)) {
|
||||
$entry['_rssbridge'] = $vendorFields;
|
||||
}
|
||||
|
||||
if (empty($entry['id']))
|
||||
$entry['id'] = hash('sha1', $entryTitle . $entryContent);
|
||||
|
||||
$items[] = $entry;
|
||||
}
|
||||
$data['items'] = $items;
|
||||
|
||||
$toReturn = json_encode($data, JSON_PRETTY_PRINT);
|
||||
|
||||
// Remove invalid non-UTF8 characters
|
||||
ini_set('mbstring.substitute_character', 'none');
|
||||
@@ -22,4 +124,8 @@ class JsonFormat extends FormatAbstract {
|
||||
|
||||
return parent::display();
|
||||
}
|
||||
|
||||
private function isHTML($text) {
|
||||
return (strlen(strip_tags($text)) != strlen($text));
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Mrss
|
||||
* Documentation Source http://www.rssboard.org/media-rss
|
||||
*/
|
||||
* MrssFormat - RSS 2.0 + Media RSS
|
||||
* http://www.rssboard.org/rss-specification
|
||||
* http://www.rssboard.org/media-rss
|
||||
*
|
||||
* Validators:
|
||||
* https://validator.w3.org/feed/
|
||||
* http://www.rssboard.org/rss-validator/
|
||||
*
|
||||
* Notes about the implementation:
|
||||
*
|
||||
* - The item author is not supported as it needs to be an e-mail address to be
|
||||
* valid.
|
||||
* - The RSS specification does not explicitly allow to have more than one
|
||||
* enclosure as every item is meant to provide one "story", thus having
|
||||
* multiple enclosures per item may lead to unexpected behavior.
|
||||
* On top of that, it requires to have a length specified, which RSS-Bridge
|
||||
* can't provide.
|
||||
* - The Media RSS extension comes in handy, since it allows to have multiple
|
||||
* enclosures, even though they recommend to have only one enclosure because
|
||||
* of the one-story-per-item reason. It only requires to specify the URL,
|
||||
* everything else is optional.
|
||||
* - Since the Media RSS extension has its own namespace, the output is a valid
|
||||
* RSS 2.0 feed that works with feed readers that don't support the extension.
|
||||
*/
|
||||
class MrssFormat extends FormatAbstract {
|
||||
const ALLOWED_IMAGE_EXT = array(
|
||||
'.gif', '.jpg', '.png'
|
||||
);
|
||||
|
||||
public function stringify(){
|
||||
$https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 's' : '';
|
||||
$httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$httpInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
|
||||
$urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
|
||||
$urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : '';
|
||||
$urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
|
||||
|
||||
$serverRequestUri = isset($_SERVER['REQUEST_URI']) ? $this->xml_encode($_SERVER['REQUEST_URI']) : '';
|
||||
$feedUrl = $this->xml_encode($urlPrefix . $urlHost . $urlRequest);
|
||||
|
||||
$extraInfos = $this->getExtraInfos();
|
||||
$title = $this->xml_encode($extraInfos['name']);
|
||||
$icon = $extraInfos['icon'];
|
||||
|
||||
if(!empty($extraInfos['uri'])) {
|
||||
$uri = $this->xml_encode($extraInfos['uri']);
|
||||
@@ -21,55 +47,65 @@ class MrssFormat extends FormatAbstract {
|
||||
$uri = REPOSITORY;
|
||||
}
|
||||
|
||||
$uriparts = parse_url($uri);
|
||||
$icon = $this->xml_encode($uriparts['scheme'] . '://' . $uriparts['host'] . '/favicon.ico');
|
||||
|
||||
$items = '';
|
||||
foreach($this->getItems() as $item) {
|
||||
$itemAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : '';
|
||||
$itemTitle = strip_tags(isset($item['title']) ? $this->xml_encode($item['title']) : '');
|
||||
$itemUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : '';
|
||||
$itemTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_RFC2822, $item['timestamp'])) : '';
|
||||
$itemContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : '';
|
||||
$itemTimestamp = $item->getTimestamp();
|
||||
$itemTitle = $this->xml_encode($item->getTitle());
|
||||
$itemUri = $this->xml_encode($item->getURI());
|
||||
$itemContent = $this->xml_encode($this->sanitizeHtml($item->getContent()));
|
||||
$entryID = $item->getUid();
|
||||
$isPermaLink = 'false';
|
||||
|
||||
if (empty($entryID) && !empty($itemUri)) { // Fallback to provided URI
|
||||
$entryID = $itemUri;
|
||||
$isPermaLink = 'true';
|
||||
}
|
||||
|
||||
if (empty($entryID)) // Fallback to title and content
|
||||
$entryID = hash('sha1', $itemTitle . $itemContent);
|
||||
|
||||
$entryTitle = '';
|
||||
if (!empty($itemTitle))
|
||||
$entryTitle = '<title>' . $itemTitle . '</title>';
|
||||
|
||||
$entryLink = '';
|
||||
if (!empty($itemUri))
|
||||
$entryLink = '<link>' . $itemUri . '</link>';
|
||||
|
||||
$entryPublished = '';
|
||||
if (!empty($itemTimestamp)) {
|
||||
$entryPublished = '<pubDate>'
|
||||
. $this->xml_encode(gmdate(DATE_RFC2822, $itemTimestamp))
|
||||
. '</pubDate>';
|
||||
}
|
||||
|
||||
$entryDescription = '';
|
||||
if (!empty($itemContent))
|
||||
$entryDescription = '<description>' . $itemContent . '</description>';
|
||||
|
||||
$entryEnclosuresWarning = '';
|
||||
$entryEnclosures = '';
|
||||
if(isset($item['enclosures'])) {
|
||||
$entryEnclosures .= '<enclosure url="'
|
||||
. $this->xml_encode($item['enclosures'][0])
|
||||
. '" type="' . getMimeType($item['enclosures'][0]) . '" />';
|
||||
|
||||
if(count($item['enclosures']) > 1) {
|
||||
$entryEnclosures .= PHP_EOL;
|
||||
$entryEnclosuresWarning = '<br>Warning:
|
||||
Some media files might not be shown to you. Consider using the ATOM format instead!';
|
||||
foreach($item['enclosures'] as $enclosure) {
|
||||
$entryEnclosures .= '<atom:link rel="enclosure" href="'
|
||||
. $enclosure . '" type="' . getMimeType($enclosure) . '" />'
|
||||
. PHP_EOL;
|
||||
}
|
||||
}
|
||||
foreach($item->getEnclosures() as $enclosure) {
|
||||
$entryEnclosures .= '<media:content url="'
|
||||
. $this->xml_encode($enclosure)
|
||||
. '" type="' . getMimeType($enclosure) . '"/>'
|
||||
. PHP_EOL;
|
||||
}
|
||||
|
||||
$entryCategories = '';
|
||||
if(isset($item['categories'])) {
|
||||
|
||||
foreach($item['categories'] as $category) {
|
||||
$entryCategories .= '<category>'
|
||||
. $category . '</category>'
|
||||
. PHP_EOL;
|
||||
}
|
||||
foreach($item->getCategories() as $category) {
|
||||
$entryCategories .= '<category>'
|
||||
. $category . '</category>'
|
||||
. PHP_EOL;
|
||||
}
|
||||
|
||||
$items .= <<<EOD
|
||||
|
||||
<item>
|
||||
<title>{$itemTitle}</title>
|
||||
<link>{$itemUri}</link>
|
||||
<guid isPermaLink="true">{$itemUri}</guid>
|
||||
<pubDate>{$itemTimestamp}</pubDate>
|
||||
<description>{$itemContent}{$entryEnclosuresWarning}</description>
|
||||
<author>{$itemAuthor}</author>
|
||||
{$entryTitle}
|
||||
{$entryLink}
|
||||
<guid isPermaLink="{$isPermaLink}">{$entryID}</guid>
|
||||
{$entryPublished}
|
||||
{$entryDescription}
|
||||
{$entryEnclosures}
|
||||
{$entryCategories}
|
||||
</item>
|
||||
@@ -79,22 +115,28 @@ EOD;
|
||||
|
||||
$charset = $this->getCharset();
|
||||
|
||||
/* xml attributes need to have certain characters escaped to be w3c compliant */
|
||||
$imageTitle = htmlspecialchars($title, ENT_COMPAT);
|
||||
$feedImage = '';
|
||||
if (!empty($icon) && in_array(substr($icon, -4), self::ALLOWED_IMAGE_EXT)) {
|
||||
$feedImage .= <<<EOD
|
||||
<image>
|
||||
<url>{$icon}</url>
|
||||
<title>{$title}</title>
|
||||
<link>{$uri}</link>
|
||||
</image>
|
||||
EOD;
|
||||
}
|
||||
|
||||
/* Data are prepared, now let's begin the "MAGIE !!!" */
|
||||
$toReturn = <<<EOD
|
||||
<?xml version="1.0" encoding="{$charset}"?>
|
||||
<rss version="2.0"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:media="http://search.yahoo.com/mrss/"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{$title}</title>
|
||||
<link>http{$https}://{$httpHost}{$httpInfo}/</link>
|
||||
<link>{$uri}</link>
|
||||
<description>{$title}</description>
|
||||
<image url="{$icon}" title="{$imageTitle}" link="{$uri}"/>
|
||||
<atom:link rel="alternate" type="text/html" href="{$uri}" />
|
||||
<atom:link rel="self" href="http{$https}://{$httpHost}{$serverRequestUri}" />
|
||||
{$feedImage}
|
||||
<atom:link rel="alternate" type="text/html" href="{$uri}"/>
|
||||
<atom:link rel="self" href="{$feedUrl}" type="application/atom+xml"/>
|
||||
{$items}
|
||||
</channel>
|
||||
</rss>
|
||||
|
@@ -4,10 +4,15 @@
|
||||
* Returns $this->items as raw php data.
|
||||
*/
|
||||
class PlaintextFormat extends FormatAbstract {
|
||||
|
||||
public function stringify(){
|
||||
$items = $this->getItems();
|
||||
$toReturn = print_r($items, true);
|
||||
$data = array();
|
||||
|
||||
foreach($items as $item) {
|
||||
$data[] = $item->toArray();
|
||||
}
|
||||
|
||||
$toReturn = print_r($data, true);
|
||||
|
||||
// Remove invalid non-UTF8 characters
|
||||
ini_set('mbstring.substitute_character', 'none');
|
||||
|
262
index.php
262
index.php
@@ -51,263 +51,15 @@ $whitelist_default = array(
|
||||
try {
|
||||
|
||||
Bridge::setWhitelist($whitelist_default);
|
||||
$actionFac = new \ActionFactory();
|
||||
$actionFac->setWorkingDir(PATH_LIB_ACTIONS);
|
||||
|
||||
$showInactive = filter_input(INPUT_GET, 'show_inactive', FILTER_VALIDATE_BOOLEAN);
|
||||
$action = array_key_exists('action', $params) ? $params['action'] : null;
|
||||
$bridge = array_key_exists('bridge', $params) ? $params['bridge'] : null;
|
||||
|
||||
// Return list of bridges as JSON formatted text
|
||||
if($action === 'list') {
|
||||
|
||||
$list = new StdClass();
|
||||
$list->bridges = array();
|
||||
$list->total = 0;
|
||||
|
||||
foreach(Bridge::getBridgeNames() as $bridgeName) {
|
||||
|
||||
$bridge = Bridge::create($bridgeName);
|
||||
|
||||
if($bridge === false) { // Broken bridge, show as inactive
|
||||
|
||||
$list->bridges[$bridgeName] = array(
|
||||
'status' => 'inactive'
|
||||
);
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
$status = Bridge::isWhitelisted($bridgeName) ? 'active' : 'inactive';
|
||||
|
||||
$list->bridges[$bridgeName] = array(
|
||||
'status' => $status,
|
||||
'uri' => $bridge->getURI(),
|
||||
'name' => $bridge->getName(),
|
||||
'icon' => $bridge->getIcon(),
|
||||
'parameters' => $bridge->getParameters(),
|
||||
'maintainer' => $bridge->getMaintainer(),
|
||||
'description' => $bridge->getDescription()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$list->total = count($list->bridges);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($list, JSON_PRETTY_PRINT);
|
||||
|
||||
} elseif($action === 'detect') {
|
||||
|
||||
$targetURL = $params['url']
|
||||
or returnClientError('You must specify a url!');
|
||||
|
||||
$format = $params['format']
|
||||
or returnClientError('You must specify a format!');
|
||||
|
||||
foreach(Bridge::getBridgeNames() as $bridgeName) {
|
||||
|
||||
if(!Bridge::isWhitelisted($bridgeName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridge = Bridge::create($bridgeName);
|
||||
|
||||
if($bridge === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridgeParams = $bridge->detectParameters($targetURL);
|
||||
|
||||
if(is_null($bridgeParams)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridgeParams['bridge'] = $bridgeName;
|
||||
$bridgeParams['format'] = $format;
|
||||
|
||||
header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301);
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
returnClientError('No bridge found for given URL: ' . $targetURL);
|
||||
|
||||
} elseif($action === 'display' && !empty($bridge)) {
|
||||
|
||||
$format = $params['format']
|
||||
or returnClientError('You must specify a format!');
|
||||
|
||||
// DEPRECATED: 'nameFormat' scheme is replaced by 'name' in format parameter values
|
||||
// this is to keep compatibility until futher complete removal
|
||||
if(($pos = strpos($format, 'Format')) === (strlen($format) - strlen('Format'))) {
|
||||
$format = substr($format, 0, $pos);
|
||||
}
|
||||
|
||||
// whitelist control
|
||||
if(!Bridge::isWhitelisted($bridge)) {
|
||||
throw new \Exception('This bridge is not whitelisted', 401);
|
||||
die;
|
||||
}
|
||||
|
||||
// Data retrieval
|
||||
$bridge = Bridge::create($bridge);
|
||||
|
||||
$noproxy = array_key_exists('_noproxy', $params) && filter_var($params['_noproxy'], FILTER_VALIDATE_BOOLEAN);
|
||||
if(defined('PROXY_URL') && PROXY_BYBRIDGE && $noproxy) {
|
||||
define('NOPROXY', true);
|
||||
}
|
||||
|
||||
// Cache timeout
|
||||
$cache_timeout = -1;
|
||||
if(array_key_exists('_cache_timeout', $params)) {
|
||||
|
||||
if(!CUSTOM_CACHE_TIMEOUT) {
|
||||
unset($params['_cache_timeout']);
|
||||
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) . '?' . http_build_query($params);
|
||||
header('Location: ' . $uri, true, 301);
|
||||
die();
|
||||
}
|
||||
|
||||
$cache_timeout = filter_var($params['_cache_timeout'], FILTER_VALIDATE_INT);
|
||||
|
||||
} else {
|
||||
$cache_timeout = $bridge->getCacheTimeout();
|
||||
}
|
||||
|
||||
// Remove parameters that don't concern bridges
|
||||
$bridge_params = array_diff_key(
|
||||
$params,
|
||||
array_fill_keys(
|
||||
array(
|
||||
'action',
|
||||
'bridge',
|
||||
'format',
|
||||
'_noproxy',
|
||||
'_cache_timeout',
|
||||
'_error_time'
|
||||
), '')
|
||||
);
|
||||
|
||||
// Remove parameters that don't concern caches
|
||||
$cache_params = array_diff_key(
|
||||
$params,
|
||||
array_fill_keys(
|
||||
array(
|
||||
'action',
|
||||
'format',
|
||||
'_noproxy',
|
||||
'_cache_timeout',
|
||||
'_error_time'
|
||||
), '')
|
||||
);
|
||||
|
||||
// Initialize cache
|
||||
$cache = Cache::create('FileCache');
|
||||
$cache->setPath(PATH_CACHE);
|
||||
$cache->purgeCache(86400); // 24 hours
|
||||
$cache->setParameters($cache_params);
|
||||
|
||||
$items = array();
|
||||
$infos = array();
|
||||
$mtime = $cache->getTime();
|
||||
|
||||
if($mtime !== false
|
||||
&& (time() - $cache_timeout < $mtime)
|
||||
&& !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'])) {
|
||||
$stime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||
|
||||
if($mtime <= $stime) { // Cached data is older or same
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s ', $mtime) . 'GMT', true, 304);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
$cached = $cache->loadData();
|
||||
|
||||
if(isset($cached['items']) && isset($cached['extraInfos'])) {
|
||||
$items = $cached['items'];
|
||||
$infos = $cached['extraInfos'];
|
||||
}
|
||||
|
||||
} else { // Collect new data
|
||||
|
||||
try {
|
||||
$bridge->setDatas($bridge_params);
|
||||
$bridge->collectData();
|
||||
|
||||
$items = $bridge->getItems();
|
||||
$infos = array(
|
||||
'name' => $bridge->getName(),
|
||||
'uri' => $bridge->getURI(),
|
||||
'icon' => $bridge->getIcon()
|
||||
);
|
||||
} catch(Error $e) {
|
||||
error_log($e);
|
||||
|
||||
$item = array();
|
||||
|
||||
// Create "new" error message every 24 hours
|
||||
$params['_error_time'] = urlencode((int)(time() / 86400));
|
||||
|
||||
// Error 0 is a special case (i.e. "trying to get property of non-object")
|
||||
if($e->getCode() === 0) {
|
||||
$item['title'] = 'Bridge encountered an unexpected situation! (' . $params['_error_time'] . ')';
|
||||
} else {
|
||||
$item['title'] = 'Bridge returned error ' . $e->getCode() . '! (' . $params['_error_time'] . ')';
|
||||
}
|
||||
|
||||
$item['uri'] = (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
|
||||
. '?' . http_build_query($params);
|
||||
$item['timestamp'] = time();
|
||||
$item['content'] = buildBridgeException($e, $bridge);
|
||||
|
||||
$items[] = $item;
|
||||
} catch(Exception $e) {
|
||||
error_log($e);
|
||||
|
||||
$item = array();
|
||||
|
||||
// Create "new" error message every 24 hours
|
||||
$params['_error_time'] = urlencode((int)(time() / 86400));
|
||||
|
||||
$item['uri'] = (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
|
||||
. '?' . http_build_query($params);
|
||||
$item['title'] = 'Bridge returned error ' . $e->getCode() . '! (' . $params['_error_time'] . ')';
|
||||
$item['timestamp'] = time();
|
||||
$item['content'] = buildBridgeException($e, $bridge);
|
||||
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
// Store data in cache
|
||||
$cache->saveData(array(
|
||||
'items' => $items,
|
||||
'extraInfos' => $infos
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
// Data transformation
|
||||
try {
|
||||
$format = Format::create($format);
|
||||
$format->setItems($items);
|
||||
$format->setExtraInfos($infos);
|
||||
$format->setLastModified($cache->getTime());
|
||||
$format->display();
|
||||
} catch(Error $e) {
|
||||
error_log($e);
|
||||
header('Content-Type: text/html', true, $e->getCode());
|
||||
die(buildTransformException($e, $bridge));
|
||||
} catch(Exception $e) {
|
||||
error_log($e);
|
||||
header('Content-Type: text/html', true, $e->getCode());
|
||||
die(buildTransformException($e, $bridge));
|
||||
}
|
||||
if(array_key_exists('action', $params)) {
|
||||
$action = $actionFac->create($params['action']);
|
||||
$action->setUserData($params);
|
||||
$action->execute();
|
||||
} else {
|
||||
$showInactive = filter_input(INPUT_GET, 'show_inactive', FILTER_VALIDATE_BOOLEAN);
|
||||
echo BridgeList::create($showInactive);
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
|
33
lib/ActionAbstract.php
Normal file
33
lib/ActionAbstract.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract class for action objects
|
||||
*/
|
||||
abstract class ActionAbstract implements ActionInterface {
|
||||
/**
|
||||
* Holds the user data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $userData = null;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $userData {@inheritdoc}
|
||||
*/
|
||||
public function setUserData($userData) {
|
||||
$this->userData = $userData;
|
||||
}
|
||||
}
|
65
lib/ActionFactory.php
Normal file
65
lib/ActionFactory.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
/**
|
||||
* Factory for action objects.
|
||||
*/
|
||||
class ActionFactory extends FactoryAbstract {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $name {@inheritdoc}
|
||||
*/
|
||||
public function create($name) {
|
||||
$filePath = $this->buildFilePath($name);
|
||||
|
||||
if(!file_exists($filePath)) {
|
||||
throw new \Exception('File ' . $filePath . ' does not exist!');
|
||||
}
|
||||
|
||||
require_once $filePath;
|
||||
|
||||
$class = $this->buildClassName($name);
|
||||
|
||||
if((new \ReflectionClass($class))->isInstantiable()) {
|
||||
return new $class();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build class name from action name
|
||||
*
|
||||
* The class name consists of the action name with prefix "Action". The first
|
||||
* character of the class name must be uppercase.
|
||||
*
|
||||
* Example: 'display' => 'DisplayAction'
|
||||
*
|
||||
* @param string $name The action name.
|
||||
* @return string The class name.
|
||||
*/
|
||||
protected function buildClassName($name) {
|
||||
return ucfirst(strtolower($name)) . 'Action';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build file path to the action class.
|
||||
*
|
||||
* @param string $name The action name.
|
||||
* @return string Path to the action class.
|
||||
*/
|
||||
protected function buildFilePath($name) {
|
||||
return $this->getWorkingDir() . $this->buildClassName($name) . '.php';
|
||||
}
|
||||
}
|
34
lib/ActionInterface.php
Normal file
34
lib/ActionInterface.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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.
|
||||
*
|
||||
* For the full license information, please view the UNLICENSE file distributed
|
||||
* with this source code.
|
||||
*
|
||||
* @package Core
|
||||
* @license http://unlicense.org/ UNLICENSE
|
||||
* @link https://github.com/rss-bridge/rss-bridge
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for action objects.
|
||||
*/
|
||||
interface ActionInterface {
|
||||
/**
|
||||
* Set user data for the action to consume.
|
||||
*
|
||||
* @param array $userData An associative array of user data.
|
||||
* @return void
|
||||
*/
|
||||
function setUserData($userData);
|
||||
|
||||
/**
|
||||
* Execute the action.
|
||||
*
|
||||
* Note: This function directly outputs data to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function execute();
|
||||
}
|
@@ -31,7 +31,6 @@
|
||||
* utilized for limiting access to authorized users only.
|
||||
*/
|
||||
class Authentication {
|
||||
|
||||
/**
|
||||
* Throw an exception when trying to create a new instance of this class.
|
||||
* Use {@see Authentication::showPromptIfNeeded()} instead!
|
||||
@@ -83,5 +82,4 @@ class Authentication {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -213,7 +213,7 @@ class Bridge {
|
||||
// Create initial whitelist or load from disk
|
||||
if (!file_exists(WHITELIST) && !empty(self::$whitelist)) {
|
||||
file_put_contents(WHITELIST, implode("\n", self::$whitelist));
|
||||
} else {
|
||||
} elseif(file_exists(WHITELIST)) {
|
||||
|
||||
$contents = trim(file_get_contents(WHITELIST));
|
||||
|
||||
|
@@ -290,5 +290,4 @@ abstract class BridgeAbstract implements BridgeInterface {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@
|
||||
* @todo Return error if a caller creates an object of this class.
|
||||
*/
|
||||
final class BridgeCard {
|
||||
|
||||
/**
|
||||
* Build a HTML document string of buttons for each of the provided formats
|
||||
*
|
||||
@@ -208,6 +207,11 @@ This bridge is not fetching its content through a secure connection</div>';
|
||||
* @return string The list input field
|
||||
*/
|
||||
private static function getListInput($entry, $id, $name) {
|
||||
if(isset($entry['required']) && $entry['required'] === true) {
|
||||
Debug::log('The "required" attribute is not supported for lists.');
|
||||
unset($entry['required']);
|
||||
}
|
||||
|
||||
$list = '<select '
|
||||
. self::getInputAttributes($entry)
|
||||
. ' id="'
|
||||
@@ -268,6 +272,11 @@ This bridge is not fetching its content through a secure connection</div>';
|
||||
* @return string The checkbox input field
|
||||
*/
|
||||
private static function getCheckboxInput($entry, $id, $name) {
|
||||
if(isset($entry['required']) && $entry['required'] === true) {
|
||||
Debug::log('The "required" attribute is not supported for checkboxes.');
|
||||
unset($entry['required']);
|
||||
}
|
||||
|
||||
return '<input '
|
||||
. self::getInputAttributes($entry)
|
||||
. ' id="'
|
||||
|
@@ -53,7 +53,6 @@
|
||||
* The default cache timeout for the bridge.
|
||||
*/
|
||||
interface BridgeInterface {
|
||||
|
||||
/**
|
||||
* Collects data from the site
|
||||
*/
|
||||
|
@@ -20,7 +20,6 @@
|
||||
* @todo Return error if a caller creates an object of this class.
|
||||
*/
|
||||
final class BridgeList {
|
||||
|
||||
/**
|
||||
* Get the document head
|
||||
*
|
||||
|
@@ -64,6 +64,8 @@ class Cache {
|
||||
* @return object|bool The cache object or false if the class is not instantiable.
|
||||
*/
|
||||
public static function create($name){
|
||||
$name = self::sanitizeCacheName($name) . 'Cache';
|
||||
|
||||
if(!self::isCacheName($name)) {
|
||||
throw new \InvalidArgumentException('Cache name invalid!');
|
||||
}
|
||||
@@ -137,4 +139,75 @@ class Cache {
|
||||
public static function isCacheName($name){
|
||||
return is_string($name) && preg_match('/^[A-Z][a-zA-Z0-9-]*$/', $name) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of cache names from the working directory.
|
||||
*
|
||||
* The list is cached internally to allow for successive calls.
|
||||
*
|
||||
* @return array List of cache names
|
||||
*/
|
||||
public static function getCacheNames(){
|
||||
|
||||
static $cacheNames = array(); // Initialized on first call
|
||||
|
||||
if(empty($cacheNames)) {
|
||||
$files = scandir(self::getWorkingDir());
|
||||
|
||||
if($files !== false) {
|
||||
foreach($files as $file) {
|
||||
if(preg_match('/^([^.]+)Cache\.php$/U', $file, $out)) {
|
||||
$cacheNames[] = $out[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cacheNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sanitized cache name.
|
||||
*
|
||||
* The cache name can be specified in various ways:
|
||||
* * The PHP file name (i.e. `FileCache.php`)
|
||||
* * The PHP file name without file extension (i.e. `FileCache`)
|
||||
* * The cache name (i.e. `file`)
|
||||
*
|
||||
* Casing is ignored (i.e. `FILE` and `fIlE` are the same).
|
||||
*
|
||||
* A cache file matching the given cache name must exist in the working
|
||||
* directory!
|
||||
*
|
||||
* @param string $name The cache name
|
||||
* @return string|null The sanitized cache name if the provided name is
|
||||
* valid, null otherwise.
|
||||
*/
|
||||
protected static function sanitizeCacheName($name) {
|
||||
|
||||
if(is_string($name)) {
|
||||
|
||||
// Trim trailing '.php' if exists
|
||||
if(preg_match('/(.+)(?:\.php)/', $name, $matches)) {
|
||||
$name = $matches[1];
|
||||
}
|
||||
|
||||
// Trim trailing 'Cache' if exists
|
||||
if(preg_match('/(.+)(?:Cache)$/i', $name, $matches)) {
|
||||
$name = $matches[1];
|
||||
}
|
||||
|
||||
// The name is valid if a corresponding file is found on disk
|
||||
if(in_array(strtolower($name), array_map('strtolower', self::getCacheNames()))) {
|
||||
$index = array_search(strtolower($name), array_map('strtolower', self::getCacheNames()));
|
||||
return self::getCacheNames()[$index];
|
||||
}
|
||||
|
||||
Debug::log('Invalid cache name specified: "' . $name . '"!');
|
||||
|
||||
}
|
||||
|
||||
return null; // Bad parameter
|
||||
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user