Merge pull request #167 from teromene/new-attribute-system

New attribute system
This commit is contained in:
Mitsu 2015-11-03 17:28:20 +01:00
commit 98b2019831
15 changed files with 417 additions and 325 deletions

23
CREATE_BRIDGE.md Normal file
View file

@ -0,0 +1,23 @@
# Howto create a bridge
A bridge is an interface that allows rss-bridge to create a RSS feed from a website.
The bridge is a PHP file, located in the `bridges/` folder.
##Specifications
A rss bridge must extend the `BridgeAbstract` class, and implement the following functions :
* The `loadMetadatas` function, described below,
* The `getCacheDuration` function, describing the time during which rss-bridge will output cached values instead of re-generating a RSS feed.
* The `collectData` function, also described below.
##The `collectData` function
This function takes as a parameter an array called `$param`, that is automatically filled with values from the user, according to the values setted in `loadMetadatas`.
This function is the place where all the website scrapping and the RSS feed generation process will go.
The RSS elements are stored in the class variable `items[]`.
Every RSS element is an instance of the `Item` class.

View file

@ -1,6 +1,6 @@
<?php <?php
/** /**
* 2014-05-25 *
* @name Acrimed Bridge * @name Acrimed Bridge
* @homepage http://www.acrimed.org/ * @homepage http://www.acrimed.org/
* @description Returns the newest articles. * @description Returns the newest articles.
@ -8,7 +8,16 @@
*/ */
class AcrimedBridge extends BridgeAbstract{ class AcrimedBridge extends BridgeAbstract{
public function collectData(array $param){ public function loadMetadatas() {
$this->maintainer = "qwertygc";
$this->name = "Acrimed Bridge";
$this->uri = "http://www.acrimed.org/";
$this->description = "Returns the newest articles.";
$this->update = "2014-05-25";
}
public function collectData(array $param){
function StripCDATA($string) { function StripCDATA($string) {
$string = str_replace('<![CDATA[', '', $string); $string = str_replace('<![CDATA[', '', $string);
@ -37,13 +46,6 @@ class AcrimedBridge extends BridgeAbstract{
} }
public function getName(){
return 'Acrimed Bridge';
}
public function getURI(){
return 'http://acrimed.org/';
}
public function getCacheDuration(){ public function getCacheDuration(){
return 3600*2; // 2 hours return 3600*2; // 2 hours

View file

@ -5,10 +5,10 @@
* *
* @name Anime-Ultime * @name Anime-Ultime
* @homepage http://www.anime-ultime.net/ * @homepage http://www.anime-ultime.net/
* @description Returns the 10 newest releases posted on Anime-Ultime <br /> Type = A (Anime), D (Drama), T (Tokusatsu), or leave empty for everything * @description Returns the 10 newest releases posted on Anime-Ultime
* @maintainer ORelio * @maintainer ORelio
* @update 2015-09-07 * @update 2015-10-30
* @use1(type="A/D/T/Empty") * @use1(list|type="everything=>;Anime=>A;Drama=>D;Tokusatsu=>T")
*/ */
class AnimeUltimeBridge extends BridgeAbstract { class AnimeUltimeBridge extends BridgeAbstract {

113
bridges/Arte7Bridge.php Normal file
View file

@ -0,0 +1,113 @@
<?php
/**
* RssBridgeArte7
*
* @name Arte +7
* @homepage http://www.arte.tv/
* @description Returns newest videos from ARTE +7
* @maintainer mitsukarenai
* @update 2015-10-31
* @use1(list|catfr="Toutes les vidéos (français)=>toutes-les-videos;Actu & société=>actu-société;Séries & fiction=>séries-fiction;Cinéma=>cinéma;Arts & spectacles classiques=>arts-spectacles-classiques;Culture pop=>culture-pop;Découverte=>découverte;Histoire=>histoire;Junior=>junior")
* @use2(list|catde="Alle Videos (deutsch)=>alle-videos;Aktuelles & Gesellschaft=>aktuelles-gesellschaft;Fernsehfilme & Serien=>fernsehfilme-serien;Kino=>kino;Kunst & Kultur=>kunst-kultur;Popkultur & Alternativ=>popkultur-alternativ;Entdeckung=>entdeckung;Geschichte=>geschichte;Junior=>junior")
*/
class Arte7Bridge extends BridgeAbstract{
public function loadMetadatas() {
$this->maintainer = "mitsukarenai";
$this->name = "Arte +7";
$this->uri = "http://www.arte.tv/";
$this->description = "Returns newest videos from ARTE +7";
$this->update = "2015-10-31";
$this->parameters["Catégorie (Français)"] =
'[
{
"type" : "list",
"identifier" : "catfr",
"name" : "Catégorie",
"values" : [
{
"name" : "Toutes les vidéos (français)",
"value" : "toutes-les-videos"
},
{
"name" : "Actu & société",
"value" : "actu-société"
},
{
"name" : "Séries & fiction",
"value" : "séries-fiction"
},
{
"name" : "Cinéma",
"value" : "cinéma"
}
]
}
]';
}
public function collectData(array $param){
function extractVideoset($category='toutes-les-videos', $lang='fr')
{
$url = 'http://www.arte.tv/guide/'.$lang.'/plus7/'.$category;
$input = file_get_contents($url) or die('Could not request ARTE.');
if(strpos($input, 'categoryVideoSet') !== FALSE)
{
$input = explode('categoryVideoSet: ', $input);
$input = explode('}},', $input[1]);
$input = $input[0].'}}';
}
else
{
$input = explode('videoSet: ', $input);
$input = explode('}]},', $input[1]);
$input = $input[0].'}]}';
}
$input = json_decode($input, TRUE);
return $input;
}
$category='toutes-les-videos'; $lang='fr';
if (!empty($param['catfr']))
$category=$param['catfr'];
if (!empty($param['catde']))
{ $category=$param['catde']; $lang='de'; }
$input_json = extractVideoset($category, $lang);
foreach($input_json['videos'] as $element) {
$item = new \Item();
$item->uri = $element['url'];
$item->id = $element['id'];
$hack_broadcast_time = $element['rights_end'];
$hack_broadcast_time = strtok($hack_broadcast_time, 'T');
$hack_broadcast_time = strtok('T');
$item->timestamp = strtotime($element['scheduled_on'].'T'.$hack_broadcast_time);
$item->thumbnailUri = $element['thumbnail_url'];
$item->title = $element['title'];
if (!empty($element['subtitle']))
$item->title = $element['title'].' | '.$element['subtitle'];
$item->duration = round((int)$element['duration']/60);
$item->content = $element['teaser'].'<br><br>'.$item->duration.'min<br><a href="'.$item->uri.'"><img src="' . $item->thumbnailUri . '" /></a>';
$this->items[] = $item;
}
}
public function getName(){
return 'Arte7';
}
public function getURI(){
return 'http://www.arte.tv/';
}
public function getCacheDuration(){
return 1800; // 30 minutes
}
}

View file

@ -1,71 +0,0 @@
<?php
/**
* RssBridgeArte7de
* Returns images from given page and tags
*
* @name Arte +7 DE
* @homepage http://www.arte.tv/guide/de/plus7
* @description Returns newest videos from ARTE +7 (german)
* @maintainer mitsukarenai
* @update 2015-10-30
* @use1(list|cat="Alle Videos=>alle-videos;Aktuelles & Gesellschaft=>aktuelles-gesellschaft;Fernsehfilme & Serien=>fernsehfilme-serien;Kino=>kino;Kunst & Kultur=>kunst-kultur;Popkultur & Alternativ=>popkultur-alternativ;Entdeckung=>entdeckung;Geschichte=>geschichte;Junior=>junior")
*/
class Arte7deBridge extends BridgeAbstract{
public function collectData(array $param){
function extractVideoset($category='alle-videos')
{
$url = 'http://www.arte.tv/guide/de/plus7/'.$category;
$input = file_get_contents($url) or die('Could not request ARTE.');
if(strpos($input, 'categoryVideoSet') !== FALSE)
{
$input = explode('categoryVideoSet: ', $input);
$input = explode('}},', $input[1]);
$input = $input[0].'}}';
}
else
{
$input = explode('videoSet: ', $input);
$input = explode('}]},', $input[1]);
$input = $input[0].'}]}';
}
$input = json_decode($input, TRUE);
return $input;
}
$category='alle-videos';
if (!empty($param['cat']))
$category=$param['cat'];
$input_json = extractVideoset($category);
foreach($input_json['videos'] as $element) {
$item = new \Item();
$item->uri = $element['url'];
$item->id = $element['id'];
$hack_broadcast_time = $element['rights_end'];
$hack_broadcast_time = strtok($hack_broadcast_time, 'T');
$hack_broadcast_time = strtok('T');
$item->timestamp = strtotime($element['scheduled_on'].'T'.$hack_broadcast_time);
$item->thumbnailUri = $element['thumbnail_url'];
$item->title = $element['title'];
if (!empty($element['subtitle']))
$item->title = $element['title'].' | '.$element['subtitle'];
$item->duration = round((int)$element['duration']/60);
$item->content = $element['teaser'].'<br><br>'.$item->duration.'min<br><a href="'.$item->uri.'"><img src="' . $item->thumbnailUri . '" /></a>';
$this->items[] = $item;
}
}
public function getName(){
return 'Arte7de';
}
public function getURI(){
return 'http://www.arte.tv/';
}
public function getCacheDuration(){
return 1800; // 30 minutes
}
}

View file

@ -1,71 +0,0 @@
<?php
/**
* RssBridgeArte7fr
* Returns images from given page and tags
*
* @name Arte +7 FR
* @homepage http://www.arte.tv/guide/fr/plus7
* @description Returns newest videos from ARTE +7 (french)
* @maintainer mitsukarenai
* @update 2015-10-30
* @use1(list|cat="Toutes les vidéos=>toutes-les-videos;Actu & société=>actu-société;Séries & fiction=>séries-fiction;Cinéma=>cinéma;Arts & spectacles classiques=>arts-spectacles-classiques;Culture pop=>culture-pop;Découverte=>découverte;Histoire=>histoire;Junior=>junior")
*/
class Arte7frBridge extends BridgeAbstract{
public function collectData(array $param){
function extractVideoset($category='toutes-les-videos')
{
$url = 'http://www.arte.tv/guide/fr/plus7/'.$category;
$input = file_get_contents($url) or die('Could not request ARTE.');
if(strpos($input, 'categoryVideoSet') !== FALSE)
{
$input = explode('categoryVideoSet: ', $input);
$input = explode('}},', $input[1]);
$input = $input[0].'}}';
}
else
{
$input = explode('videoSet: ', $input);
$input = explode('}]},', $input[1]);
$input = $input[0].'}]}';
}
$input = json_decode($input, TRUE);
return $input;
}
$category='toutes-les-videos';
if (!empty($param['cat']))
$category=$param['cat'];
$input_json = extractVideoset($category);
foreach($input_json['videos'] as $element) {
$item = new \Item();
$item->uri = $element['url'];
$item->id = $element['id'];
$hack_broadcast_time = $element['rights_end'];
$hack_broadcast_time = strtok($hack_broadcast_time, 'T');
$hack_broadcast_time = strtok('T');
$item->timestamp = strtotime($element['scheduled_on'].'T'.$hack_broadcast_time);
$item->thumbnailUri = $element['thumbnail_url'];
$item->title = $element['title'];
if (!empty($element['subtitle']))
$item->title = $element['title'].' | '.$element['subtitle'];
$item->duration = round((int)$element['duration']/60);
$item->content = $element['teaser'].'<br><br>'.$item->duration.'min<br><a href="'.$item->uri.'"><img src="' . $item->thumbnailUri . '" /></a>';
$this->items[] = $item;
}
}
public function getName(){
return 'Arte7fr';
}
public function getURI(){
return 'http://www.arte.tv/';
}
public function getCacheDuration(){
return 1800; // 30 minutes
}
}

72
bridges/DemoBridge.php Normal file
View file

@ -0,0 +1,72 @@
<?php
/**
* ABCTabsBridge
* Returns the newest tabs
*
* @name ABC Tabs Bridge
* @homepage http://www.abc-tabs.com/
* @description Returns 22 newest tabs
* @maintainer kranack
* @update 2014-07-23
*
*/
class DemoBridge extends BridgeAbstract{
public function loadMetadatas() {
$this->maintainer = "teromene";
$this->name = "DemoBridge";
$this->uri = "http://github.com/sebsauvage/rss-bridge";
$this->description = "Bridge used for demos";
$this->update = "2015-11-03";
$this->parameters['testCheckbox'] =
'[
{
"type" : "checkbox",
"identifier" : "testCheckbox",
"name" : "test des checkbox"
}
]';
$this->parameters['testList'] =
'[
{
"type" : "list",
"identifier" : "testList",
"name" : "test des listes",
"values" : [
{
"name" : "Test",
"value" : "test"
},
{
"name" : "Test 2",
"value" : "test2"
}
]
}
]';
$this->parameters['testNumber'] =
'[
{
"type" : "number",
"identifier" : "testNumber",
"name" : "test des numéros",
"exampleValue" : "1515632"
}
]';
}
public function collectData(array $param){
}
public function getCacheDuration(){
return 3600; // 1 hour
}
}

View file

@ -9,7 +9,7 @@
*/ */
class FacebookBridge extends BridgeAbstract{ class FacebookBridge extends BridgeAbstract{
private $name;
public function collectData(array $param){ public function collectData(array $param){

View file

@ -3,17 +3,13 @@
* RssBridgeLeBonCoin * RssBridgeLeBonCoin
* Search LeBonCoin for most recent ads in a specific region and topic. * Search LeBonCoin for most recent ads in a specific region and topic.
* Returns the most recent classified ads in results, sorting by date (most recent first). * Returns the most recent classified ads in results, sorting by date (most recent first).
* Region identifiers : alsace, aquitaine, auvergne, basse_normandie, bourgogne, bretagne, centre,
* champagne_ardenne, corse, franche_comte, haute_normandie, ile_de_france, languedoc_roussillon,
* limousin, lorraine, midi_pyrenees, nord_pas_de_calais, pays_de_la_loire, picardie,
* poitou_charentes, provence_alpes_cote_d_azur, rhone_alpes, guadeloupe, martinique, guyane, reunion.
* 2014-07-22
* *
* @name LeBonCoin * @name LeBonCoin
* @homepage http://www.leboncoin.fr * @homepage http://www.leboncoin.fr
* @description Returns most recent results from LeBonCoin for a region and a keyword. * @description Returns most recent results from LeBonCoin for a region and a keyword.
* @maintainer 16mhz * @maintainer 16mhz
* @use1(r="Region identifier", k="Keyword") * @update 2015-10-30
* @use1(list|r="Alsace=>alsace;Aquitaine=>aquitaine;Auvergne=>auvergne;Basse Normandie=>basse_normandie;Bourgogne=>bourgogne;Bretagne=>bretagne;Centre=>centre;Champagne Ardenne=>champagne_ardenne;Corse=>corse;Franche Comté=>franche_comte;Haute Normandie=>haute_normandie;Ile de France=>ile_de_france;Languedoc Roussillon=>languedoc_roussillon;Limousin=>limousin;Lorraine=>lorraine;Midi Pyrénées=>midi_pyrenees;Nord Pas De Calais=>nord_pas_de_calais;Pays de la Loire=>pays_de_la_loire;Picardie=>picardie;Poitou Charentes=>poitou_charentes;Provence Alpes Côte d'Azur=>provence_alpes_cote_d_azur;Rhône-Alpes=>rhone_alpes;Guadeloupe=>guadeloupe;Martinique=>martinique;Guyane=>guyane;Réunion=>reunion", text|k="Keyword")
*/ */
class LeBonCoinBridge extends BridgeAbstract{ class LeBonCoinBridge extends BridgeAbstract{

View file

@ -3,32 +3,32 @@
* RssBridgeOpenClassrooms * RssBridgeOpenClassrooms
* Retrieve lastest tutorials from OpenClassrooms. * Retrieve lastest tutorials from OpenClassrooms.
* Returns the most recent tutorials, sorting by date (most recent first). * Returns the most recent tutorials, sorting by date (most recent first).
* 2014-05-25
* *
* @name OpenClassrooms Bridge * @name OpenClassrooms Bridge
* @homepage http://fr.openclassrooms.com/ * @homepage https://openclassrooms.com/
* @description Returns latest tutorials from OpenClassrooms. * @description Returns latest tutorials from OpenClassrooms.
* @maintainer sebsauvage * @maintainer sebsauvage
* @use1(u="informatique or sciences") * @update 2015-10-30
* @use1(list|u="Arts & Culture=>arts;Code=>code;Design=>design;Entreprise=>business;Numérique=>digital;Sciences=>sciences;Sciences humaines=>humanities;Systèmes d'information=>it;Autres=>others")
*/ */
class OpenClassroomsBridge extends BridgeAbstract{ class OpenClassroomsBridge extends BridgeAbstract{
public function collectData(array $param){ public function collectData(array $param){
if ($param['u']!='informatique' && $param['u']!='sciences') if (empty($param['u']))
{ {
$this->returnError('Error: You must chose "informatique" or "science".', 404); $this->returnError('Error: You must chose a category.', 404);
} }
$html = ''; $html = '';
$link = 'http://fr.openclassrooms.com/'.$param['u'].'/cours?title=&sort=updatedAt+desc'; $link = 'https://openclassrooms.com/courses?categories='.$param['u'].'&title=&sort=updatedAt+desc';
$html = file_get_html($link) or $this->returnError('Could not request OpenClassrooms.', 404); $html = file_get_html($link) or $this->returnError('Could not request OpenClassrooms.', 404);
foreach($html->find('li.col6') as $element) { foreach($html->find('.courseListItem') as $element) {
$item = new \Item(); $item = new \Item();
$item->uri = 'http://fr.openclassrooms.com'.$element->find('a', 0)->href; $item->uri = 'https://openclassrooms.com'.$element->find('a', 0)->href;
$item->title = $element->find('div.courses-content strong', 0)->innertext; $item->title = $element->find('h3', 0)->plaintext;
$item->content = $element->find('span.course-tags', 0)->innertext; $item->content = $element->find('slidingItem__descriptionContent', 0)->plaintext;
$this->items[] = $item; $this->items[] = $item;
} }
} }
@ -38,7 +38,7 @@ class OpenClassroomsBridge extends BridgeAbstract{
} }
public function getURI(){ public function getURI(){
return 'http://fr.openclassrooms.com'; return 'https://openclassrooms.com/';
} }
public function getCacheDuration(){ public function getCacheDuration(){

View file

@ -9,8 +9,8 @@
* @description Returns the newest broadcasts or highlights by channel name using the Twitch API (v3) * @description Returns the newest broadcasts or highlights by channel name using the Twitch API (v3)
* @maintainer logmanoriginal * @maintainer logmanoriginal
* @update 2015-07-14 * @update 2015-07-14
* @use1(channel="Channel", broadcasts="true|false") * @use1(text|channel="Channel", list|broadcasts="Show broadcasts=>true;Don't show broadcasts=>false")
* @use2(channel="Channel", limit="Limit", broadcasts="true|false") * @use2(text|channel="Channel", text|limit="Limit", list|broadcasts="Show broadcasts=>true;Don't show broadcasts=>false")
* *
* Description for the API is available on GitHub: https://github.com/justintv/twitch-api * Description for the API is available on GitHub: https://github.com/justintv/twitch-api
*/ */

View file

@ -2,9 +2,9 @@
/** /**
* *
* @name World of Tanks * @name World of Tanks
* @description News about the tank slaughter game. Language can be fr, ? * @description News about the tank slaughter game.
* @update 2015-09-12 * @update 2015-09-12
* @use1(lang="Searched language",category="Category id") * @use1(list|lang="Français=>fr;English=>en;Español=>es;Deutsch=>de;Čeština=>cs;Polski=>pl;Türkçe=>tr",text|category="Category id")
*/ */
define('WORLD_OF_TANKS', 'http://worldoftanks.eu/'); define('WORLD_OF_TANKS', 'http://worldoftanks.eu/');
define('NEWS', '/news/'); define('NEWS', '/news/');

View file

@ -2,24 +2,69 @@
/** /**
* RssBridgeYoutube * RssBridgeYoutube
* Returns the newest videos * Returns the newest videos
*
* @name Youtube Bridge
* @homepage https://www.youtube.com/
* @description Returns the 10 newest videos by username/channel/playlist or search
* @maintainer mitsukarenai
* @update 2015-07-08
* @use1(u="username")
* @use2(c="channel id")
* @use3(p="playlist id")
* @use4(s="search keyword",pa="page")
*
* WARNING: to parse big playlists (over ~90 videos), you need to edit simple_html_dom.php: * WARNING: to parse big playlists (over ~90 videos), you need to edit simple_html_dom.php:
* change: define('MAX_FILE_SIZE', 600000); * change: define('MAX_FILE_SIZE', 600000);
* into: define('MAX_FILE_SIZE', 900000); (or more) * into: define('MAX_FILE_SIZE', 900000); (or more)
*/ */
class YoutubeBridge extends BridgeAbstract{ class YoutubeBridge extends BridgeAbstract {
private $request;
public function loadMetadatas() {
$this->name = "Youtube Bridge";
$this->homepage = "https://youtube.com";
$this->description = "Returns the 10 newest videos by username/channel/playlist or search";
$this->maintainer = "mitsukarenai";
$this->parameters["By username"] =
'[
{
"type" : "text",
"identifier" : "u",
"name" : "username",
"exampleValue" : "test"
}
]';
$this->parameters['By channel id'] =
'[
{
"type" : "number",
"identifier" : "c",
"name" : "channel id",
"exampleValue" : "15"
}
]';
$this->parameters['By playlist Id'] =
'[
{
"type" : "number",
"identifier" : "c",
"name" : "playlist id",
"exampleValue" : "15"
}
]';
$this->parameters["Search result"] =
'[
{
"type" : "text",
"identifier" : "s",
"name" : "search keyword",
"exampleValue" : "test"
},
{
"type" : "number",
"identifier" : "pa",
"name" : "page",
"exampleValue" : "1"
}
]';
}
public function collectData(array $param){ public function collectData(array $param){

154
index.php
View file

@ -1,4 +1,5 @@
<?php <?php
$time_start = microtime(true);
/* /*
TODO : TODO :
- manage SSL detection because if library isn't loaded, some bridge crash ! - manage SSL detection because if library isn't loaded, some bridge crash !
@ -13,7 +14,7 @@ TODO :
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
error_reporting(0); error_reporting(0);
//ini_set('display_errors','1'); error_reporting(E_ALL); // For debugging only. ini_set('display_errors','1'); error_reporting(E_ALL); // For debugging only.
// extensions check // extensions check
if (!extension_loaded('openssl')) if (!extension_loaded('openssl'))
@ -52,6 +53,7 @@ if (!file_exists($whitelist_file)) {
} }
else { else {
$whitelist_selection = explode("\n", file_get_contents($whitelist_file)); $whitelist_selection = explode("\n", file_get_contents($whitelist_file));
array_pop($whitelist_selection);
} }
// whitelist control function // whitelist control function
@ -94,14 +96,14 @@ try{
$bridge->setCache($cache); // just add disable cache to your query to disable caching $bridge->setCache($cache); // just add disable cache to your query to disable caching
} }
$bridge->setDatas($_REQUEST); $bridge->setDatas($_REQUEST);
$bridge->loadMetadatas();
// Data transformation // Data transformation
$format = Format::create($format); $format = Format::create($format);
$format $format
->setDatas($bridge->getDatas()) ->setDatas($bridge->getDatas())
->setExtraInfos(array( ->setExtraInfos(array(
'name' => $bridge->getName(), 'name' => $bridge->name,
'uri' => $bridge->getURI(), 'uri' => $bridge->uri,
)) ))
->display(); ->display();
die; die;
@ -135,86 +137,97 @@ function getHelperButtonsFormat($formats){
return $buttons; return $buttons;
} }
function displayBridgeCard($bridgeReference, $bridgeInformations, $formats, $isActive = true) function displayBridgeCard($bridgeName, $formats, $isActive = true)
{ {
$name = isset($bridgeInformations['homepage']) ? '<a href="'.$bridgeInformations['homepage'].'">'.$bridgeInformations['name'].'</a>' : $bridgeInformations['name'];
$description = isset($bridgeInformations['description']) ? $bridgeInformations['description'] : 'No description provided'; $bridgeElement = Bridge::create($bridgeName);
$bridgeElement->loadMetadatas();
$name = '<a href="'.$bridgeElement->uri.'">'.$bridgeElement->name.'</a>';
$description = $bridgeElement->description;
$card = <<<CARD $card = <<<CARD
<section id="bridge-{$bridgeReference}" data-ref="{$bridgeReference}"> <section id="bridge-{$bridgeName}" data-ref="{$bridgeName}">
<h2>{$name}</h2> <h2>{$name}</h2>
<p class="description"> <p class="description">
{$description} {$description}
</p> </p>
CARD; CARD;
if( isset($bridgeInformations['use']) && count($bridgeInformations['use']) > 0 )
// If we don't have any parameter for the bridge, we print a generic form to load it.
if(count($bridgeElement->parameters) == 0) {
$card .= '<form method="POST" action="?">
<input type="hidden" name="action" value="display" />
<input type="hidden" name="bridge" value="' . $bridgeName . '" />' . PHP_EOL;
if ($isActive)
{ {
$card .= '<ol class="list-use">' . PHP_EOL; $card .= getHelperButtonsFormat($formats);
foreach($bridgeInformations['use'] as $anUseNum => $anUse)
{
$card .= '<li data-use="' . $anUseNum . '">' . PHP_EOL;
$card .= '<form method="GET" action="?">
<input type="hidden" name="action" value="display" />
<input type="hidden" name="bridge" value="' . $bridgeReference . '" />' . PHP_EOL;
foreach($anUse as $argValue)
{
$idArg = 'arg-' . $bridgeReference . '-' . $anUseNum . '-' . $argValue['query-name'];
if($argValue['type'] == null || $argValue['type'] == "text") { //If we have no type, treat it as a text field for compatibility
$card .= '<input id="' . $idArg . '" type="text" value="" placeholder="' . $argValue['value'] . '" name="' . $argValue['query-name'] . '" />' . PHP_EOL;
} else if($argValue['type'] == "list") {
$card .= '<select id="' . $idArg . '" name="' . $argValue['query-name'] . '" >' . PHP_EOL;
$optionList = explode(";", $argValue['value']);
foreach($optionList as $option) {
$option = explode("=>", $option);
$card .= "<option value='".$option[1]."'>".$option[0]."</option>";
}
$card .= "</select>";
}
}
$card .= '<br />';
if ($isActive)
{
$card .= getHelperButtonsFormat($formats);
}
else
{
$card .= '<span style="font-weight: bold;">Inactive</span>';
}
$card .= '</form></li>' . PHP_EOL;
}
$card .= '</ol>' . PHP_EOL;
} }
else else
{ {
$card .= '<form method="GET" action="?"> $card .= '<span style="font-weight: bold;">Inactive</span>';
<input type="hidden" name="action" value="display" />
<input type="hidden" name="bridge" value="' . $bridgeReference . '" />' . PHP_EOL;
if ($isActive)
{
$card .= getHelperButtonsFormat($formats);
}
else
{
$card .= '<span style="font-weight: bold;">Inactive</span>';
}
$card .= '</form>' . PHP_EOL;
} }
$card .= '</form>' . PHP_EOL;
}
$card .= isset($bridgeInformations['maintainer']) ? '<span class="maintainer">'.$bridgeInformations['maintainer'].'</span>' : ''; foreach($bridgeElement->parameters as $parameterName => $parameter)
{
$card .= '<ol class="list-use">' . PHP_EOL;
$card .= '<h5>'.$parameterName.'</h5>' . PHP_EOL;
$card .= '<form method="POST" action="?">
<input type="hidden" name="action" value="display" />
<input type="hidden" name="bridge" value="' . $bridgeName . '" />' . PHP_EOL;
$parameter = json_decode($parameter, true);
foreach($parameter as $inputEntry) {
$idArg = 'arg-' . $bridgeName . '-' . $parameterName . '-' . $inputEntry['identifier'];
$card .= '<label for="' .$idArg. '">' .$inputEntry['name']. ' : </label>' . PHP_EOL;
if(!isset($inputEntry['type']) || $inputEntry['type'] == 'text') {
$card .= '<input id="' . $idArg . '" type="text" value="" placeholder="' . $inputEntry['exampleValue'] . '" name="' . $inputEntry['identifier'] . '" /><br />' . PHP_EOL;
} else if($inputEntry['type'] == 'number') {
$card .= '<input id="' . $idArg . '" type="number" value="" placeholder="' . $inputEntry['exampleValue'] . '" name="' . $inputEntry['identifier'] . '" /><br />' . PHP_EOL;
} else if($inputEntry['type'] == 'list') {
$card .= '<select id="' . $idArg . '" name="' . $inputEntry['name'] . '" >';
foreach($inputEntry['values'] as $listValues) {
$card .= "<option value='" . $listValues['value'] . "'>" . $listValues['name'] . "</option>";
}
$card .= '</select><br >';
} else if($inputEntry['type'] == 'checkbox') {
$card .= '<input id="' . $idArg . '" type="checkbox" name="' . $inputEntry['identifier'] . '" /><br />' . PHP_EOL;
}
}
if ($isActive)
{
$card .= getHelperButtonsFormat($formats);
}
else
{
$card .= '<span style="font-weight: bold;">Inactive</span>';
}
$card .= '</form>' . PHP_EOL;
}
$card .= '<span class="maintainer">'.$bridgeElement->maintainer.'</span>';
$card .= '</section>'; $card .= '</section>';
return $card; return $card;
} }
$bridges = Bridge::searchInformation();
$formats = Format::searchInformation(); $formats = Format::searchInformation();
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -239,24 +252,27 @@ $formats = Format::searchInformation();
$activeFoundBridgeCount = 0; $activeFoundBridgeCount = 0;
$showInactive = isset($_REQUEST['show_inactive']) && $_REQUEST['show_inactive'] == 1; $showInactive = isset($_REQUEST['show_inactive']) && $_REQUEST['show_inactive'] == 1;
$inactiveBridges = ''; $inactiveBridges = '';
foreach($bridges as $bridgeReference => $bridgeInformations) foreach(Bridge::listBridges() as $bridgeName)
{ {
if(BridgeWhitelist($whitelist_selection, $bridgeReference)) if(BridgeWhitelist($whitelist_selection, $bridgeName))
{ {
echo displayBridgeCard($bridgeReference, $bridgeInformations, $formats); echo displayBridgeCard($bridgeName, $formats);
$activeFoundBridgeCount++; $activeFoundBridgeCount++;
} }
elseif ($showInactive) elseif ($showInactive)
{ {
// inactive bridges // inactive bridges
$inactiveBridges .= displayBridgeCard($bridgeReference, $bridgeInformations, $formats, false) . PHP_EOL; $inactiveBridges .= displayBridgeCard($bridgeName, $formats, false) . PHP_EOL;
} }
} }
echo '<hr />' . $inactiveBridges; echo '<hr />' . $inactiveBridges;
?> ?>
<footer> <footer>
<?= $activeFoundBridgeCount; ?>/<?= count($bridges) ?> active bridges (<a href="?show_inactive=1">Show inactive</a>)<br /> <?= $activeFoundBridgeCount; ?>/<?= count($whitelist_selection) ?> active bridges (<a href="?show_inactive=1">Show inactive</a>)<br />
<a href="https://github.com/sebsauvage/rss-bridge">RSS-Bridge alpha 0.1 ~ Public Domain</a> <a href="https://github.com/sebsauvage/rss-bridge">RSS-Bridge alpha 0.1 ~ Public Domain</a>
</footer> </footer>
</body> </body>
</html> </html>
<?php
echo "Ran for ". (microtime(true) - $time_start);
?>

View file

@ -6,15 +6,29 @@
interface BridgeInterface{ interface BridgeInterface{
public function collectData(array $param); public function collectData(array $param);
public function getName();
public function getURI();
public function getCacheDuration(); public function getCacheDuration();
public function loadMetadatas();
} }
abstract class BridgeAbstract implements BridgeInterface{ abstract class BridgeAbstract implements BridgeInterface{
protected $cache; protected $cache;
protected $items = array(); protected $items = array();
public $name = "Bridge sans nom";
public $uri = "";
public $description = 'No description provided';
public $maintainer = 'No maintainer';
public $parameters = array();
/**
* Loads the Bridge Metadatas
*/
public function loadMetadatas() {
}
/** /**
* Launch probative exception * Launch probative exception
*/ */
@ -30,6 +44,8 @@ abstract class BridgeAbstract implements BridgeInterface{
return $this->items; return $this->items;
} }
/** /**
* Defined datas with parameters depending choose bridge * Defined datas with parameters depending choose bridge
* Note : you can defined a cache before with "setCache" * Note : you can defined a cache before with "setCache"
@ -239,74 +255,25 @@ class Bridge{
} }
/** /**
* Read bridge dir and catch informations about each bridge depending annotation * Lists the available bridges.
* @return array Informations about each bridge * @return array List of the bridges
*/ */
static public function searchInformation(){ static public function listBridges() {
$pathDirBridge = self::getDir(); $pathDirBridge = self::getDir();
$listBridge = array(); $listBridge = array();
$dirFiles = scandir($pathDirBridge);
$searchCommonPattern = array('maintainer', 'description', 'homepage', 'name');
$dirFiles = scandir($pathDirBridge);
if( $dirFiles !== false ){ if( $dirFiles !== false ){
foreach( $dirFiles as $fileName ){ foreach( $dirFiles as $fileName ){
if( preg_match('@([^.]+)\.php@U', $fileName, $out) ){ // Is PHP file ? if( preg_match('@([^.]+)\.php@U', $fileName, $out) ){
$infos = array(); // Information about the bridge $listBridge[] = $out[1];
$resParse = token_get_all(file_get_contents($pathDirBridge . $fileName)); // Parse PHP file }
foreach($resParse as $v){ }
if( is_array($v) && $v[0] == T_DOC_COMMENT ){ // Lexer node is COMMENT ? }
$commentary = $v[1];
foreach( $searchCommonPattern as $name){ // Catch information with common pattern
preg_match('#@' . preg_quote($name, '#') . '\s+(.+)#', $commentary, $outComment);
if( isset($outComment[1]) ){
$infos[$name] = $outComment[1];
}
}
preg_match_all('#@use(?<num>[1-9][0-9]*)\s?\((?<args>.+)\)(?:\r|\n)#', $commentary, $outComment); // Catch specific information about "use". return $listBridge;
}
if( isset($outComment['args']) && is_array($outComment['args']) ){
$infos['use'] = array();
foreach($outComment['args'] as $num => $args){ // Each use
preg_match_all('#(?<type>[a-z]+)\|(?<name>[a-z]+)="(?<value>.*)"(?:,|$)#U', $args, $outArg); // Catch arguments for current use
if(!isset($outArg['name']) || count($outArg['name']) == 0) {
preg_match_all('#(?<name>[a-z]+)="(?<value>.*)"(?:,|$)#U', $args, $outArg); // Catch arguments
}
if( isset($outArg['name'])){
$usePos = $outComment['num'][$num]; // Current use name
if( !isset($infos['use'][$usePos]) ){ // Not information actually for this "use" ?
$infos['use'][$usePos] = array();
}
foreach($outArg['name'] as $numArg => $name){ // Each arguments
$infos['use'][$usePos][$name] = array();
$infos['use'][$usePos][$name]['query-name'] = $name;
$infos['use'][$usePos][$name]['value'] = $outArg['value'][$numArg];
$infos['use'][$usePos][$name]['type'] = $outArg['type'][$numArg];
}
}
}
}
}
}
if( isset($infos['name']) ){ // If informations containt at least a name
$listBridge[$out[1]] = $infos;
}
}
}
}
return $listBridge;
}
} }