API - Badgit - I'm baaaad, I'm baaaad...

Histoire de bosser un peu sur l'utilisation d'Imagick (pour lequel je m'étais fait des notes ici 12) j'ai essayé de faire une petite «api» de génération de badges simple.

Objectifs

  • Un script qui permet de faire des badges à une ou plusieurs parties,
  • gestion de la taille de police et de la police,
  • gestion des couleurs,
  • gestion d'icônes

Résultat

On peut appeler l'api directement en précisant les variables suivantes:

  • txt: le texte; s'il y a plusieurs parties, on les sépare par un |. exemple ?txt=trop beau|pas vrai
  • backcolor: la couleur de fond; on peut préciser la couleur de chaque partie en les séparant par | aussi. La notation se fait comme en css (sauf pour le # qu'il faut omettre) ```F00|red|rgba(255,0,0,0.5)
  • textcolor: pareil pour le texte. Par défaut, badgit va choisir le blanc ou le noir afin de maintenir le meilleur contraste.
  • fontsize: la taille de police
  • font: une des fontes installées. Je n'en ai mis que deux pour le moment mais on peut utiliser «courier» par exemple.
  • icon: le nom d'une icône de iconeleon (j'ai d'ailleurs ajouté une option pour copier le nom en question depuis l'api d'icônes.)

Exemples

api.warriordudimanche.net/badgit/?txt=Mon%20super%20badge&backcolor=red&txtcolor=&icon=&font=montserrat.ttf&fontsize=16

api.warriordudimanche.net/badgit/?txt=Mon%20super|badge&backcolor=red|pink&txtcolor=pink|red&icon=&font=montserrat.ttf&fontsize=16

api.warriordudimanche.net/badgit/?txt=Mon%20super|badge|de%20ouf&backcolor=red|pink|maroon&txtcolor=pink|red&icon=&font=montserrat.ttf&fontsize=16

api.warriordudimanche.net/badgit/?txt=Mon%20super|badge%20|de%20ouf%20&backcolor=red|pink|maroon&txtcolor=pink|red&icon=|fontawesome_solid/smile-beam.svg|fontawesome_solid/hand-back-fist.svg&font=montserrat.ttf&fontsize=16

Frontend

J'ai goupillé aussi un petit front basique, histoire de ne pas se taper tout au clavier.

FireShot Capture 026 - Badgit - api.warriordudimanche.net.png

Conclusion

Ça ne servira sans doute à personne mais bon, sait-on jamais

Ceci dit, il y a une classe badge qui peut faire l'affaire quelque part...

Le code est là : https://api.warriordudimanche.net/badgit/?download

PHP - Notes perso sur Imagick 2 - ImagickDraw... si on dessinait ?

Deuxième épisode de mes notes perso sur la bibliothèque Image magic pour évoquer la classe ImagickDraw qui, comme son nom l'indique, permet de dessiner avec Imagick. ( 1er épisode )

On va se limiter à des usages basiques parce que la lecture du sommaire suffit à imaginer des possibilités certes alléchantes mais totalement hors de propos en ce qui me concerne (courbes de bézier etc)

Spoiler: c'est nettement moins intuitif et simple que pour le traitement d'image... l'écart entre Imagick et GD dans le domaine du tracé n'est plus si évident: ça mériterait de faire un classe pour simplifier tout ça... ( /me se jette sur son bujo pour griffonner spasmodiquement)

Préambule

Cette classe crée un objet servant d'instructions à appliquer ensuite à un objet Imagick.

On partira du principe que vous avez fait des instances des classes comme suit:

$im=new Imagick(); # l'image dans laquelle vous allez appliquer l'objet ImagickDraw
$draw=new ImagikDraw();

Ajouter un texte

Fixer les caractéristiques

  • $draw->setFont(fonte); : sélectionne la fonte à utiliser
  • $draw->setFontSize(taille); : définit la taille en pixels
  • $draw->setFillColor(couleur);: définit la couleur de fond (normalement, couleur est un objet ImagickPixel, voir 1er épisode mais on peut passer une chaîne au format de couleur CSS )
  • $draw->setTextAlignment(alignement); : une des constantes d'alignement imagick::ALIGN_LEFT imagick::ALIGN_CENTER Imagick::ALIGN_RIGHT
  • $draw->setGravity(Imagick::GRAVITY_CENTER); centre le texte dans sa boîte (horizontal et vertical)
  • $draw->setTextDecoration(decoration): une des constantes de décoration imagick::DECORATION_UNDERLINE imagick::DECORATION_OVERLINE imagick::DECORATION_LINETROUGH et bien d'autres (comme du... bruit ?!).
  • $draw->setTextAntialias(true);: ajouter de l'antialias
  • l'espacement :
    • entre les mots : $draw->setTextInterwordSpacing(taille)
    • entre les lignes : $draw->setTextInterlineSpacing(taille)

Tracer le texte

  • $draw->annotation(x,y,texte) : trace un texte dans la police sélectionnée
  • $im->annotateImage( $draw, 0, 0, 0, $fontName ); : ajoute le texte à l'image.

Obtenir des infos utiles

  • obtenir la liste des polices disponibles: $im->queryFonts($pattern = "*") 🆒 on peut filtrer avec une pattern à la façon de glob().
  • obtenir les infos fixées par setXXX : getXXX ... ainsi on a getFont(), getFontSize() etc...
  • obtenir les dimensions de la boîte de texte: $im->queryFontMetrics($draw, text); on récupère un tableau comme ci-dessous
  • 
    Array
    (
        [characterWidth] => 9
        [characterHeight] => 9
        [ascender] => 9 # la taille au-dessus de la baseline
        [descender] => -2 # la taille sous la baseline
        [textWidth] => 71
        [textHeight] => 10
        [maxHorizontalAdvance] => 12
        [boundingBox] => Array
            (
                [x1] => 0
                [y1] => -2
                [x2] => 6.890625
                [y2] => 7
            )
        [originX] => 70
        [originY] => 0
    )
    

    Dessiner des formes

    Fixer les caractéristiques

    • opacité du trait : $draw->setStrokeOpacity(0-1);
    • couleur du trait : $draw->setStrokeColor(couleur);
    • épaisseur du trait : $draw->setStrokewidth(nb);
    • type de trait : $draw->setStrokeDashArray() Le motif semble être plein de possibilités car on peut le définir très spécifiquement et même utiliser une image comme motif (->setStrokePatternURL)
    • couleur de remplissage : $draw->setFillColor(couleur);

    Formes

    • cercle : $draw->circle ($x, $y, $x + $r, $y);
    • ellipse : $draw->ellipse($ox,$oy,$rx,$ry,$start,$end);
    • point : $draw->point ($x, $y);
    • polygone : $draw->polygon ($tableau_de_coordonnées); : array( 'x' => 3, 'y' => 4 ), array( 'x' => 2, 'y' => 6 )
    • ligne brisée : $draw->polyline ($tableau_de_coordonnées); : array( 'x' => 3, 'y' => 4 ), array( 'x' => 2, 'y' => 6 )
    • rectangle : $draw->rectangle ($x, $y, $x2, $y2); )
    • rectangle arrondi: $draw->roundRectangle ($x, $y, $x2, $y2,$rayonx,$rayony);

    Exemple

    Pour écrire un texte dans une image:

    
    $text='pipo et mollo';
    $im=new Imagick();
    $draw=new ImagickDraw();
    //var_dump($im->queryFonts('*'));exit;
    $draw->setFont( 'Courier' );
    $draw->setFontSize( 20 );
    $draw->setFillColor( 'black' );
    $draw->setTextAntialias(true);
    $metrics = $im->queryFontMetrics($draw, $text);
    $draw->annotation(0,$metrics['ascender'],$text);
    $im->newImage( 300, 20, 'lightblue');
    $im->drawImage($draw);
    $im->setImageFormat( 'png' );
    header('Content-type: image/jpeg');
    exit($im);  
    
    ce qui donne cette image
    index2.png
    C'est pas ouf...

    Il serait intéressant de pousser les tests mais là, j'ai pas le temps...

    Peut-être reprendrais-je des trucs existant avec tout ça ( scriptopic, RoR, Stamp mematic etc etc.)

    Et c'est là que Bronco prit  conscience de la quantité de   merdes affligeantes qu'il avait  codées sur un coup de tête  à la va-comme-je-te-pousse   et qu'il avait infligées à tous...

    PHP - Notes perso sur Imagick, un résumé de pourquoi je vire GD à coups de pompes dans l'oignon.

    Allez, pour une fois, j'ai un peu de temps devant moi, je vais éplucher un peu la lib Image magick dont je parlais il n'y a guère...

    La base

    charger UNE image

    Simple: pas besoin de plusieurs fonctions selon le format, il suffit de $images = new Imagick('image.jpg');

    charger DES images (et là c'est fort)

    Même pas nécessaire de passer par un foreach, on fournit le tableau des fichiers voire directement un glob: $images = new Imagick(glob('images/*.JPG'));

    Sauver une image

    $im->writeImage('image.jpg');

    Faire une miniature

    Si on laisse une dimension à 0, les proportions sont conservées (quand tu vois la merde que c'est avec GD !) $image->thumbnailImage(100, 0);

    Output une image

    header('Content-type: image/jpeg');
    $image = new Imagick('image.jpg');
    # ici on effectue un traitement puis on sort le résultat
    echo $image;

    Récupération d'infos sur les images

    • taille $im->getImageWidth() $im->getImageHeight()
    • format $im->getImageFormat()

    création d'une nouvelle image

    $im->NewImage(largeur,hauteur,couleur de fond);

    création d'une couleur

    Comme pour GD, il faut créer un objet couleur dans les traitements d'image, mais c'est plus simple qu'avec GD (et plus complet): il suffit de passer une couleur selon les normes CSS. Du coup, la transparence n'est pas gérée par une connerie de paramètre «alpha» mais simplement par ... rgba()... 💖

    $couleur=new ImagickPixel("white");
    $couleur=new ImagickPixel("#FFF");
    $couleur=new ImagickPixel('rgb(255,255,200)');
    $couleur=new ImagickPixel('rgba(255,255,200,0.5)');

    🆒 ⮕ Ça peut paraître compliqué, mais en fait, dans les fonctions où on est sensé utiliser ImagickPixel, je me suis aperçu qu'on pouvait tout simplement passer une string contenant la couleur css... elles se démerdent seules. 😍

    Traitements

    Ajouts

    • de bordure ->borderImage(couleur,largeur bords verticaux, largeur bords horizontaux): $im->borderImage(new ImagickPixel("white"), 5, 5);
    • de texte :
    • de stéganographie (cacher un filigrane dans une image) ->steganoImage():

    Modification de couleurs

    • sepia ->sepiaToneImage(force) : une valeur raisonnable est 80 (sic)
    • solarisation ->solarizeImage(force)
    • négatif ->negateImage(gris): $im->negateImage(0);
    • niveaux
      • $im->normalizeImage();
      • $im->autoLevelImage();
    • gamma ->gammaImage(niveau) : $im->gammaImage(5);
    • contraste $im->contrastImage(niveau)
    • luminosité et contraste $im->brightnessContrastImage(niveau luminosite, niveau contraste);
    • égalisation $im->equalizeImage()
    • coloriser ->colorizeImage(couleur,opacite) : $im->colorizeImage("red",0.5); 🤬 pas réussi à l'utiliser pour ce test...

    Modification de taille et d'orientation

    • redimensionner :
      • ->resizeImage(largeur,hauteur, filtre, flou) : $i->resizeImage(250,0,Imagick::FILTER_POINT,0);
      • ->scaleImage(largeur,hauteur): pas encore compris la différence avec la précédente
      • recadrer ->cropImage(largeur,hauteur,x,y): $im->cropImage(200,200,50,50);
      • 💖 créer une miniature à la taille donnée en recadrant l'image autour du centre ->cropThumbnailImage(largeur,hauteur)
    • retourner :
      • $im->flipImage() pour retourner horizontalement
      • $im->flopImage() pour retourner verticalement
    • pivoter ->rotateimage(color, $angle): $im->rotateImage(new ImagickPixel('#00000000'), 75);

    Modifications de qualité

    • modification d'opacité ->setImageOpacity(0-1) : $im->->setImageOpacity(0.3);
    • netteté ->sharpenImage(rayon, deviation,canal):
    • amélioration ->enhanceImage()
    • flou :
      • flou tout court ->blurImage(rayon, décalage): $im->blurImage(5,2);
      • gaussien ->gaussianBlurImage(rayon, deviation) : $im->gaussianBlurImage(5,2);
      • de mouvement ->motionBlurImage(rayon,deviation,angle) : $im->motionBlurImage(5,5,45);
    • réduction du nombre de couleurs ->posterizeImage(nb de couleurs, 0/1) :$im->posterizeImage(5,0);
    • ajout de bruit ->addNoiseImage(type) : `$im->addNoiseImage(imagick::NOISE_GAUSSIAN ); voir les constantes de type de bruit

    Modification d'aspect et déformations

    • aspect crayon $im->sketchImage(rayon, deviation, angle);
    • aspect fusain $im ->charcoalImage(rayon, deviation);
    • aspect emboss ->shadeImage(gris, angle, hauteur):
      • $im->->shadeImage(1, 90, 2); # emboss + image grisée
      • $im->shadeImage(0, 90,2) # emboss sur l'image d'origine (couleur)
    • peinture à l'huile ->oilPaintImage(rayon) : $im->oilPaintImage(5);
    • détection de bords ->edgeImage(rayon) : $im->edgeImage(5);
    • vagues ->waves(amplitude,longueur): $im->waveImage( 10, 10);
    • déformation ->distortImage(methode, arguments[],0) : voir les constantes de déformation

    interactions d'images

    Conclusion

    Image Magick me semble particulièrement bien nommée tant les possibilités sont énormes et la simplicité d'utilisation étonnante: on sent une volonté de se simplifier la vie lors de l'utilisation... c'est juste beau.

    Je voulais mettre une image de chaque effet dans les descriptions mais:

    1. ça prenait une place de ouf
    2. je préfère reprendre certaines de mes applis/api avec imagick
    3. j'ai plus le temps, les autres arrivent
    4. j'ai la flemme.

    [EDIT] En fait, j'ai fait une page de test même si tout n'est pas concluant : http://test.warriordudimanche.net/imagick/

    Api perso: Fetchit, le bon chienchien du oueb...

    Ouate ?

    Après avoir fait goofi puis Getlib j'ai codé vite fait une petite «api» destinée à ramener en local n'importe quelle ressource distante... «quelle différence avec getlib ?» allez-vous me demander sur un ton narquois à propos de la cruauté duquel je tairais scrupuleusement tout commentaire.

    J'ai eu envie de faire ça car j'en avais assez de passer par le combo

    bouton droit sur une ressourcetélécharger envoyer sur mon sitefaire un lien ou une img

    Du coup, il suffit d'ajouter l'adresse de l'api à l'url vers la ressource distante... Donc http://insta.com/image.jpg devient par exemple http://api.warriordudimanche.net/fetchit?url=http://insta.com/image.jpg

    Fetchit va récupérer la ressource en local et vous servir cette version au lieu de la distante. Comme d'hab' si cette ressource a déjà été récupérée elle n'est pas re téléchargée.

    Le deuxième effet kiskool (paye ta réf de vieux) c'est que du coup, comme getlib, ça permet de récupérer toute lib en local et être plus RGPD friendly.

    Examples:

  • utiliser directement une image distante : <img src="http:www.distantserver.com/pic.png"/> ➜ <img src="http://api.url.com?url=http:www.distantserver.com/pic.png"/>
  • lien vers une ressource distante : <a href="http:www.distantserver.com/file.pdf"> Link to distant file</a> ➜ <a href="http://api.url.com?url=http:www.distantserver.com/pic.png"> Link to distant file</a>
  • utiliser une lib hébergée sur un CDN distant : <script src="http:www.distantnastyserver.com/lib.js"></script> ➜ <script src="http://api.url.com?url=http:www.distantnastyserver.com/lib.js"></script>

    Con figue ?

    Afin d'éviter que votre server ne se retrouve floodé par des fichiers vidéos 8K à 60 gigots l'unité, il y a une limite de taille configurée dans la constante SIZE_LIMIT, fixée par défaut à 10 Mo.

    Le code ?! c'est... le code.

    Ceux qui aiment farfouiller verront que cette fois, j'ai fait une classe fetchit_class.php qui se charge de tout. Son fonctionnement est tellement simple que je me fissure même pas le joufflu à vous le détailler, démerdez-vous.

    License

    Comme d'hab', c'est cadeau... Utilisez, partagez, modifiez... juste respectez la Dont be a dick licence

    donne le ouade

    Comme tout ça n'a de sens que si on héberge soi-même, vous pouvez récup' le zip qui va bien ici : https://api.warriordudimanche.net/fetchit/?download

    Le mot final

    Mes chers cons-patriotes, non aux fuites de données, vive le oueb libre et participatif et vive la france et bisou !

  • L'appli «inutile» du jour, Readme Toaster

    Il y a quelques jours, j'ai vu passer un article sur le contenu idéal d'un Readme ( https://warriordudimanche.net/article1840/6448d4a15a710 ) et en partageant le lien sur mastodon, on a émis l'idée de coder un assistant de génération qui permette de faire ça simplement...

    Nicolas Delsaux* m'a alors passé quelques exemples d'applis déjà réalisées et - pour autant que j'ai pu en juger avec un test rapide - très bien foutues et très complètes:

    Hélas... vous me connaissez...

    le malheur était déjà en train de se produire: impossible d'empêcher mon cerveau de travailler en background façon «à la volette»

    alavolette.gif

    Du coup, si je voulais pouvoir faire autre chose, il fallait d'abord vider ma tête de ce «projet» LOL.

    Voici donc ReadmeToaster

    L'objectif est de pouvoir faire un readme rapidement, de pouvoir modifier «simplement» les éléments du contenu (ordre ou items), de pouvoir ajouter des captures d'écran, sélectionner une license...

    FireShot Capture  - Readme Toaster.png

    La capture d'écran parle d'elle-même: on peut même choisir de générer des fichiers séparés pour certaines parties (Roadmap, Changelog...)

    Configuration

    La configuration des items se fait via le fichier config/patrs.json qui contient les objets, leur type (select/text/textarea etc), leur titre/label, leur placeholder, leur attribut name etc.

        "Name":{
            "type":"text",
            "title":"The project name",
            "name":"name",
            "placeholder":"ReadmeToaster",
            "class":"name",
            "required":"required"
        },
        "Description":{
            "type":"textarea",
            "title":"A short description (what's the project's purpose ?)",
            "name":"description",
            "placeholder":"A tiny webapp to create normalised readme files",
            "class":"description"
        },
        "Installation":{
            "type":"textarea",
            "title":"How to install or deploy ?",
            "name":"installation",
            "placeholder":"Just copy the folder onto your server and that's it... Noooo, I'm kidding !",
            "class":"install"
        },
        "Contribute":{
            "type":"textarea",
            "name":"contribute",
            "placeholder":"* translations,n* bug finding",
            "class":"text",
            "title":"Explain how to contribute"
        },
        "Contribute in a separated file":{
            "type":"checkbox",
            "name":"contribute_separate",
            "title":"Put contribute in a separate file",
            "placeholder":"",
            "class":"",
            "value":"contribute_text"
        },

    On peut ainsi facilement ajouter, modifier ou déplacer des items dans le frontend sans mettre les doigts dans le code. Si on peut pouvoir séparer un contenu dans un fichier à part, on colle un item checkbox dont le nom est ITEM_separate.

    Le fichier généré sera un zip contenant tous les fichiers, y compris les éventuelles captures d'écran fournies.

    Conclusion

    Pas sûr que ça serve à quelqu'un vu que c'est plus un amusement qu'autre chose (ne me jugez pas), mais bon: si jamais quelqu'un le veut... c'est par là : https://outils.warriordudimanche.net/outils/readmetoaster/ et pour le télécharger: http://outils.warriordudimanche.net/outils/readmetoaster/?download

    ET EN TOUT CAS, C'EST PLUS DANS MA TÊTE !

    [*] Pub gratuite pour Nicolas

    [Solved] After upgrade to Mint 21, apache will not start - Linux Mint Forums

    Si après une MAJ vers linux mint 21.1 apache ne démarre plus et fait une erreur du genre

    apache2: Syntax error on line 146 of /etc/apache2/apache2.conf: Syntax error on line 3 of /etc/apache2/mods-enabled/php7.4.load: Cannot load /usr/lib/apache2/modules/libphp7.4.so into server: /usr/lib/apache2/modules/libphp7.4.so: cannot open shared object file: No such file or directory

    on peut rattraper le coup en désactivant php7.4 au profit de 8.1:

    sudo a2enmod php8.1
    systemctl restart apache2

    BronKOBOt (@bronkobot@botsin.space) - Faire un Bot Mastodon from scratch.

    Tiens... et si je faisais un bot pour poster une citation par jour tirée des passages de romans que j'ai sélectionnés et stockés su ma Kobo ?!

    C'est par ces mots que j'ai commencé à galérer... comme quoi, il suffit d'une idée à la con pour se lancer dans tout un merdier pourtant parfaitement facultatif ...

    Le postulat de départ

    Je veux qu'un BOT mastodon poste une citation de mes bookmarks de liseuse DONC il faut récupérer ces passages bookmarkés.

    Donc, il faut trouver le fichier de base de donnée.

    Puis il faut extraire les données intéressantes.

    Puis utiliser ces données dans un BOT qui sera appelé une fois par jour.

    Étape 1: trouver et comprendre les données sur la KoBo

    En fouillant un peu, on trouve un fichier sqlite (JOIE) dont le chemin est .kobo/KoboReader.sqlite

    Comment différencier la base de   livres des autres ?!    Ben elle pèse plus de 700mo...    C'est un signe.

    Un passage par DBBrowser pour SQlite permet de jeter un oeil sur la structure des données.

    Idéalement, il me faut deux informations: la citation et le titre du bouquin dont elle est extraite.

    drame.jpeg

    En fait les titres se trouvent dans la table content et les annotations dans la table Bookmark

    deux tables

    Je pourrais utiliser Calibre et chercher un moyen de faire un export complet de ces deux données uniquement. Pas sûr que ça marche. Ou alors faire un export via le DBexplorer pis me retaper le truc à chaque export...

    Étape 2 : extraire les données et les préparer pour le Bot

    En vieux programmeur qui bricole, je vois là un prétexte pour coder une petite appli en python qui se chargera de l'extraction.

    Mon problème, c'est que je me sers des notes de la Kobo pour retenir des passages intéressants mais aussi, parfois, pour noter vite fait un mot de vocabulaire espagnol que je ne connaissais pas et dont je veux conserver la traduction. Mais ces mots de vocabulaire ne sont pas des citations: il faudrait donc les virer à la main à chaque fois. C'est chiant.

    L'appli devra donc permettre de filtrer les citations avant de générer un fichier exploitable par le bot.

    Pour faire court

    J'ai fait l'appli en question: elle permet donc de récupérer les données, filtrer en fonction de la longueur de la citation ou du fait qu'elle est ou pas accompagnée d'une note personnelle...

    Capture du 2022-12-03 15-57-22.png

    On peut formater les données selon plusieurs modèles (HTML, Json, Markdown, TXT brut, BOT) voire même créer son propre format (genre %title:«%quote» )

    Si ça intéresse quelqu'un,   contactez-moi vu que j'ai la  flemme de mettre ça là

    Voilà le ZIP : Kobone : KOBO Note Extractor

    Étape 3 : coder un bot en PHP afin de l'appeler par la suite avec un CRONJob.

    Rien d'extraordinaire ici: je fais un script qui parse le fichier obtenu à l'étape précédente, tire une citation au hasard et la poste sur le compte Masto du Bot.

    Le point le plus intéressant du bouzin est plutôt la fonction servant à poster sur un compte mastodon:

    
    define('TOKEN','letokendesécuritéquetuchopesdansmastodon');
    define('MASTODON_URL','https://botsin.space/'); // Ici, il faut coller l'url de votre serveur mastodon
    define('HEADER',"Citation du jour:");
     function post2Mastodon($data=null){
            if (!$data){return false;}
            $headers = [
              'Authorization: Bearer '. TOKEN
            ];
            $data=[
                'status'=> HEADER.$data,
                'language'=>"fr",
                'visibility' => 'public'
            ];
            $ch_status = curl_init();
            curl_setopt($ch_status, CURLOPT_URL,  MASTODON_URL.'/api/v1/statuses');
            curl_setopt($ch_status, CURLOPT_POST, 1);
            curl_setopt($ch_status, CURLOPT_POSTFIELDS, $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);
            return $output_status;
        }
    

    Étape 4: Créer une appli Mastodon pour avoir un jeton d'utilisation

    Aller sur le compte mastodon en question, puis dans les préférences.

    Cliquer sur «developpement» puis «Nouvelle application».

    Remplir le formulaire simplissime puis valider. Cliquez ensuite sur le nom de votre application dans la nouvelle page et copiez votre jeton d’accès. C'est celui-ci qu'il faut coller dans le script PHP (dans la constante TOKEN)

    Étape 5 : Définir un Cronjob

    Direction le panneau de config de votre hébergement, rubrique cronjob. Sur Cpanel c'est là :

    Capture du 2022-12-03 16-11-42.png

    Définissez la fréquence (pour moi une fois par jour) et l'heure (8:00).

    Ensuite, il faut définir la commande qui va appeler le script du BOT: wget fera l'affaire...

    wget -qO /dev/null http://xxxxxxxxxxx.xx/index.php

    L'option -q pour quiet et -O /dev/null pour éviter d'avoir un fichier de sortie qui se crée à la racine.

    Capture du 2022-12-04 11-10-50.png

    Fin

    Une fois tout ça terminé, j'ai bien un bot qui poste une citation à 8:00 tous les jours.

    capture du bot

    Bon, elles ne seront pas toujours bien formatées vu que la sélection de texte sur liseuse c'est un peu touchy... mais c'était plus pour apprendre à le faire qu'autre chose...

    Pis ça m'a permis de me  remettre à Python...

    https://botsin.space/@bronkobot

    Optipic: une «api» pour optimiser les images

    Le cadeau du jour: un script qui permet d'automatiser l'optimisation d'une image pour le ouaibe sans passer par une appli quelconque.

    Le problème

    Tout le monde est d'accord pour affirmer qu'il est indispensable de minimiser le poids des pages web et que dans cette optique, le premier geste - après avoir viré les bibliothèques inutiles bien entendu - reste l'optimisation des images.

    J'avais vu passer un article fort bien écrit sur ce sujet mais hélas, j'ai omis de le bookmarker et paf: le voilà perdu dans les méandres de mon historique sur un des ordinateurs que j'utilise.

    Tout le monde est d'accord sur le principe mais souvent, c'est comme l'écriture de la doc ou les tests unitaires: on a la flemme de s'y coller...

    J'ai parfaitement conscience  de la déferlante de commentaires  que cette comparaison risque  de me valoir !

    Ze solution

    L'idéal serait bien sûr que l'optimisation soit transparente et automatique... genre: tu te contentes de passer à la balise img l'URL de l'API avec celle de l'image et POF, tu as l'image en version optimisée.

    Comment ça   «t'es pas cap' ?»

    Optipic est donc un script auquel on passe l'URL d'une image, le format souhaité, le niveau de qualité et -éventuellement - la largeur maximum pour obtenir en retour l'image transformée.

    Les paramètres sont les suivants:

    • i ➜ l'url de l'image
    • maxwidth ➜ la largeur maximum de l'image (opt.)
    • format ➜ le format de sortie de l'image : jpg,gif,png,webp,avif (PHP 8 minimum pour l'avif)
    • quality ➜ la qualité (niveau de compression) de 0 à 100

    Le script renvoie directement l'image transformée avec le header adéquat et du coup, c'est transparent pour HTML/CSS.

    Notez que l'image optimisée est sauvée dans le dossier rendered/ afin d'éviter une charge inutile: si une image a déjà été optimisée, le script la sert directement au lieu de la refaire à chaque fois.

    But there's more !

    Même si ce script est déjà à ce stade absolument fabuleux (si, si !), je me suis dit que les paramètres risquaient de se répéter et qu'il pouvait s'avérer fastidieux de retaper le tout à chaque fois. Par conséquent, j'ai ajouté la possibilité de créer des scripts d'optimisation - un peu comme dans scriptopic.

    Ainsi, si vous placez un fichier PHP contenant les paramètres dans le dossier scripts/ , vous pouvez l'appeler via le paramètre $_GET script:

    Exemple: je cree scripts/webp.php et je mets dedans:

    
    // webp  50%
    $params=[
        'format'        =>'webp',
        'quality'       =>50,
        'maxwidth'      =>null
    ];
    

    Puis je l'appelle en faisant : api.url/?script=webp&i=http:/image.url/pic.jpg

    Pour le moment, il y a quatre scripts: jpg80,jpg70,avif,webp... à vous de créer les vôtres en fonction de vos besoins...

    Et ça marche ?

    Ben j'ai fait un test dans ce blog pour voir avec mon image de titre LOL:

    version originale

    qui pèse 113 ko en jpg

    Puis avec son optimisation via le script webp ci-dessus:

    version optimisée

    qui ne pèse plus que... 18 ko en webp 50%

    Et ça juste en rajoutant https://api.warriordudimanche.net/optipic/?script=webp&i= dans le chemin de l'image.

    la classe

    En cas d'erreur ?

    Si Optipic ne parvient pas à créer l'image, il crée une image d'erreur à la place, histoire de voir le souci quand même...

    la classe

    Ce comportement peut être débrayé avec la constante ERROR_PIC ligne 29.

    Test, téléchargement pis tout ça

    Comme pour toutes les api de ma page, le script est téléchargeable via le ?download : https://api.warriordudimanche.net/optipic/?download et testable au même endroit: https://api.warriordudimanche.net/optipic/?i=...

    Nota bene

    1. Pensez bien à mettre le paramètre d'URL (i) en dernier car sinon, php inclura les paramètres dans l'URL passée
    2. Même avec un script vous pouvez toujours changer un paramètre. Exemple: ?script=webp&quality=30&i=xxx permet de changer la qualité précisée dans le script (50).
    3. Par défaut, le format de sortie est le jpeg mais c'est configurable dans la constante DEFAULT_FORMAT ligne 28

    Au passage, ce script utilise une classe que j'avais codée pour scriptopic: pictools. Grâce à elle, le travail d'optimisation tient en

    
        $picture=new pictool($params);
        $picture->load($url);
        if (!empty($params['maxwidth'])){
            $picture->resize($params['maxwidth']);
        }
        $picture->save($generated_picture_path);
        $picture->display();
    

    Cadeau !

    Merci qui ?!
    Qui a dit   jacky et michel ?!

    YoutubeRSS

    Hier, je me suis aperçu que le bookmarklet que j'avais fait pour trouver le flux RSS d'une chaîne youtube ne fonctionnait pas toujours 🤬: en effet, si l'URL de la chaîne n'est pas du type www.youtube.com/channel/xxxCHANNEL_IDxxx ça ne fonctionne pas... Or, les chaînes peuvent être aussi sous une forme dans laquelle le channel_id n'apparaît pas.

    zut flûte et cacaboudin

    Du coup, je m'y mets

    Au lieu de laisser youtube me chier dans les bottes, je me suis dit que, si le channel_id n'est pas dans l'URL, il doit être planqué quelque part dans le html de la page.

    En fouillant un peu, twingo bongo jannielongo bingo 🥳 J'ai trouvé ça en parsant avec (presque) la même regex que pour l'URL.

    con.jpeg

    J'ai donc codé vite fait une «api» qui renvoie l'URL du flux RSS d'une chaîne Youtube dont on fournit l'adresse.

    On peut l'utiliser avec le frontend minimaliste prévu, en faisant une requête GET ou via le bookmarklet qui va bien.

    Le tout est bien entendu utilisable, autohébergeable et modifiable, comme d'habitude

    Allez !

    Classe PHP pour GD + API: Scriptopic

    Il y a quelques jours, lassé de reprendre à zéro à chaque fois que je dois faire un truc avec GD sur PHP, je me suis dit que je pouvais faire une classe pour ça. Comme, exceptionnellement, j'avais un peu moins de deux heures de tranquillité, je m'y suis collé.

    Au bout du compte, une fois la classe codée, il faut bien la tester...😬

    drame.jpeg

    C'est le problème des codeurs : ils ont du mal à arrêter de coder 🤩. Du coup, me voilà en route pour un script exploitant pictools.php... et ce qui aurait du prendre deux heures a pris plusieurs jours de papa codeur (petit rappel: 1 h de papa codeur = 7,2 heures de codeur normal en zone de guerre, au cours actuel 💣)

    Bref, j'ai donc pondu une «api» avec un frontend permettant d'appliquer des transformations à une image à partir de son URL.

    😎 petite image, long discours, toussa.

    Capture du 2022-07-04 21-43-27.png

    Donc, on fournit l'URL de l'image puis on ajoute des actions les unes à la suite des autres. Certaines n'ont pas besoin de paramètres (emboss, sepia etc) et d'autres si (contrast, resize etc)

    Quand on clique sur un bouton action, on ajoute cette action à la liste avec, le cas échéant, l'input qui va bien pour les paramètres avec un placeholder de rappel.

    Ainsi, on peut resize l'image à une taille précise ou à un pourcentage de la taille normale: tous les paramètres de coordonnées et de taille peuvent être précisés en pixels ou en pourcentages.

    De plus, si on veut redimensionner l'image à une largeur en conservant le ratio automatiquement, il suffit de mettre -1 à la place de la hauteur: le script se démerdera tout seul.

    La config ci-dessus donne le résultat ci-dessous:

    pexels-photo-67818-large-758x505.jpeg

    L'image d'origine

    result.jpeg

    Le résultat donné par scriptopic

    Mais c'est pas tout

    Donc, scriptopic permet de retoucher une image automatiquement. OK.👍

    Mais cette image est utilisable directement depuis son URL de génération: si on colle l'URL précisée dans le cadre résultat, ça fonctionne. Avec un peu d'habitude, on peut le faire en direct (genre pour une image d'en-tête...). Comme les images retouchées sont sauvegardées avec un hash de l'url de requête, si on l'appelle à nouveau, elle ne sera plus générée mais simplement renvoyée (visible soulagement du serveur )

    Et aussi

    Comme des fois on a la flemme de faire une balise image, Scriptopic vous la donne directement: un double-clic et c'est copié prêt à coller...

    Mais ce n'est toujours pas tout... (vous êtes gâtés)

    Un truc rigolo, c'est que, comme pour Stamp, le front de scriptopic génère un bookmarklet en temps réel (c'est la deuxième ligne du cadre résultat): une fois satisfait de votre script, le bookmarklet généré permet de l'appliquer à l'image en cours: vous ouvrez l'image dans un onglet et clic-clac merci kodak.

    Si vous voulez simplement envoyer l'image en cours pour travailler dessus, le bookmarklet de base est dispo en footer.

    Atta atta, pars pas j'ai pas fini

    Histoire d'ajouter encore une feature, vous pouvez stocker des scripts, à la main, dans le dossier ... scripts/ . Vous utiliserez le nom du fichier dans l'url avec ?script=[nomdefichier]

    Ainsi, en sauvant le json de l'exemple (cadre «Script au format JSON») dans un fichier scripts/sepia.json vous pouvez ensuite l'appeler avec&script=sepia

    Vous pouvez vous faire une bibliothèque de scripts pour tout et les appeler directement au lieu de vous taper du json dans l'URL

    Tout est expliqué dans l'aide : https://api.warriordudimanche.net/scriptopic/?help

    Hé m'sieu m'sieu:  pourquoi à la main ?  C'est mieux avec un  ptit bouton pour sauver  le script, non?

    Ben parce que pour sauver sur le serveur, il faudrait un compte admin, donc un espace sécurisé et tout le toutim... et là, on parle pas du même projet

    En conclusion

    Le bouzin est testable là: https://api.warriordudimanche.net/scriptopic/

    Et téléchargeable ici: https://api.warriordudimanche.net/scriptopic/?download

    Je n'ai pas nettoyé le code, vu que je subis un harcèlement constant à la maison (lol), mais je le ferais, promis ! Le tout est en beta à l'arrache en licence amusez-vous avec.

    Je n'ai pas encore écrit de doc pour pictools_class.php qui se trouve dans le zip, mais c'est assez simple à utiliser et chaque méthode est «documentée»

    
    $picture=new pictool();// on peut mettre un array contenant les valeurs initiales des attributs : ['format'=>'png'] par exemple)
    $picture->load('www.moncul.sur/la_commode.jpeg');
    $picture->contrast(20);
    $picture->sepia();
    $picture->save("fichier.jpeg");
    $picture->display();
    

    Le script matrix qui alterne sketch et gaussian à plusieurs reprises puis colorise en vert

    Pas flippant du tout.

    Todo

    • Débugger, vu que ça va se dévoiler à l'usage plus intensif
    • ajouter le listage et l'usage des scripts sauvegardés dans le front.

    Stamp v1.0

    Dans la catégorie débranchement de cerveau, je vous propose une appli vigoureusement inutile mais totalement défoulatoire: Stamp.

    Cette appli/api vous donne la possibilité d'ajouter un tampon sur une image en un minimum d'opérations. Ainsi, vous pourrez passer :

    de ça

    1.jpg

    à ça

    2.jpeg

    A partir du frontend

    En partant de là : https://api.warriordudimanche.net/stamp/ vous remplissez l'URL et le texte, vous validez et hop.

    Capture du 2022-06-22 17-18-14.png

    Mais aussi avec le bookmarklet

    Comme toujours, le bookmarklet vous permet d'envoyer l'URL courante à Stamp: ouvrez l'image dans un nouvel onglet et cliquez sur le bookmarklet.

    pour les plus observateurs

    Bande de coquins, vous avez sans doute remarqué un autre bookmarklet à côté du premier... c'est un bookmarklet dynamique: grâce à lui vous pouvez créer des bookmarklets avec un texte spécifique.

    Par exemple, si vous envisagez d'utiliser souvent le tampon «dans ton cul», pourquoi le retaper à chaque fois ? Glissez ce lien dans la barre de favoris et let's the fun begins !

    Comme d'hab

    Fait à l'arrache, interrompu toutes les minutes mais avec amour, dévotion à l'absurdité du monde et mon ordi.

    PHP: “JPEG library reports unrecoverable error: Not a JPEG file: starts with 0x89 0x50” Error Solved – An Exploring South African

    Tiens, je ne savais pas que la bibliothèque GD avait une fonction imagecreatefromstring() qui permet de créer une ressource image à partir d'une chaîne.

    C'est très utile dans le cas où on récupère une image via une URL sur un site et qu'on veut lui appliquer un traitement.

    En effet, quand on veut faire ça «normalement», on a recours à imagecreatefrom[FORMAT] (imagecreratefromPng() par exemple), ce qui oblige à connaître l'extension ou au moins le type mime de l'image... et des fois, ça couille : l'URL ne contient pas l'extension ou alors il y a des paramètres GET dedans, bref, ça fait chmir.

    Avant, je partais vers la récupération de l'extension du fichier pour appeler la fonction adaptée... c'est chiant, sale et pas parfait comme solution (bugs de nom et besoin de télécharger localement l'image sous forme de fichier)

    $downloaded_pic=file_get_contents($url);
    file_put_contents($local_path_pic,$downloaded_pic);
    $ext=pathinfo($url)['extension'];
    $fun=$ext=='jpg'?'jpeg':$ext;
    $function_name='imagecreatefrom'.$fun;
    $img  = $function_name($local_path_pic);

    Heureusement

    Avec imagecreatefromstring(), ça passe tout seul, c'est plus propre, plus lisible et surtout, pas besoin du type de l'image ou d'un fichier local...

    
    if ($downloaded_pic=file_get_contents($url)){
        $image=imagecreatefromstring($downloaded_pic);
    }else{
        exit("Erreur de téléchargement de l'image");
    }
    

    On peut même récupérer les dimensions de l'image avec un équivalent de getimagesize() : getimagesizefromstring() !

    Appli: Metabook - search ebooks on multiple websites

    Parfois un pouet sur Mastodon pour partager une URL et une idée concorde avec un truc que t'avais déjà fait : https://framapiaf.org/@bronco/108423992250980547

    Ainsi, Gilles me fait passer une adresse de métamoteur de recherche d'ebooks ( https://recherche-ebook.fr/ ) tout en notant que ce serait bien de faire une version qui soit plus propre... (pas de JS, de redirections, de pubs etc..)

    therese.jpeg

    écoutez Thérèse, comme la vie est savoureuse, n'est-ce pas...

    Il se trouve que je m'étais fait un script dont le but était justement de charger des urls, de les parser, de récupérer et d'organiser du contenu.

    Ça s'appelle Slurp
    Pour faire simple, on crée des «profils» correspondant à une série d'URL avec la regex de parsing et le template correspondants. Il suffit alors d'appeler le profil pour obtenir une page de résultats mise en forme.

    Comment ça marche ?

    1. on accède au script : ?p=<profil>
    2. slurp accède au fichier de configuration du profil dans packs/<profil>.php
    3. pour chaque url du pack, il charge la page, la parse, met en forme les données dans le template

    Le pack est un array du type:

    $packs['<profil>']=[
        [
            'url'=>'http://urltoparse.com/',
            'pattern'=>'REGEX PATTERN with (?<name>..) capture',
            'template'=>'<li> HTML Template where data is inserted to : use %name% '
        ],
        [
            'url'=>'http://urltoparse.com/',
            'pattern'=>'REGEX PATTERN with (?<name>..) capture',
            'template'=>'<li> HTML Template where data is inserted to : use %name% '
        ],
    
    ];

    Dans le template de chaque url,

    • on peut utiliser %variable% pour placer les captures regex : (?<title>[^"]*?)%title%
    • deux variables sont toujours accessibles:
      • %ROOT% pour accéder à l'url du pack
      • %DOMAIN% pour accéder au domaine de cette url (pour compléter une URL relative par exemple)
    Ya plus qu'à   adapter

    J'ai ajouté la possibilité de créer un dossier au nom du pack contenant un header et un footer pour qu'on puisse faire un site à partir d'un profil. packstemplates/<profil>/

    J'ai ensuite créé un pack contenant les principaux sites d'epubs, cherché les patterns regex...

    Et voilà: metapub cherche sur six sites en même temps: http://slurp.warriordudimanche.net/?p=ebook

    meta.jpg

    Comme d'hab

    1. c'est fait à l'arrache, mais vous avez l'habitude
    2. c'est cadeau, faites-en ce que vous voulez: avec slurp, vous pouvez parser les sites que vous voulez (warez, catalogues, porno... )
    3. vous pouvez installer slurp sur votre serveur et adapter le pack ebook au fur et à mesure que des changements se font (domaine, html de la page etc)
    4. vous pouvez télécharger slurp avec le pack ebook ici: http://slurp.warriordudimanche.net/?download

    A venir ?

    • On peut déjà commencer par faire une UI moins dégueu, ce sera pas mal
    • slurp permet de récupérer le résultat en json mais le RSS n'est pas encore implémenté...
    • ajouter des sites... et les maintenir.

    Enjoy !

    Fil RSS des articles