Status changes by RSS
This commit is contained in:
parent
22de0b26e0
commit
a7075c82f3
258
0.3/class_rssfeed.php
Normal file
258
0.3/class_rssfeed.php
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* class_rssfeed.php uses:
|
||||||
|
* RSSFeed: This class has methods for making a RSS 2.0 feed.
|
||||||
|
* RSSMerger: This class has the ability to merge different RSS feeds and sort them after the date the feed items were posted.
|
||||||
|
* @author David Laurell <david.laurell@gmail.com>
|
||||||
|
*
|
||||||
|
* + 03/2013
|
||||||
|
* Few changes, AutoblogRSS and FileRSSFeed
|
||||||
|
* @author Arthur Hoaro <http://hoa.ro>
|
||||||
|
*/
|
||||||
|
class RSSFeed {
|
||||||
|
protected $xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a RSS feed
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$template = <<<END
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
END;
|
||||||
|
|
||||||
|
$this->xml = new SimpleXMLElement($template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set RSS Feed headers
|
||||||
|
* @param $title the title of the feed
|
||||||
|
* @param $link link to the website where you can find the RSS feed
|
||||||
|
* @param $description a description of the RSS feed
|
||||||
|
* @param $rsslink the link to this RSS feed
|
||||||
|
*/
|
||||||
|
public function setHeaders($title, $link, $description, $rsslink) {
|
||||||
|
$atomlink = $this->xml->channel->addChild("atom:link","","http://www.w3.org/2005/Atom");
|
||||||
|
$atomlink->addAttribute("href",$rsslink);
|
||||||
|
$atomlink->addAttribute("rel","self");
|
||||||
|
$atomlink->addAttribute("type","application/rss+xml");
|
||||||
|
|
||||||
|
$this->xml->channel->addChild("title",$title);
|
||||||
|
$this->xml->channel->addChild("link",$link);
|
||||||
|
$this->xml->channel->addChild("description",$description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the language of the RSS feed
|
||||||
|
* @param $lang the language of the RSS feed
|
||||||
|
*/
|
||||||
|
public function setLanguage($lang) {
|
||||||
|
$this->xml->channel->addChild("language",$lang);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds a picture to the RSS feed
|
||||||
|
* @param $url URL to the image
|
||||||
|
* @param $title The image title. Usually same as the RSS feed's title
|
||||||
|
* @param $link Where the image should link to. Usually same as the RSS feed's link
|
||||||
|
*/
|
||||||
|
public function setImage($url, $title, $link) {
|
||||||
|
$image = $this->xml->channel->addChild("image");
|
||||||
|
$image->addChild("url",$url);
|
||||||
|
$image->addChild("title",$title);
|
||||||
|
$image->addChild("link",$link);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Add a item to the RSS feed
|
||||||
|
* @param $title The title of the RSS feed
|
||||||
|
* @param $link Link to the item's url
|
||||||
|
* @param $description The description of the item
|
||||||
|
* @param $author The author who wrote this item
|
||||||
|
* @param $guid Unique ID for this post
|
||||||
|
* @param $timestamp Unix timestamp for making a date
|
||||||
|
*/
|
||||||
|
public function addItem($title, $link, $description, $author, $guid, $timestamp) {
|
||||||
|
$item = $this->xml->channel->addChild("item");
|
||||||
|
$item->addChild("title",$title);
|
||||||
|
$item->addChild("description",$description);
|
||||||
|
$item->addChild("link",$link);
|
||||||
|
$item->addChild("guid",$guid);
|
||||||
|
$item->addChild("author",$author);
|
||||||
|
$item->addChild("pubDate",date(DATE_RSS,intval($timestamp)));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Displays the RSS feed
|
||||||
|
*/
|
||||||
|
public function displayXML() {
|
||||||
|
header('Content-type: application/rss+xml; charset=utf-8');
|
||||||
|
echo $this->xml->asXML();
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getXML() {
|
||||||
|
return $this->xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RSSMerger {
|
||||||
|
private $feeds = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a RSSmerger object
|
||||||
|
*/
|
||||||
|
function __construct() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the feeds array from the given url which is a rss feed
|
||||||
|
* @param $url
|
||||||
|
*/
|
||||||
|
function add($xml) {
|
||||||
|
|
||||||
|
foreach($xml->channel->item as $item) {
|
||||||
|
$item->sitetitle = $xml->channel->title;
|
||||||
|
$item->sitelink = $xml->channel->link;
|
||||||
|
|
||||||
|
preg_match("/^[A-Za-z]{3}, ([0-9]{2}) ([A-Za-z]{3}) ([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([\+|\-]?[0-9]{4})$/", $item->pubDate, $match);
|
||||||
|
$item->time = time($match[4]+($match[6]/100),$match[5],$match[6],date("m",strtotime($match[2])),$match[1],$match[3]);
|
||||||
|
|
||||||
|
$this->feeds[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Comparing function for sorting the feeds
|
||||||
|
* @param $value1
|
||||||
|
* @param $value2
|
||||||
|
*/
|
||||||
|
function feeds_cmp($value1,$value2) {
|
||||||
|
if(intval($value1->time) == intval($value2->time))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (intval($value1->time) < intval($value2->time)) ? +1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the feeds array using the Compare function feeds_cmp
|
||||||
|
*/
|
||||||
|
function sort() {
|
||||||
|
usort($this->feeds,Array("RssMerger","feeds_cmp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function return the feed items.
|
||||||
|
* @param $limit how many feed items that should be returned
|
||||||
|
* @return the feeds array
|
||||||
|
*/
|
||||||
|
function getFeeds($limit) {
|
||||||
|
return array_slice($this->feeds,0,$limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileRSSFeed extends RSSFeed {
|
||||||
|
protected $filename;
|
||||||
|
|
||||||
|
public function __construct($filename) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->filename = $filename;
|
||||||
|
|
||||||
|
$this->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load() {
|
||||||
|
if ( file_exists( $this->filename )) {
|
||||||
|
$this->xml = simplexml_load_file($this->filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($title, $link, $description, $rsslink) {
|
||||||
|
parent::setHeaders($title, $link, $description, $rsslink);
|
||||||
|
$this->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addItem($title, $link, $description, $author, $guid, $timestamp) {
|
||||||
|
parent::addItem($title, $link, $description, $author, $guid, $timestamp);
|
||||||
|
$this->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function write() {
|
||||||
|
if ( file_exists( $this->filename )) {
|
||||||
|
unlink($this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
$outputXML = new RSSFeed();
|
||||||
|
foreach($this->xml->channel->item as $f) {
|
||||||
|
$item = $outputXML->addItem($f->title,$f->link,$f->description,$f->author,$f->guid, strtotime($f->pubDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
$merger = new RssMerger();
|
||||||
|
$merger->add($outputXML->getXML());
|
||||||
|
$merger->sort();
|
||||||
|
|
||||||
|
unset($this->xml->channel->item);
|
||||||
|
foreach($merger->getFeeds(20) as $f) {
|
||||||
|
parent::addItem($f->title,$f->link,$f->description,$f->author,$f->guid,$f->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents( $this->filename, $this->xml->asXML() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoblogRSS extends FileRSSFeed {
|
||||||
|
public function __construct($filename) {
|
||||||
|
parent::__construct($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addUnavailable($title, $folder, $siteurl, $rssurl) {
|
||||||
|
$path = pathinfo( $_SERVER['PHP_SELF'] );
|
||||||
|
$autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
|
||||||
|
$_SERVER["SERVER_NAME"].$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
|
||||||
|
|
||||||
|
parent::addItem( 'L\'autoblog "'. $title.'" est indisponible', $autobHref,
|
||||||
|
'Autoblog: <a href="'. $autobHref .'">'.$title.'</a><br>
|
||||||
|
Site: <a href="'. $siteurl .'">'. $siteurl .'</a><br>
|
||||||
|
RSS: <a href="'.$rssurl.'">'.$rssurl.'</a><br>
|
||||||
|
Folder: '. $folder ,
|
||||||
|
'admin',
|
||||||
|
$autobHref,
|
||||||
|
time()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAvailable($title, $folder, $siteurl, $rssurl) {
|
||||||
|
$path = pathinfo( $_SERVER['PHP_SELF'] );
|
||||||
|
$autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
|
||||||
|
$_SERVER["SERVER_NAME"].$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
|
||||||
|
|
||||||
|
parent::addItem( 'L\'autoblog "'. $title.' est de nouveau disponible', $autobHref,
|
||||||
|
'Autoblog : <a href="'. $autobHref .'">'.$title.'</a><br>
|
||||||
|
Site: <a href="'. $siteurl .'">'. $siteurl .'</a><br>
|
||||||
|
RSS: <a href="'.$rssurl.'">'.$rssurl.'</a><br>
|
||||||
|
Folder: '. $folder ,
|
||||||
|
'admin',
|
||||||
|
$autobHref,
|
||||||
|
time()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCodeChanged($title, $folder, $siteurl, $rssurl, $code) {
|
||||||
|
$path = pathinfo( $_SERVER['PHP_SELF'] );
|
||||||
|
$autobHref = 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.
|
||||||
|
$_SERVER["SERVER_NAME"].$_SERVER["SERVER_PORT"]. $path['dirname'].'/'.$folder;
|
||||||
|
|
||||||
|
parent::addItem( 'L\'autoblog "'. $title.' a renvoyé un code imprévu', $autobHref,
|
||||||
|
'Code: '. $code .'<br>
|
||||||
|
Autoblog : <a href="'. $autobHref .'">'.$title.'</a><br>
|
||||||
|
Site: <a href="'. $siteurl .'">'. $siteurl .'</a><br>
|
||||||
|
RSS: <a href="'.$rssurl.'">'.$rssurl.'</a><br>
|
||||||
|
Folder: '. $folder ,
|
||||||
|
'admin',
|
||||||
|
$autobHref,
|
||||||
|
time()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -144,24 +144,8 @@ function updateType($siteurl) {
|
||||||
|
|
||||||
function debug($data)
|
function debug($data)
|
||||||
{
|
{
|
||||||
if(is_array($data))
|
echo '<pre>';
|
||||||
{
|
var_dump($data);
|
||||||
echo '<p>Array <br/>{<br/>';
|
echo '</pre>';
|
||||||
foreach ( $data AS $Key => $Element )
|
|
||||||
{
|
|
||||||
echo ' ['. $Key .'] =>';
|
|
||||||
debug($Element);
|
|
||||||
}
|
|
||||||
echo '}</p>';
|
|
||||||
}
|
|
||||||
else if(is_bool($data))
|
|
||||||
{
|
|
||||||
if($data === 1)
|
|
||||||
echo 'true<br/>';
|
|
||||||
else
|
|
||||||
echo 'false<br/>';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
echo $data.'<br />';
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
define('XSAF_VERSION', 3);
|
define('XSAF_VERSION', 3);
|
||||||
define('ROOT_DIR', __DIR__);
|
define('ROOT_DIR', __DIR__);
|
||||||
|
define('RSS_FILE', 'rss.xml');
|
||||||
|
|
||||||
if(file_exists("config.php")){
|
if(file_exists("config.php")){
|
||||||
include "config.php";
|
include "config.php";
|
||||||
}else{
|
}else{
|
||||||
|
@ -78,11 +80,15 @@ function get_link_from_datafeed($data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverUrl()
|
function serverUrl($return_subfolder = false)
|
||||||
{
|
{
|
||||||
$https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
|
$https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
|
||||||
$serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
|
$serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
|
||||||
return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport;
|
if($return_subfolder === true) {
|
||||||
|
$path = pathinfo( $_SERVER['PHP_SELF'] );
|
||||||
|
$subfolder = $path['dirname'] .'/';
|
||||||
|
} else $subfolder = '';
|
||||||
|
return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport.$subfolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
function objectCmp($a, $b) {
|
function objectCmp($a, $b) {
|
||||||
|
@ -152,6 +158,20 @@ function versionCheck() {
|
||||||
}
|
}
|
||||||
$update_available = (ALLOW_CHECK_UPDATE) ? versionCheck() : false;
|
$update_available = (ALLOW_CHECK_UPDATE) ? versionCheck() : false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSS Feed
|
||||||
|
**/
|
||||||
|
if (isset($_GET['rss'])) {
|
||||||
|
require_once('class_rssfeed.php');
|
||||||
|
$rss = new AutoblogRSS(RSS_FILE);
|
||||||
|
$rss->displayXML();
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
if( !file_exists(RSS_FILE)) {
|
||||||
|
require_once('class_rssfeed.php');
|
||||||
|
$rss = new AutoblogRSS(RSS_FILE);
|
||||||
|
$rss->create('Projet Autoblog'. ((!empty($head_title)) ? ' | '. $head_title : ''), serverUrl(true),"Projet Autoblog, flux RSS des changements de disponibilité.", serverUrl(true) . '/' . RSS_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SVG
|
* SVG
|
||||||
|
@ -172,6 +192,9 @@ if (isset($_GET['check']))
|
||||||
$svg_statusnet='<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="15" height="15"><path d="m 11.679889,7.6290431 a 4.1668792,3.7091539 0 1 1 -8.3337586,0 4.1668792,3.7091539 0 1 1 8.3337586,0 z" style="fill:none;stroke:#ff6a00;stroke-width:4;stroke-miterlimit:4" /></svg>';
|
$svg_statusnet='<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="15" height="15"><path d="m 11.679889,7.6290431 a 4.1668792,3.7091539 0 1 1 -8.3337586,0 4.1668792,3.7091539 0 1 1 8.3337586,0 z" style="fill:none;stroke:#ff6a00;stroke-width:4;stroke-miterlimit:4" /></svg>';
|
||||||
|
|
||||||
$errorlog="./".escape( $_GET['check'] ) ."/error.log";
|
$errorlog="./".escape( $_GET['check'] ) ."/error.log";
|
||||||
|
|
||||||
|
$oldvalue = null;
|
||||||
|
if(file_exists($errorlog)) { $oldvalue = file_get_contents($errorlog); };
|
||||||
if(file_exists($errorlog) && filemtime($errorlog) < $expire) { unlink($errorlog); } /* errorlog périmé ? Suppression. */
|
if(file_exists($errorlog) && filemtime($errorlog) < $expire) { unlink($errorlog); } /* errorlog périmé ? Suppression. */
|
||||||
if(file_exists($errorlog)) /* errorlog existe encore ? se contenter de lire sa taille pour avoir le statut */
|
if(file_exists($errorlog)) /* errorlog existe encore ? se contenter de lire sa taille pour avoir le statut */
|
||||||
{
|
{
|
||||||
|
@ -188,10 +211,37 @@ if (isset($_GET['check']))
|
||||||
if(strpos(strtolower($ini['SITE_TYPE']), 'microblog') !== FALSE) { die($svg_statusnet); } /* Statusnet */
|
if(strpos(strtolower($ini['SITE_TYPE']), 'microblog') !== FALSE) { die($svg_statusnet); } /* Statusnet */
|
||||||
|
|
||||||
$headers = get_headers($ini['FEED_URL']);
|
$headers = get_headers($ini['FEED_URL']);
|
||||||
if(empty($headers)) { file_put_contents($errorlog, '..'); die($svg_rouge); } /* le flux est indisponible (typiquement: erreur DNS ou possible censure) - à vérifier */
|
/* le flux est indisponible (typiquement: erreur DNS ou possible censure) - à vérifier */
|
||||||
|
if(empty($headers) || $headers === FALSE ) {
|
||||||
|
if( $oldvalue !== null && $oldvalue != '..' ) {
|
||||||
|
require_once('class_rssfeed.php');
|
||||||
|
$rss = new AutoblogRSS(RSS_FILE);
|
||||||
|
$rss->addUnavailable($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL']);
|
||||||
|
}
|
||||||
|
file_put_contents($errorlog, '..');
|
||||||
|
die($svg_rouge);
|
||||||
|
}
|
||||||
$code=explode(" ", $headers[0]);
|
$code=explode(" ", $headers[0]);
|
||||||
if($code[1] == "200") { file_put_contents($errorlog, ''); die($svg_vert);} /* code retour 200: flux disponible */
|
/* code retour 200: flux disponible */
|
||||||
else {file_put_contents($errorlog, '.'); die($svg_jaune);} /* autre code retour: un truc a changé (redirection, changement de CMS, .. bref vvb.ini doit être corrigé) */
|
if($code[1] == "200") {
|
||||||
|
if( $oldvalue !== null && $oldvalue != '' ) {
|
||||||
|
require_once('class_rssfeed.php');
|
||||||
|
$rss = new AutoblogRSS(RSS_FILE);
|
||||||
|
$rss->addAvailable($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL']);
|
||||||
|
}
|
||||||
|
file_put_contents($errorlog, '');
|
||||||
|
die($svg_vert);
|
||||||
|
}
|
||||||
|
/* autre code retour: un truc a changé (redirection, changement de CMS, .. bref vvb.ini doit être corrigé) */
|
||||||
|
else {
|
||||||
|
if( $oldvalue !== null && $oldvalue != '.' ) {
|
||||||
|
require_once('class_rssfeed.php');
|
||||||
|
$rss = new AutoblogRSS(RSS_FILE);
|
||||||
|
$rss->addCodeChanged($ini['SITE_TITLE'], escape($_GET['check']), $ini['SITE_URL'], $ini['FEED_URL'], $code[1]);
|
||||||
|
}
|
||||||
|
file_put_contents($errorlog, '.');
|
||||||
|
die($svg_jaune);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,6 +606,7 @@ if( !empty($_POST['opml_file']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projet Autoblog<?php if(!empty($head_title)) { echo " | " . escape($head_title); } ?></title>
|
<title>Projet Autoblog<?php if(!empty($head_title)) { echo " | " . escape($head_title); } ?></title>
|
||||||
|
<link rel="alternate" type="application/rss+xml" title="RSS" href="<?php echo serverUrl(true) . RSS_FILE;?>" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
body {background-color:#efefef;text-align:center;color:#333;font-family:sans-serif}
|
body {background-color:#efefef;text-align:center;color:#333;font-family:sans-serif}
|
||||||
a {color:black;text-decoration:none;font-weight:bold;}
|
a {color:black;text-decoration:none;font-weight:bold;}
|
||||||
|
@ -735,7 +786,7 @@ if( !empty($_POST['opml_file']) && ALLOW_NEW_AUTOBLOGS && ALLOW_NEW_AUTOBLOGS_BY
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
||||||
<div class="pbloc">
|
<div class="pbloc">
|
||||||
<h2>Autoblogs hébergés</h2>
|
<h2>Autoblogs hébergés <a href="?rss" title="RSS des changements"><img src="rss.png" alt="rss"/></a></h2>
|
||||||
<p>
|
<p>
|
||||||
<b>Autres fermes</b>
|
<b>Autres fermes</b>
|
||||||
→ <a href="https://duckduckgo.com/?q=!g%20%22Voici%20une%20liste%20d'autoblogs%20hébergés%22">Rechercher</a>
|
→ <a href="https://duckduckgo.com/?q=!g%20%22Voici%20une%20liste%20d'autoblogs%20hébergés%22">Rechercher</a>
|
||||||
|
|
BIN
0.3/rss.png
Normal file
BIN
0.3/rss.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 691 B |
Loading…
Reference in a new issue