tagutil: gérer vos tags audio en CLI
tagutil koi-est-ce ?
En cherchant un outil puissant pour gérer les tags et les noms de mes fichiers de musique. j’ai trouvé … Rien.
Amarok ou quelques outils graphiques font ça pas trop mal, mais jamais tout ce que j’avais besoin. De plus je voulais un truc en ligne de commande, histoire de pouvoir le planter dans des scripts, éviter les click, abuser de la completion ZSH et toussa.
Comme j’ai rien trouvé je l’ai codé (CLAP CLAP monself). C’est codé en C (un vrai langage d’homme), ça utilise taglib pour modifier et lire les tags des fichiers audios.
Ze FM
Comme je suis chic (et que comme je pond un article tout les six mois, faut bien que je les remplisse un peu) voici le FM aka le __Fuc^WFriendly Manual__. lorsque l’on lance tagutil sans arguments ça donne ça:
TagUtil v1.1 by kAworu.
usage: ./tagutil <opt> [optarg] <files>
Modify or output music file's tag.
Options:
-- <files> : only show files tag. -- is not needed but useful if the first file
argument may be a file that could match an option.
-e <files> : show tag and prompt for editing (need $EDITOR environment variable)
-r <PATTERN> <files> : rename files with the given PATTERN. you can use keywords in PATTERN:
title(%t), album(%a), artist(%A), year(%y), track(%T), comment(%c),
and genre(%g). example: "%A - %a - (%T) - %t"
-t <TITLE> <files> : change title tag to TITLE for all given files
-a <ALBUM> <files> : change album tag to ALBUM for all given files
-A <ARTIST> <files> : change artist tag to ARTIST for all given files
-y <YEAR> <files> : change year tag to YEAR for all given files
-T <TRACK> <files> : change track tag to TRACK for all given files
-c <COMMENT> <files> : change comment tag to COMMENT for all given files
-g <GENRE> <files> : change genre tag to GENRE for all given files
afficher
lorsque l’on apelle tagutil avec seulement des fichiers en arguments (pas d’option) il va afficher les tags du/des fichiers (dans l’ordre donné). Attention, si un fichier en argument n’existe pas ou n’est pas un fichier tagutil affichera une erreur et se terminera.
% ./tagutil music/JOHNNY_CASH_-_at_san_quentin_-_13_-_folsom_prison_blues.ogg
FILE: "music/JOHNNY_CASH_-_at_san_quentin_-_13_-_folsom_prison_blues.ogg"
title - "Folsom Prison blues"
album - "At San Quentin"
artist - "Johnny Cash"
year - "1969"
track - "13"
comment - ""
genre - "Country"editer
Pour éditer en masse ou par script, les options -t|-a|-A|-y|-T|-c|-g servent à éditer le champ correspondant de tous les fichiers donnés en argument (c’est rarement utile pour -t et -T d’avoir plus d’un fichier, mais bon). par exemple:
% tagutil -A "Johnny Cash" music/JOHNNY_CASH*pour éditer en mode interactif, on peut utiliser l’option -e. Pour chaque fichier donné en argument tagutil va afficher les tags, puis demander à l’utilisateur s’il veut éditer les tags. Si l’utilisateur répond y|yes $EDITOR est lancé pour éditer les tags (très convi d’éditer avec son éditeur favori). Exemple:
% tagutil -e music/JOHNNY_CASH*renommer
tagutil sait renommer un fichier en fonction de ses tags (c’est en faite la fonctionalité principale dont j’avais besoin qui m’a poussé à écrire tagutil). pour chaque fichier donné en argument, tagutil va le renommer suivant le “template” donné à l’option -r. Si l’ancien nom et le nouveau sont pareil, il ne fait rien, sinon il affiche l’ancien nom et le nouveau puis demande une confirmation de l’utilisateur. Si un fichier existe déjà avec le nom de destination, tagutil va abandonner et ne pas renommer le fichier pour éviter d’effacer un fichier existant. Un petit exemple si on veut renommer notre fichier avec le template “<artist> - <album> - <title>”:
% ./tagutil -r '%A - %a - %t' JOHNNY_CASH_-_at_san_quentin_-_13_-_folsom_prison_blues.ogg
rename "JOHNNY_CASH_-_at_san_quentin_-_13_-_folsom_prison_blues.ogg" to "Johnny Cash - At San Quentin - Folsom Prison blues.ogg" ? [y/n] y
% ls "Johnny Cash - At San Quentin - Folsom Prison blues.ogg"
Johnny Cash - At San Quentin - Folsom Prison blues.oggInstallation
tagutil est géré avec un repository mercurial. l’adresse est https://hg.kaworu.ch/tagutil/. C’est donc possible soit de faire un clone du repository:
% hg clone https://hg.kaworu.ch/tagutil/ou de se rendre sur l’url et de télécharger une archive (gz, zip, ou bz2).
Faite attention de prendre une version “tag” (genre v1.1) si vous voulez avoir une chance de pouvoir compiler car il est fort possible tip (le dernier commit dans le jargon mercurial) ne compile pas sur certains OS, voir pas tout court.
Pour la compilation voici ce qui est conseillé par la team de développement officielle (aka moi). N’oubliez pas d’installer la taglib avant de compiler tagutil :
# pour GNU/Linux
% cc -o tagutil -Wall -std=c99 -O2 -pipe -D_XOPEN_SOURCE=500 -ltag_c tagutil.c
# pour *BSD
% cc -o tagutil -Wall -std=c99 -O2 -pipe -I/usr/local/include -L/usr/local/lib/ -ltag_c tagutil.cEDIT: il y’a maintenant deux Makefile (merci bapt), choisissez le bon suivant votre OS et lancez make tagutil.
ToDo
Il y’aurait deux trois truc à faire (mais j’ai la flemme) comme gérer les
option avec getop() pour être plus “UNIX friendly”, utiliser les autohell pour le build. Il y certainement aussi
d’autres fonctionalité ou option qui pourraient être utile mais que j’utilise
pas donc n’hésitez pas à m’envoyer un mail si vous voulez ajouter une
fonctionalité etc.
Si y’en a qui ont le courage (des couilles quoi) n’hésitez pas à modifier
le code et mettre pleins de bugs dedans (j’ai l’habitude) ;)
tagutil est sous licence BSD, donc n’hésitez pas non plus à faire pleins
d’argent avec.
Posted in prog | 5 comments |
Un Camembert
et des graphiques !
dans l’esprit de la convitude des représentations de données, on trouve des jolis camembert.
je suis tombé sur un pdf de Stephen Few (”save the Pies for Dessert”) qui nous explique pourquoi les représentation de camembert saylemal et ifopa. Il est pas très long et assez interactif.
Bonne lecture ;)
what-i-dont-like-about-ruby/
Hein?
/me aime beaucoup Ruby (entre autre). Mais voilà, aucun langage de programmation n’est parfait, comme aucun outil n’est universel. Pour une tâche donnée, certains outils sont (parfait|bien|difficile|impossible).
Ce qui me chicane, c’est les [mauvaises argumentations][blog].
Malheureusement, on ne peut poster de commentaires sur ce blog, donc je fais un petit billet :)
FUNCTION CALLS WITHOUT PARENTHESES
foo = barIs bar a variable? Is bar a method? There’s no way to know for sure.
ah ? Ben si. s’il existe une variable bar, alors c’est la variable qui est utilisée, sinon c’est la méthode (et si aucun des deux n’existe, ça raise NameError).
Le fait de pouvoir appeler des méthodes sans parenthèse est très pratiques. Souvent ça améliore la lisibilité. Par exemple, grâce à ça, il est possible d’implémenter en Ruby des DSL (Domain Specific Langage) d’une lisibilité et facilité déconcertante. Voici un exemple piqué dans le projet libastag, où l’on décrit une chorégraphique à exécuter (on peut bouger les oreilles et changer la couleurs de leds) :
Choregraphy.new do
at time 0
set all leds to green
move left ear forward from degrees 10
endsi l’on était obligé de mettre des parenthèses, ça donnerait tout de suite moins cosmétique :
Choregraphy.new do
at(time(0))
set(all(leds(to(green))))
move(left(ear(forward(from(degrees(10))))))
end(ici le programmeur LISP sourit)
On a après un exemple en C et en PHP :
// C:
foo = bar(); // function
foo = bar; // variable
// PHP:
$foo = bar(); // function
$foo = $bar; // variableDommage, il faudrait aller un poil plus loin. continuons :
// Java
String str = "Hello world";
int[] ary = {12};
str.length() // function
ary.length // variableOui, cher lecteur, en Java il faut appeler length() pour avoir la taille d’un objet String, length pour avoir la taille un tableau, et pour les autres objets, ça dépend de l’implémentation :)
Personnelement, je pense que tous les dev Java se posent cette question avant d’écrire length : “String, array, ou autre chose ?”.
Ruby interdit l’accès aux variable d’instances. On utilise des méthodes public pour “simuler” l’accès et la modification de variables, mais cela reste des méthodes. On le fait parfois en Java également à grand coups de pioche setMyvar(arg) et getMyvar(). alors que Ruby donne du sucre syntaxique (omettre les parenthèse, permettre les méthodes avec =).
NO EXPLICIT RETURN
retourner implicitement la dernière évaluation d’une méthode est un concept magnifique de la programmation fonctionelle. Rien n’empêche en ruby d’écrire return, cela laisse justement la liberté au programmeur de choisir son paradigme de programmation !
First of all, in some cases you have to explicitly return anyway (e.g. at the beginning of a function)
En programmation fonctionel, si il faut écrire return, c’est qu’il y a un défaut de conception.
def f ary
return "pas glop" if ary.empty?
...
end
# devrais être écris
def f ary
if ary.empty?
"pas glop"
else
...
end
enddans le 2ème cas, la méthode f va retourner la dernière expression évaluée dans son bloc; le _if_ qui lui-même va retourner la dernière expressions évalue dans son bloc etc.
FUNCTIONS AND LAMBDAS AND PROCS AND BLOCKS
Confusingly, Procs created using proc or lambda behave differently from those created by Proc.new, but nobody really seems to understand those subtle differences.
(Ruby 1.9) Un objet Proc déclaré avec lambda, puis appelé avec un nombre d’argument plus petit/grand qu’attendu lève une exception ArgumentError (comme une méthode déclarée avec def), alors qu’avec Proc.new ou proc ou encore en bloc anonyme cette exception n’est pas levée (si vous apellez avec trop peu d’argument, il est fort probable qu’un autre exception soit levée, car les arguments manquant seront remplaçé par nil).
Proc#lambda? permet de savoir si le bloc se comporte comme s’il avait été déclaré avec lambda ou proc.
Proc.new { |i| i }.call # => nil
Proc.new {}.call(2) # => nil
lambda { |i| i }.call
ArgumentError: wrong number of arguments (0 for 1)
lambda {}.call(2)
ArgumentError: wrong number of arguments (1 for 0)Cela permet de choisir entre un objet Proc “strict” (qui réagit comme une Method) ou permissive. Tout ça est très bien documenté :
- “Changes in Ruby 1.9”
- rdoc de Kernel.lambda
- “Programming Ruby” (pp 343-345)
- “Ruby cookbook” (Recipe 7.1. Creating and Invoking a Block)
Instead of passing a block to a function, you pass it a lambda. This also makes it possible to pass multiple blocks to a single function, something that is not currently possible with Ruby.
Il est possible de donner un bloc de code, un objet Proc (qu’il soit construit avec proc, lambda ou Proc.new) ou une méthode définie avec def en paramètre d’une méthode. Il est également possible de donner plusieurs objets Proc à un méthode (ce qui est équivalent à donner deux bloc de code).
def justcall
yield
end
def hellodef
puts "Hello world"
end
helloproc = Proc.new { puts "Hello world" }
hellolambda = lambda { puts "Hello world" }
justcall &helloproc # "Hello world"
justcall &hellolambda # "Hello world"
justcall &(method :hellodef) # Hello world
def doboth first, second
first.call
second.call
end
doboth lambda { puts "FIRST" },
lambda { puts "SECOND" }TOO MANY SYNONYMS
- Enumerable#collect / Enumerable#map
- Enumerable#find / Enumerable#detect
- proc / lambda
- Array#length / Array#size
- …
All these pairs do exactly (or almost exactly) the same. Why does Ruby have all these synonyms?
Parfois, le almost fait toute la différence. Retourner un Array vide ou nil est différent, et il arrive qu’on aie besoin/envie d’un comportement.
La nature dynamique de Ruby nous permet de changer les class et les méthode déjà définie. Si je redéfini Enumerable#find (comme le fait Rails), le comportement “standard” est toujours disponible avec Enumerable#detect.
Les autres langage choisissent une syntax pour une méthode (length(), size(), len(arg)) et t’obligent à retenir leur choix arbitraire. Ruby te laisse le choix d’utiliser celui que tu préfère.
INJECT? EH?
Ruby’s inject method is basically a reduce or fold function with a different name. Why pick a new name for a function that usually goes a different name?
Enumerable#reduce est un alias de Enumerable#inject (depuis Ruby 1.9) voir ici
So what should we do now?
Rien n’est pas parfait, mais avant de critiquer il faut être sûr de quoi on parle.
“A bon entendeur”
Posted in prog | 2 comments |