Vous êtes ici

Blogs

Synchroniser une timeline Twitter sur un compte Mastodon

Face aux limites imposées aux clients non officiels du réseau social Twitter - pourtant généralement meilleurs que l'officiel - notamment la limite des 200 statut par requête et des 15 requêtes toutes les 15 minutes maximum ou encore la non conservation de la position dans la timeline, j'ai eu l'idée de synchroniser le contenu de la timeline sur celui d'un compte privé Mastodon par l'intermédiaire d'un script, puisqu'en général instances et clients Mastodon son nettement moins limités. Il suffirait ensuite d'appeler de façon régulière ce script sans interaction humaine (car on ne peut pas passer sa vie à récupérer des tweets !).

Voici donc un début de résultat.

Pour l'exploiter à votre tour, il vous faudra au minimum PHP et son extension CURL. Sans oublier de faire le nécessaire pour obtenir vos jetons d'accès développeurs sur votre instance Mastodon et Twitter...

Son utilisation dans crontab sera ensuite on ne peut plus simple :

*/1 * * * * sudo -u www-data php /chemin/twitter_to_mastodon_timeline.php

Le script PHP

<?php // simple-php-twitter-to-mastodon-timeline.php

chdir('/script/path');

    function buildBaseString($baseURI, $method, $params) {
        $r = array();
        ksort($params);
        foreach($params as $key=>$value){
            $r[] = "$key=" . rawurlencode($value);
        }
        return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
    }

    function buildAuthorizationHeader($oauth) {
        $r = 'Authorization: OAuth ';
        $values = array();
        foreach($oauth as $key=>$value)
            $values[] = "$key=\"" . rawurlencode($value) . "\"";
        $r .= implode(', ', $values);
        return $r;
    }


    $url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'; // or home_timeline.json

    // Custom Twitter data

    $oauth_access_token = " ";
    $oauth_access_token_secret = " ";
    $consumer_key = " ";
    $consumer_secret = " ";

    // Custom Mastodon data

    $mastodon_token = ' ';
    $mastodon_instance_url = 'https://instance.url'; // example : https://framapiaf.org'

    $curl_opt_url = $mastodon_instance_url . "/api/v1/statuses";

    $oauth = array( 'oauth_consumer_key' => $consumer_key,
                    'oauth_nonce' => time(),
                    'oauth_signature_method' => 'HMAC-SHA1',
                    'oauth_token' => $oauth_access_token,
                    'oauth_timestamp' => time(),
                    'oauth_version' => '1.0');

    $base_info = buildBaseString($url, 'GET', $oauth);
    $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
    $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
    $oauth['oauth_signature'] = $oauth_signature;

    $header = array(buildAuthorizationHeader($oauth), 'Expect:');
    $options = array( CURLOPT_HTTPHEADER => $header,
                      CURLOPT_HEADER => false,
                      CURLOPT_URL => $url,
                      CURLOPT_RETURNTRANSFER => true,
                      CURLOPT_SSL_VERIFYPEER => false);

    $feed = curl_init();
    curl_setopt_array($feed, $options);
    $json = curl_exec($feed);
    curl_close($feed);

    $twitter_data = json_decode($json);

    $lastid='';

    $lastidfile = 'lastid.txt';
    $current = file_get_contents($lastidfile);
    $content = "";
    $i = 0;

    foreach ($twitter_data as $twt) {
        if ($i == 0) {$lastid = $twt->id_str;}
        if ($twt->id_str == $current OR !isset($twt->id_str)) { break;  } else {

        $headers = [
        'Authorization: Bearer ' . $mastodon_token
        ];

        // You can change twitter API fields here :
        $toots[] = $twt->created_at . " -  " . $twt->user->name . "\r\r " . $twt->text . "\r\r https://twitter.com/" . $twt->user->screen_name . "/stat$

        $i++;
        }

}

if (!isset($toots)) { } else { 

$toots = array_reverse($toots);

foreach ($toots as $toot) {

$status_data = array(
  "status" => $toot,
  "language" => "fre",
  "visibility" => "private"
);

$ch_status = curl_init();
curl_setopt($ch_status, CURLOPT_URL, $curl_opt_url);
curl_setopt($ch_status, CURLOPT_POST, 1);
curl_setopt($ch_status, CURLOPT_POSTFIELDS, $status_data);
curl_setopt($ch_status, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_status, CURLOPT_HTTPHEADER, $headers);

$output_status = json_decode(curl_exec($ch_status));

curl_close ($ch_status);

}

file_put_contents($lastidfile, $lastid);

}

?>

UK/Happy hardcore : sélection janvier 2020

Revue de web automatisée sous Linux avec Semantic Scuttle, PHP, CutyCapt, GraphicsMagick ...

Les prérequis techniques

Pour ma part j'utilise de longue date Semantic Scuttle, qui me facilite grandement l'enregistrement des URL, notamment grâce à une extension pour Firefox ou le bookmarklet dédié. À défaut vous pourrez facilement adapter ce code avec une source de données en markdown... ou autre.

Certes, cela représente beaucoup de dépendances, mais on les trouve facilement sous GNU/Linux et ces composants restent gratuits.

Le script PHP


<?php // /chemin/script/RevueWeb.php $uneDate = date('Y-m-d'); $maDate = new DateTime($uneDate); $dateFormatee = date_format($maDate, 'Ymd'); $dateLisible = date_format($maDate, 'd/m/Y'); $imgDir = "/chemin/script/"; require_once 'src/Feed.php'; // (RSS to PHP) // Flux RSS des pages enregistrées dans Scuttle dédiés à votre revue de web : $rss = Feed::loadRss('https://instance.semantic.scuttle/rss.php/frenchhope/tag_de_la_revue_de_web?sort=date_desc&count=2048&privateKey=ma.cle.privee'); $versionMarkdown = "## Revue de web du $dateLisible" . PHP_EOL . PHP_EOL; // Titre // contenu foreach ($rss->item as $item) { $versionMarkdown .= "[" . $item->title . "](" . $item->link . ")" . PHP_EOL . PHP_EOL; // on formate le titre et les hyperliens // on réalise des captures d'écran au format JPEG, c'est plus joli et ça ne tiens pas trop de place. // pour cela on crée un serveur d'affichage virtuel (serveur X) avec xvfb-run parce qu'en ligne de commande sur un serveur il n'y en a pas ! // Voir la documentation de CutyCapt pour les options. $hash = hash('sha256',$item->link); $imgFile = $imgDir . "webScreenShot_" . $hash . ".jpg"; exec('xvfb-run --server-args="-screen 0, 1900x1080x24" cutycapt --min-width=1900 --min-height=1080 --smooth --url="' . $item->link . '" --out="' . $imgFile . '"'); // Recadrage avec GraphicsMagick exec('gm convert ' . $imgFile . ' -crop 1900x1080+0+0 ' . $imgFile); // Redimentionnement avec GraphicsMagick exec('gm mogrify -resize 950x540 -quality 65 ' . $imgFile); $versionMarkdown .= "![]($imgFile)" . PHP_EOL . PHP_EOL; $versionMarkdown .= "---" . PHP_EOL . PHP_EOL; } // Tout dans un fichier avec la date du jour file_put_contents("$dateFormatee.md", $versionMarkdown, FILE_APPEND | LOCK_EX); ?>

Affichage de la revue dans une page web

Pour ma part je copie ce fichier Markdown dans mon dossier de données Nextcloud car avec l'application Pico CMS je peux l'afficher directement. Dans ce cas il faut mettre à jour la base Nextcloud :

sudo -u www-data php /var/www/nextcloud/occ files:scan [nom d'utilisateur]"

Mais vous pourriez tout aussi bien créer un script en PHP pour afficher le Markdown dans une page web avec parsedown par exemple.

L'alternative à base de source de fichier Markdown plutôt que Semantic Scuttle et RSS

remplacer :

$rss = Feed::loadRss('https://instance.semantic.scuttle/rss.php/frenchhope/tag_de_la_revue_de_web?sort=date_desc&count=2048&privateKey=ma.cle.privee');

par :

$contenu = file_get_contents('/chemin/du/fichier.md');
$regex = "/\[([^\[\]]*)\](.*)/";
preg_match_all("`$regex`", $contenu, $matches);  

et :

foreach ($rss->item as $item) {
$versionMarkdown .= "[" . $item->title . "](" . $item->link . ")" . PHP_EOL . PHP_EOL; 
$hash = hash('sha256',$item->link);
$imgFile = $imgDir . "webScreenShot_" . $hash . ".jpg";
exec('xvfb-run --server-args="-screen 0, 1900x1080x24" cutycapt --min-width=1900 --min-height=1080 --smooth --url="' . $item->link . '" --out="' . $imgFile . '"');

par :

foreach ($matches as $item) {
$versionMarkdown .= "[" . $item[0] . "](" . $item[1] . ")" . PHP_EOL . PHP_EOL; 
$hash = hash('sha256',$item[1]);
$imgFile = $imgDir . "webScreenShot_" . $hash . ".jpg";
exec('xvfb-run --server-args="-screen 0, 1900x1080x24" cutycapt --min-width=1900 --min-height=1080 --smooth --url="' . $item[1] . '" --out="' . $imgFile . '"');

Utilisation

  • En ligne de commande
sudo -u www-data php /chemin/script/RevueWeb.php
  • Ou depuis l'URL de la page "RevueWeb.php" si vous la publiez avec un serveur web

http://mon.serveur.web/RevueWeb.php

  • Puis téléchargement d'une revue :

http://mon.serveur.web/20200127.md

Automatisation avec cron

Tous les jours à 20h00 par exemple :

00 20 * * *    sudo -u www-data php /chemin/script/RevueWeb.php

Dons & participations financières en 2019

Comme chaque année, depuis des années, 2019 fut une année de choix... Voici donc mes dons cette année :

  • Livre “Inégalités en France 2019”
  • GMIC
  • Fedilab / Mastalab
  • APRIL
  • digiKam
  • Framasoft
  • Wikidébats
  • Pompiers
  • Internet Archive (archive.org)
  • Médecins sans frontières
  • Greenpeace
  • Handicap International
  • Unicef
  • WWF
  • Croix Rouge Française

Pages

Subscribe to RSS - blogs