tag:linuxfr.org,2005:/tags/quick-and-dirty/publicLinuxFr.org : les contenus étiquetés avec « quick-and-dirty »2019-05-28T21:34:16+02:00/favicon.pngtag:linuxfr.org,2005:Diary/385322019-05-26T14:24:38+02:002019-05-26T20:18:18+02:00Récupérer une liste de lecture AppleLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<p>Je suis récemment allé à une soirée où le choix musical m'a plu. La personne qui mettait sa musique a découvert qu'elle pouvait me partager sa liste en m'envoyant un lien qui pointe vers <code>https://music.apple.com/fr/playlist/[quelque chose]</code>.</p>
<p>Je n'ai pas iTunes. Mon but : récupérer cette liste et en faire un truc que je peux utiliser. Ce journal est aussi un prétexte pour jouer avec <a href="https://stedolan.github.io/jq/">jq</a>, un outil pour faire des requêtes sur des données formatées en JSON.</p>
<p>Prenons une liste trouvée au hasard sur internet et travaillons dessus en mode bidouille rapide et sale : <a href="https://music.apple.com/us/playlist/playlist-by-me/pl.ae7cd2db31fc4d519725b6747b9074a5">https://music.apple.com/us/playlist/playlist-by-me/pl.ae7cd2db31fc4d519725b6747b9074a5</a></p>
<p>Nous avons besoin de :</p>
<ul>
<li>Firefox et son ardoise Javascript</li>
<li>un éditeur de texte</li>
<li>un shell</li>
<li><code>jq</code></li>
<li><code>grep</code></li>
<li><code>curl</code></li>
</ul>
<p>Allons visiter la liste avec Firefox. On est accueilli par un bandeau « Vous devez activer les DRM pour certaines des pistes audio ou vidéo de cette page ». On va pouvoir ignorer ce message, cliquer sur sa croix et continuer notre affaire.</p>
<p>La liste est affichée avec des éléments HTML simples. Avec les outils de développement, on repère vite que :</p>
<ul>
<li>chaque morceau est dans un élément avec la classe <code>tracklist-item__text</code>
</li>
<li>dans les enfants de cet élément, on trouve le nom du morceau dans l'attribut <code>aria-label</code> d'un élément de classe <code>spread</code>
</li>
<li>dans les enfants de cet élément, on trouve les artistes dans un attribut <code>data-test-song-artist-url</code>
</li>
</ul>
<p>Sortons l'ardoise Javascript (Maj+F4). Dans cette ardoise, on peut lancer des codes en les sélectionnant et en faisant Ctrl+L.</p>
<p>Pour récupérer la liste des nœuds correspondant aux morceaux :</p>
<pre><code class="javascript"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s2">".tracklist-item__text"</span><span class="p">)</span></code></pre>
<p>Ou sa version supposément plus efficace : </p>
<pre><code class="javascript"><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="s2">"tracklist-item__text"</span><span class="p">)</span></code></pre>
<p>On va appliquer une fonction à chacun de ces éléments, pour récupérer le nom et l'artiste de chaque morceau.<br>
Pour cela on va utiliser la fonction <code>map</code>, qui appelle la fonction qu'on lui donne sur chaque élément et qui retourne un tableau contenant tous ces résultats. <code>map</code> est une méthode des tableaux, il faut donc convertir le résultat des expressions précédentes en tableau.</p>
<p>À l'ancienne :</p>
<pre><code class="javascript"><span class="p">[].</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="s2">"tracklist-item__text"</span><span class="p">))</span></code></pre>
<p>Avec la syntaxe de décomposition :</p>
<pre><code class="javascript"><span class="p">[...</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="s2">"tracklist-item__text"</span><span class="p">)]</span></code></pre>
<p>Sur ce tableau, on peut appeler <code>map</code> sur une fonction qui prend l'élément HTML correspondant au morceau, et qui le transforme en un objet contenant son titre et son artiste. On rajoute JSON.stringify pour récupérer le JSON :</p>
<pre><code class="javascript"><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">([...</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="s2">"tracklist-item__text"</span><span class="p">)]).</span><span class="nx">map</span><span class="p">(</span>
<span class="nx">track</span> <span class="p">=></span> <span class="p">({</span>
<span class="nx">title</span><span class="o">:</span> <span class="nx">track</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">".spread"</span><span class="p">).</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s1">'aria-label'</span><span class="p">),</span>
<span class="nx">artist</span><span class="o">:</span> <span class="nx">track</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">"[data-test-song-artist-url]"</span><span class="p">).</span><span class="nx">dataset</span><span class="p">.</span><span class="nx">testSongArtistUrl</span>
<span class="p">})</span>
<span class="p">));</span></code></pre>
<p>Avec Ctrl+L, on se retrouve avec un tableau du genre <code>[{'title': 'blah blah', 'artist': 'qqun'}, …]</code>.</p>
<p>On enregistre ça dans un fichier <code>liste.json</code>. Et là, on peut faire certaines choses :</p>
<p>Concaténer artiste et titre en vue de faire une recherche :</p>
<pre><code class="sh">jq -r <span class="s1">'map(.artist + " " + .title)'</span> liste.json</code></pre>
<p>L'opérateur <code>map</code> applique une transformation à chaque élément. L'opération est ici une concaténation de l'artiste et du nom du morceau. On obtient le résultat au format JSON.</p>
<p>Même chose, mais avec un résultat par ligne (sans JSON) :</p>
<pre><code class="sh">jq -r <span class="s1">'map(.artist + " " + .title) | .[]'</span> liste.json</code></pre>
<p>Obtenir les adresses de recherche correspondantes sur YouTube :</p>
<pre><code class="sh">jq -r <span class="s1">'map(.artist + " " + .title) | @uri "https://www.youtube.com/results?search_query=\(.[])"'</span> liste.json</code></pre>
<p>Dans une fonction qui lit le fichier json dans son entrée :</p>
<pre><code class="sh">youtube_searches<span class="o">()</span> <span class="o">{</span>
jq -r <span class="s1">'map(.artist + " " + .title) | @uri "https://www.youtube.com/results?search_query=\(.[])"'</span>
<span class="o">}</span></code></pre>
<p>Étant donnée une liste d'adresse de recherche YouTube, récupérer l'adresse du premier résultat à coup de <code>curl $URL | grep -o '/watch?…'</code>. Attention, la fonction suivante n'est pas très polie, elle fait une requête vers YouTube par morceau. Vous pouvez vous faire kicker par YouTube. Aussi, j'ai rajouté un petit <code>sleep 5</code> pour limiter les dégâts : </p>
<pre><code class="sh">youtube_first_results<span class="o">()</span> <span class="o">{</span>
<span class="k">while</span> <span class="nb">read</span> line<span class="p">;</span> <span class="k">do</span>
<span class="nb">printf</span> <span class="s2">"https://www.youtube.com%s\n"</span> <span class="s2">"</span><span class="k">$(</span>curl -s <span class="s2">"</span><span class="nv">$line</span><span class="s2">"</span> <span class="p">|</span> grep -o <span class="s1">'/watch?v=[^"]\+'</span> <span class="p">|</span> head -1<span class="k">)</span><span class="s2">"</span>
sleep <span class="m">5</span>
<span class="k">done</span>
<span class="o">}</span></code></pre>
<p>Le script complet :</p>
<pre><code class="sh"><span class="ch">#!/usr/bin/env sh</span>
youtube_searches<span class="o">()</span> <span class="o">{</span>
jq -r <span class="s1">'map(.artist + " " + .title) | @uri "https://www.youtube.com/results?search_query=\(.[])"'</span>
<span class="o">}</span>
youtube_first_results<span class="o">()</span> <span class="o">{</span>
<span class="k">while</span> <span class="nb">read</span> line<span class="p">;</span> <span class="k">do</span>
<span class="nb">printf</span> <span class="s2">"https://www.youtube.com%s\n"</span> <span class="s2">"</span><span class="k">$(</span>curl -s <span class="s2">"</span><span class="nv">$line</span><span class="s2">"</span> <span class="p">|</span> grep -o <span class="s1">'/watch?v=[^"]\+'</span> <span class="p">|</span> head -1<span class="k">)</span><span class="s2">"</span>
sleep <span class="m">5</span>
<span class="k">done</span>
<span class="o">}</span>
<<span class="s2">"liste.json"</span> youtube_searches <span class="p">|</span> youtube_first_results >> liste-youtube.txt</code></pre>
<p>Si vous souhaitez télécharger les morceaux plutôt qu'avoir leur liste, des outils font ça très bien et la fonction <code>youtube_first_results</code> est redondante avec des fonctionalités de téléchargement à partir d'une chaîne de recherche qui existent déjà.</p>
<p>Bon dimanche, et bon vote pour celles et ceux qui voteront cet après midi !</p>
<div><a href="https://linuxfr.org/users/raphj/journaux/recuperer-une-liste-de-lecture-apple.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/117314/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/raphj/journaux/recuperer-une-liste-de-lecture-apple#comments">ouvrir dans le navigateur</a>
</p>
raphjhttps://linuxfr.org/nodes/117314/comments.atomtag:linuxfr.org,2005:Diary/355292015-01-09T20:22:08+01:002015-01-09T22:17:59+01:00Des bookmarks dans mon terminal !Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<p>Coucou à tous !</p>
<p>Je voulais vous partager une astuce toute simple que je viens de mettre en place sur mon ordi, en espérant que ça puisse servir à d'autre.</p>
<p>Il m'arrive régulièrement d'avoir simultanément plusieurs dossiers de travail en console, et je voulais pouvoir passer facilement de l'un à l'autre en console. Je me suis donc créé deux commandes shell : <code>x</code> et <code>ccd</code>. Je les ai appelé comme ça par ce que je manquait d'inspiration, que <code>x</code> c'est cour, et que <code>ccd</code> ça ressemble à <code>cd</code>, et que c'est ’dredi :) L'installation est très simple : copier-coller le code suivant dans votre ~/.truc-chose-shell-rc. On peut bien sur tout mettre sur deux lignes, mais je me suis dis que ça serais plus écrit compréhensible comme ça :</p>
<pre><code>function ccd() {
if [ -r ~/.signet/save$1 ]
then
cd "$(cat ~/.signet/save$1)"
else
echo >&2 "Le signet $1 n'existe pas"
fi
}
function x() {
pwd > ~/.signet/save$1
pwd > ~/.signet/save
}
</code></pre>
<p>Pour les plus mauvais en shell, voici comment s'en servir :</p>
<p>Concrètement la commande <code>x</code> sans argument sauve le dossier courant dans un fichier, ce qui me permet d'y revenir plus tard avec la commande <code>ccd</code>. Si j'ajoute une argument, par exemple <code>x signet1</code> alors <code>ccd signet1</code> me permettra de crée un signet nommé, et me permettre d'y revenir plus tard avec <code>ccd signet1</code>. Bonus sur la cerise : vu que les signets sont sauvés dans des fichiers, alors, ils sont persistant au reboot. NB : <code>ccd</code> sans arguments permet toujours d'aller dans le dernier dossier enregistré (avec ou sans signet nommé).</p>
<p>Voila, c'est tout. Certes ce n'est pas grand chose, et la plus part d'entre vous savent faire bien mieux que moi, mais je pensais que ça valais la peine d'être partagé. Le shell n'étant pas du tout ma spécialité, je suis ouvert à toutes critiques.</p>
<p>Et vous, vous avez d'autres astuces que vous utilisez tous les jours à partager ?</p><div><a href="https://linuxfr.org/users/robin--2/journaux/des-bookmarks-dans-mon-terminal.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/104441/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/robin--2/journaux/des-bookmarks-dans-mon-terminal#comments">ouvrir dans le navigateur</a>
</p>
robinhttps://linuxfr.org/nodes/104441/comments.atom