Recherche de site Web

Créez votre propre cadre de balisage musical avec Groovy


Je vais séparer le framework que j'utilise dans une classe distincte, puis écrire un programme de test pour l'exercer.

Dans cette série, je développe plusieurs scripts pour m'aider à nettoyer ma collection de musique. Dans le dernier article, j'ai écrit et testé un script Groovy pour nettoyer l'assemblage hétéroclite des champs de balises. Dans cet article, je vais séparer le framework que j'utilise dans une classe distincte, puis écrire un programme de test pour l'exercer.

Installer Java et Groovy

Groovy est basé sur Java et nécessite une installation Java. Une version récente et décente de Java et Groovy pourrait se trouver dans les référentiels de votre distribution Linux. Groovy peut également être installé en suivant les instructions sur la page d'accueil de Groovy. Une alternative intéressante pour les utilisateurs de Linux est SDKMan, qui peut être utilisé pour obtenir plusieurs versions de Java, Groovy et de nombreux autres outils associés. Pour cet article, j'utilise les versions du SDK :

  • Java : version 11.0.12-ouverte d'OpenJDK 11 ;
  • Groovy : version 3.0.8.

Retour au problème

Si vous n'avez pas lu les parties 1 à 5 de cette série, faites-le maintenant afin de comprendre la structure prévue de mon répertoire musical, le cadre créé dans cet article et la manière dont nous récupérons les fichiers FLAC, MP3 et OGG.

  • Comment j'analyse mon répertoire musical avec Groovy
  • Ma bibliothèque open source préférée pour analyser les fichiers musicaux
  • Comment j'utilise Groovy pour analyser les pochettes d'album dans mon répertoire musical
  • Nettoyez les fichiers indésirables de votre répertoire musical à l'aide de Groovy
  • Nettoyer les balises musicales avec un script Groovy

La classe framework

Comme je l'ai mentionné à plusieurs reprises, en raison de la structure des répertoires musicaux, nous disposons d'un cadre standard pour lire les sous-répertoires des artistes, les sous-sous-répertoires des albums, la musique et les autres fichiers qu'ils contiennent. Plutôt que de copier ce code dans chaque script, vous devez créer une classe Groovy qui encapsule le comportement général du framework et délègue le comportement spécifique à l'application aux scripts qui l'appellent.

Voici le framework, déplacé dans une classe Groovy :

 1    public class TagAnalyzerFramework {
   
 2        // called before any data is processed
 3        Closure atBeginning
   
 4        // called for each file to be processed
 5        Closure onEachLine
   
 6        // called after all data is processed
 7        Closure atEnd
   
 8        // the full path name to the music library
 9        String musicLibraryDirName
   
10        public void processMusicLibrary() {
11            // Before we start processing...
12            atBeginning()
13            // Iterate over each dir in music library 
14            // These are assumed to be artist directories
  
15            new File(musicLibraryDirName).eachDir { artistDir ->
   
16                // Iterate over each dir in artist dir
17                // These are assumed to be album directories
18                artistDir.eachDir { albumDir ->
19                    // Iterate over each file in the album directory
20                    // These are assumed to be content or related
21                    // (cover.jpg, PDFs with liner notes etc)
22                    albumDir.eachFile { contentFile ->
   
23                        // Then on each line...
24                        onEachLine(artistDir, albumDir, contentFile)
25                    }
26                }
27            }
28            // And before we finish...
29            atEnd()
30        }
31    }

La ligne 1 introduit le nom de la classe publique.

Les lignes 2 à 7 déclarent les trois fermetures que le script d'application utilise pour définir les spécificités du traitement nécessaire. C'est ce qu'on appelle la délégation de comportement.

Les lignes 8 à 9 déclarent la chaîne contenant le nom du fichier du répertoire musical.

Les lignes 10 à 30 déclarent la méthode qui gère réellement le traitement.

La ligne 12 appelle la Closure qui est exécutée avant le traitement des données.

Les lignes 15 à 27 bouclent sur la structure du fichier artiste/album/contenu.

La ligne 24 appelle la Closure qui traite chaque fichier de contenu.

La ligne 29 appelle la Closure qui est exécutée une fois toutes les données traitées.

Je souhaite compiler cette classe avant de l'utiliser, comme suit :

$ groovyc TagAnalyzerFramework.groovy$

Voilà pour le cadre.

Utiliser le framework dans un script

Voici un script simple qui imprime une liste de valeurs séparées par des barres de tous les fichiers du répertoire musical :

 1  int fileCount
 
 2  def myTagAnalyzer = new TagAnalyzerFramework()
 
 3  myTagAnalyzer.atBeginning = {
 4      // Print the CSV file header and initialize the file counter
 5      println "artistDir|albumDir|contentFile"
 6      fileCount = 0
 7  }
 
 8  myTagAnalyzer.onEachLine = { artistDir, albumDir, contentFile ->
 9      // Print the line for this file
10      println "$artistDir.name|$albumDir.name|$contentFile.name"
11      fileCount++
12  }
 
13  myTagAnalyzer.atEnd = {
14      // Print the file counter value
15      System.err.println "fileCount $fileCount"
16  }
 
17  myTagAnalyzer.musicLibraryDirName = '/home/clh/Test/Music'
 
18  myTagAnalyzer.processMusicLibrary()

La ligne 1 définit une variable locale, fileCount, utilisée pour compter le nombre de fichiers de contenu. Notez que cette variable n'a pas besoin d'être finale.

La ligne 2 appelle le constructeur de la classe TagAnalyzerFramework.

La ligne 3 fait ce qui ressemble à une erreur en Java. Il semble faire référence à un champ dans une classe étrangère. Cependant, dans Groovy, cela appelle en fait un setter sur ce champ, donc c'est acceptable, tant que la classe d'implémentation "se souvient" qu'elle a un contrat pour fournir un setter pour cette propriété.

Les lignes 3 à 7 créent un Closure qui imprime l'en-tête de valeur séparé par des barres et initialise la variable fileCount.

Les lignes 8 à 12 définissent de la même manière le Closure qui gère la logique de traitement de chaque ligne. Dans ce cas, il s'agit simplement d'imprimer les noms de l'artiste, de l'album et du fichier de contenu. Si je reviens à la ligne 24 de TagAnalyzerFramework, je vois qu'il appelle ce Closure avec trois arguments correspondant aux paramètres affichés ici.

Les lignes 13 à 16 définissent la fermeture qui termine le traitement une fois que toutes les données sont lues. Dans ce cas, il imprime le nombre de fichiers avec l'erreur standard.

La ligne 17 définit le nom du répertoire de la bibliothèque musicale.

Et la ligne 18 appelle la méthode pour traiter la bibliothèque musicale.

Exécutez le script :

$ groovy MyTagAnalyzer.groovy
artistDir|albumDir|contentFile
Bombino|Azel|07_Igmayagh_Dum_1.6.16.mp3
Bombino|Azel|08_Ashuhada_1.6.16.mp3
Bombino|Azel|04_Tamiditine_Tarhanam_1.6.16.mp3
Bombino|Azel|10_Naqqim_Dagh_Timshar_1.6.16.mp3
[...]
St Germain|Tourist|04_-_St Germain_-_Land Of....flac
fileCount 55
$

Bien sûr, les fichiers .class créés en compilant la classe framework doivent être sur le chemin de classe pour que cela fonctionne. Naturellement, je pourrais utiliser jar pour regrouper ces fichiers de classe.

Ceux qui sont gênés par ce qui ressemble à la définition de champs dans une classe étrangère pourraient définir des instances locales de fermetures et les transmettre en tant que paramètres, soit au constructeur, soit à processMusicLibrary(), et obtenir le même effet.

Je pourrais revenir aux exemples de code fournis dans les articles précédents pour moderniser cette classe de framework. Je laisse cet exercice au lecteur.

Délégation de comportement

Pour moi, la chose la plus cool qui se passe ici est la délégation de comportement, qui nécessite diverses manigances dans d'autres langues. Pendant de nombreuses années, Java nécessitait des classes anonymes et pas mal de code supplémentaire. Les Lambdas ont parcouru un long chemin pour résoudre ce problème, mais ils ne peuvent toujours pas faire référence à des variables non finales en dehors de leur portée.

C'est tout pour cette série sur l'utilisation de Groovy pour gérer les balises de ma bibliothèque musicale. Il y aura d'autres articles Groovy à l'avenir.

Articles connexes: