Gospelled in MP3 under spotlight

Je fais de la musique depuis longtemps, sous licence creative commons CC(by). Pour obtenir un public plus large, je diffuse gratuitement depuis mon site et j’essaye d’être sur un maximum de services, et pour être suivi, j’ai mis en place une page podcasts toute simple et utilisée.

L’autre jour je suis allé sur Apple Podcasts Connect (https://podcastsconnect.apple.com) pour y constater que les stats ne sont pas disponibles alors que mon serveur vois bien plein de requêtes avec comme user agent « iTMS ». Bref, passons. Je vois en moyenne de 100 à 500 episodes par jour, écoutés au travers du podcast.

Parlant avec des utilisateurs de Spotify, je me dis qu’il doit y avoir un moyen d’être présent là aussi. Spotify est un gros player, ils acceptent les podcasts et j’ai cru comprendre qu’ils diffusaient de la musique. Gros potentiel pour moi.

Je me diffuse moi-même. Je vais sur Spotify for Creators, je crée un compte, j’indique l’URL de mon feed (http://habett.net/tracks.rss) et, alors que tout se passe bien jusqu’au bout, je finis par être inondé de messages « An episode of your podcast has been removed » !!!

En détail, chaque message indique que tel épisode est jugé comme non conforme à leur « content policy »:

Spotify for Creators supports the distribution of audio and video podcasts. Content that appears to be exclusively or primarily music is automatically taken down.

Si je comprends bien, de la musique, des podcasts, mais surtout pas le mélange des deux. Le pain, le beure mais surtout pas la tartine gratuite. J’imagine qu’ils font cela pour forcer les créateurs à passer par un organisme de gestion et/ou se blinder sur les questions de droits d’auteur en se déchargeant sur des opérateurs tiers. Techniquement, je ne vois aucune explication. Bref, cela ne vas pas avec les tout petits diffuseurs autonomes.


Gospelled in MP3 under spotlight

🤔 Sprite ou Vecteur

Interfaces graphiques oldschool (90s), GUI tout en sprites/bitmaps. Simple, efficace, binaire. Ensuite les vecteurs sont apparus à droite à gauche, essentiellement pour le texte typographique. Sur mon Acorn, on pouvait activer un mode antialiasing pour le texte et les résultats étaient non seulement magnifiques, mais aussi gracieux en très grandes tailles. A l’époque, les images en format vectoriel étaient très appréciées car réutilisables, souples et légères.

Quand le NeXT est apparu, le truc qui m’avait le plus impressioné, en plus de son boîtier cubique noir et de sa gestion du multitâche, était son mode d’affichage. Le mobilier des fenêtres, et surtout les icônes, sublimes, étaient en vectoriel (display postscript). Bref, un format issu du monde de l’impression, appliqué à une lignée (imaginée) de systèmes d’exploitation pour s’accommoder d’un futur dans lequel nous sommes arrivés.

Si plus personne ne discute réellement le fait que la typographie numérique soit basée sur des vecteurs, le reste de l’environnement est resté bitmap dans des proportions totalitaires. A l’époque où l’on est capable de faire du ray-tracing en temp réel, on reste bloqué avec des images non vectorielles. Si on regarde dans Xcode, il est demandé de fournir des logos et images en plusieurs définitions là ou un seul fichier vectoriel pourrait suffire. Ce futur est bien décevant.

Si je prend Pages.app, le mini traitement de texte sur Mac, on peut monter la taille des caractères très haut, 1000pt. A cette taille, le tracé (issu de vecteurs) reste parfaitement harmonieux.

Mon problème du jour, est exprimé par l’implémentation des emojis. Prenez un emoji et affichez-le dans une très grande taille, vous verrez surgir un infect mélange de pixel et de flou. Dès 256pt, la perte de qualité est gênante. Les émojis ne sont des caractères que fonctionnellement. Quel héritage triste Apple a-t-il hérité de NeXT ? LibreOffice sous Linux présente ce même problème, MSWord aussi j’imagine.

Ou aurait pu avoir des Emojis vectoriels, techniquement tout était prêt. Mais non, on a droit, puisque c’est en partie le problème à mon avis, à un mélange idiot. Imaginer un monde en vectoriel, adapté du jour au lendemain aux affichages sub-pixels intégré. Imaginez ce monde. La formalisation unicode est sans doute une très grande occasion manquée, emojis et autres aussi.

🤔

Chaque plateforme a son emojiset et la complexification du développement de cet eco-système est telle que c’est perdu. A l’époque des écrans 4K et plus, on en reste là. On fait transiter de gros fichiers plein de pixels inutiles et d’une qualité discutable. Zut pour les SVG/XML ? Fuck pour les PDFs sans graphiques bitmap/photos inclus ? Un fichier vectoriel peut encapsuler des bitmaps si vraiment il y a besoin mais la réciproque n’est pas vraie.

Peut-être que nous sommes dans un autre type de monde ? pixels/vecteurs/fractales ? Je ne sais pas. En attendant, on fait du ravaudage et on perds du temps.

Je voulais conclure sur l’ascii-art et Figlet, les logiciels de vectorisation, les IA qui génèrent des photos alors qu’elles figurent des vecteurs, mais il est trop tard. Trop tard. Désolé.


🤔 Sprite ou Vecteur

My Ranker

J’adore SolR mais certaines choses sont plus compliquées à faire. Je voulais me faire un algorithme de ranking personnel basé sur la pertinence (de base) et sur une valeur numérique (karma ou date par exemple), ainsi que donner plus d’importance à certains champs. Ainsi, sur mon SolrR 8, cela se formule comme ça (je ne mets ici que les paramètres différents d’une utilisation) :

defType=edismax

&q=remix test

&sort=product($qq,karma)+desc

&qq={!edismax v="remix test" qf="title^20 description^2 author^10 "}

J’aurais aimé mettre dans qq, v=$q au lieu de répéter la requête mais j’ai l’impression que ce n’est pas valable. En tout cas mon ranking est alors bien meilleur.

Enfin, pour ce qui est mettre un bonus aux documents les plus récents, toujours en edismax, j’ajoute: &bf=sqrt(sqrt(ms(dated))). Il est pertinent d’ajuster la fonction ms avec une origine temporelle du décompte: ms(mydatefield, 2000-01-01T00:00:00Z)


My Ranker

No Return (mails)

Je gère pour un site des envois d’e-mails personnalisés en masse. J’envoyais mais, au bout d’un certain temps, j’en ai eu mare de recevoir, par exemple, les messages d’absence en retour.

Au final, j’ai ajouté à ces messages des headers qui font le job, globalement car certains serveurs me résistent de par leur implémentation.

'X-Auto-Response-Suppress:' => 'OOF, DR, RN, NRN, AutoReply'
'Auto-Submitted:' => 'auto-generated'

C’est assez élégant et fonctionnel.


No Return (mails)

Deep structure JSON

J’aime bien le JSON mais je dois avouer que quand il s’agit de traiter des structures plus profondes (au delà des tables et des listes, et surtout les cas où la profondeur est variable (exemple: JORF), je suis assez démuni alors que je n’ai pas du tout ce problème avec du XML où il est facile de naviguer entre enfants et parents, etc.

J’avais fais des essais avec JSON::XPath et autres mais la syntaxe me dépasse car j’y vois des tonnes de confusions avec le XPath du XML (notamment à propos de la notion de. parent). Plutôt que de me prendre la tête , je me suis mis à chercher un convertisseur JSON vers XML.

Trouvé ici : https://stackoverflow.com/questions/17398601/how-to-create-xml-from-json-string-in-perl

use JSON::Any;
use XML::Simple;

my $convertor = JSON::Any->new();
my $data = $convertor->decode($json);
my $xml = XMLout($data);

J’adore!


Deep structure JSON

robots.txt

Historiquement, un fichier texte posé à la racine d’un serveur Web, nommé robots.txt, est une pseudo norme supposée déclarer le comportement toléré de la part des agents logiciels le visitant.

Grand amateur de scraping, je connais cette norme mais elle ne m’est d’utilité que pour refuser à mes intermédiaires certaines taches. Au fond je ne les respecte pas. Je suis même surpris que cette idée perdure. A vrai dire, je n’ai jamais participé à un site sur lequel ce serait une préoccupation.

L’idée est de lister les URLs autorisées/interdites. Le format de ce fichier fait même en sorte qu’il soit possible de décrire des politiques différentes robot part robot (agent par agent).

Imaginons un site public (administration d’Etat). Accepterions nous ouvertement qu’il procède à des distinctions agent par agent ? Discriminations non acceptables. Notons que j’ai vu un paquet de sites répondant à de tels critère mettre en place des restrictions type captcha sur des fichiers type robots.txt ou même des flux RSS !

Derrière chaque robot/agent il y a une personne/structure. Cela en ferait un sous-citoyen ? On ne scrape pas pour assouvir un désir malsain d’accrétion. On le fait globalement pour des traitements postérieurs que l’on aurait autrement fait sur des jeux de données, sous réserve qu’ils soient d’accès intelligibles et techniquement raisonnables. Surtout sur des sites étatiques. 

Je fais ce focus sur des sites publics car ils sont plus loin de ces parties du web où la monétisation par la publicité s’impose (?!?), et car ils sont redevables aux citoyens dont ils relèvent. 

Ce n’est pas un plaidoyer contre les distinctions droïds/humains, ni browser/agents. La distinction logiciels/agents est de plus en plus complexe. Un proxy vaut il un script à fin d’accessibilité, un curl pour archivage ?

Un dernier mot sur la tendance actuelle qui est de passer de jeux de données à des API publiques. Je n’ai pas de religion sur ce point mais au final j’aime que les cohabitent et que cela n’exclue pas le scraping.

Resistance is futile.


robots.txt

Let it be dark in javascript

Au début on se dit qu’il faut questionner le choix utilisateur avec une mediaQuery:

 (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)

Reste que si l’on est dans un contexte incertain, développement d’un add-on dans mon cas, se résoudre à cette simple requête est une mauvaise stratégies car le site sur lequel on vient se pluger lui peut ne pas adapter son style aux choix utilisateur (dark mode ou non).

Sur Firefox qui est mon browser de dev, je ne comprenais pas pourquoi j’obtenais « rgba(0, 0, 0, 0) » avec la ligne suivante sur des pages où le fond est blanc mais le système est en dark mode:

window.getComputedStyle(document.body,null).getPropertyValue('background-color');

A vrai dire, mon erreur était de comprendre cette ligne comme parlant de la couleur noire (0,0,0) alors que le dernier 0 indique en rgba que le fond est transparent, or le fond d’écran d’une page web est blanc. La proprieté (‘background’) retourne d’ailleurs ‘none’. Chrome et safari retournent une valeur rgb qui est plus simple à comprendre.

Au final, je pense être pas mal avec ce bloc:

var dark = false;
let bs = window.getComputedStyle(document.body,null);
let baco = bs.getPropertyValue('background-color');
  if(bs.getPropertyValue('background') == 'none') {
  if(!(/rgba.*,\s?0\)$/.test(baco))) {
    dark = true;
  }
} else {
  let sacos = baco.split(/,/);
  let moy = 128;
  if((sacos != null) && (sacos.length > 2)) {
    moy = (parseInt(sacos[0].replace(/\D+/g,''))+parseInt(sacos[1].replace(/\D/g,''))+parseInt(sacos[2].replace(/\D/g,''))) / 3;
  }
 
  if((moy < 128) && !(/rgba.*,\s?0\)$/.test(baco))) {
    dark = true;
  }
}

Au final, j’aime bien mon petit calcul pour essayer d’évaluer si la couleur est plutôt sombre ou claire.


Let it be dark in javascript

Linkedin’s code tag

Mon user script puis mon prototype d’add-on avait de manière récurrente des problèmes avec Linkedin.

Après moultes débugs, j’ai fini par comprendre qu’ils font en fait un usage très spécial de la balise <code>

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code

Pour linkedin, code se retrouve être une balise cachée dans laquelle ils embarquent des données.

Mon content script évitait déjà les balises script et autres styles mais de la à penser que le contenu des balises code doivent être ignorés, il faut vraiment avoir l’esprit tordu.

Avant ou après le rachat par MSFT ?

https://stackoverflow.com/questions/42530879/why-does-lindkedin-use-hidden-code-tags-in-their-updated-website


Linkedin’s code tag

Dans un browser, ça a l’apparence du web mais ce n’est pas du web

Faites une requête avec le mot « emprise » dans un moteur de recherche type google. Vous obtenez des résultats. C’est sur le web et dans un browser. Mon test pour dire que c’est du web est que c’est modifiable/remixable: par exemple:

document.evaluate('//text()[contains(.,"emprise")]',document.body,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);

Cela retourne des résultats avec lesquels ont peut jouer (console JS/DOM, user scripts, ..etc)

Par contre, si je vais sur docs.google.com, que je crée un document dans lequel je tape juste le mot « emprise », même en faisant attention à la case du texte, je n’obtiens rien avec le test précédent, mis à part un script de données qui contient ce même mot. En clair, il ne trouve pas de nodes textuelles contenant le mot en question. Et pour cause, l’affichage est en fait une balise canvas donc hors du DOM qui est l’essence du web/html. Autant mettre un binaire qui pointerai vers une VM. Ici le web n’est qu’un transport et le browser un simple réceptacle.

Ensuite le site en question trouve malin d’intercepter tous les événements clavier. Tout y passe sauf bien sûr ceux qui sont interceptés auparavant par le browser. Bref, on ne peux pas jouer ici. Ce n’est pas du web, désolé. Mauvais karma.


Dans un browser, ça a l’apparence du web mais ce n’est pas du web