J'ai pris de la musique (principalement anison) à partir d'un CD et je l'ai écoutée avec un baladeur, mais avant de le savoir, mes fichiers dépassaient 8000 chansons. Même si je pense créer une liste de lecture, ** cela prend beaucoup de temps pour ajouter mon anison préféré à la liste de lecture **, vérifier les informations de lien dans la liste des artistes, ajouter des chansons, etc. ** Les vacances sont terminées **. (Je ne pense pas que ce soit pertinent pour quiconque utilise Spotify, Apple Music, etc.) Ce serait bien si je pouvais apprécier ce genre de travail, mais comme j'étais fatigué de créer des listes de lecture, j'ai trouvé que ** je n'étais pas adapté pour le travail de création de listes de lecture en premier lieu **. Heureusement, j'ai réalisé que ** je ne peux pas créer de listes de lecture, mais que je peux écrire des programmes **, j'ai donc créé un programme qui crée automatiquement des listes de lecture Anison, mais il y avait beaucoup de choses qui ne fonctionnaient pas, alors j'ai partagé des informations. J'ai également écrit un article.
Bien que l'introduction soit devenue longue, le programme créé cette fois-ci est un programme qui crée une ** playlist anison (fichier m3u) ** à partir de ** fichiers musicaux existants (fichiers m4a, mp3, flac) **. Le contenu du processus est
Si vous spécifiez un chemin arbitraire et appuyez sur le bouton d'exécution, l'anison sauvegardée sur l'ordinateur personnel sera extraite et le fichier de liste de lecture sera sorti. Il est également possible de créer une liste de lecture en spécifiant une animation spécifique en spécifiant le nom de l'œuvre. Le code source et le fichier exécutable (pour Windows) se trouvent sur GitHub, veuillez donc les vérifier également.
Le code de base du générateur de playlist est apg.py dans le code publié sur github. J'ai également implémenté le code GUI apg_gui.py implémenté dans PyQt5, mais comme cela n'appelle que la classe définie dans apg.py, vous pouvez créer une liste de lecture avec juste apg.py. Dans apg.py, ** A ** nison ** P ** laylist ** G ** énerator est défini comme la classe APG, et il a des fonctions correspondant à 1 à 3 de l'implémentation ci-dessus. Je vais. Les détails de chaque processus sont expliqués ci-dessous.
La fonction MakeAnisonDatabase dans apg.py est expliquée. Ici, les informations d'Anison sont enregistrées dans la base de données. La raison d'utiliser la base de données est qu'il est inutile d'acquérir les données d'Anison et la musique disponible chaque fois que vous créez une liste de lecture, et une fois que vous créez la base de données, vous pouvez réduire le temps nécessaire pour créer la deuxième liste de lecture et les suivantes. C'est le résultat de la réflexion. J'ai juste besoin de le déplacer, donc je l'implémente sans réfléchir profondément à la structure de la base de données (même si je n'ai tout simplement pas connaissance de la base de données ...). La bibliothèque utilisée est sqlite3. Le code spécifique est le suivant. Tout d'abord, récupérez le chemin du fichier csv DL à partir d'Anison Generation. Il y a trois fichiers zip dans DL, et ils sont enregistrés dans anison.csv pour l'animation, game.csv pour les jeux et sf.csv pour les effets spéciaux (le but initial est l'animation, mais c'est un gros problème J'utilise aussi des jeux et des effets spéciaux). Si vous placez le dossier décompressé dans le dossier de données, ce sera comme suit.
./data/ --- anison/ -- anison.csv #Anime
| └ readme.txt
├ game/ --- game.csv #Jeu
| └ readme.txt
└ sf/--- sf.csv #Effets spéciaux
└ readme.txt
Chaque dossier contient également un fichier texte, mais en exécutant le code suivant, vous ne pouvez obtenir que le fichier csv même si vous placez le dossier décompressé dans ./data tel quel.
path_data = "./data" #Dossier dans lequel le fichier csv téléchargé depuis Anison Generation est enregistré
file_paths = [i for i in glob.glob(path_data + "/**", recursive=True) if os.path.splitext(i)[-1] == ".csv"] #Obtenez uniquement le chemin du fichier csv de manière récursive
Ensuite, enregistrez les informations dans le fichier csv dans la base de données. Comme il n'y a que trois fichiers csv cibles, anison.csv, game.csv et sf.csv, ne lisez pas les autres fichiers. Le code suivant crée des tables appelées anison, game et sf et enregistre 1000 lignes dans la base de données. (J'ai fait référence à un site, mais je pense que cela ne change pas avec ou sans lui.)
data_name = ["anison.csv", "game.csv", "sf.csv"] #Le nom du fichier csv téléchargé depuis Anison Generation
for file_path in file_paths:
if os.path.basename(file_path) in data_name: #Le nom du fichier csv est anison.csv, game.csv, sf.Si l'un des csv
category = os.path.splitext(os.path.basename(file_path))[0]
# anison, game,Créer une table nommée sf
with sqlite3.connect(self.path_database)as con, open(file_path, "r", encoding="utf-8") as f:
cursor = con.cursor()
#Créer si la table n'existe pas
cursor.execute("CREATE TABLE IF NOT EXISTS '%s'('%s', '%s', '%s', '%s', '%s', '%s')" % (category, "artist", "title", "anime", "genre", "oped", "order"))
command = "INSERT INTO " + category + " VALUES(?, ?, ?, ?, ?, ?)" #Définition de l'instruction SQL
lines = f.readlines() #Lire le fichier csv
buffer = [] #Variables d'enregistrement des données collectivement
buffer_size = 1000 #Enregistrez 100 articles à la fois
for i, line in tqdm(enumerate(lines[1:])): #Lire le fichier csv ligne par ligne
*keys, = line.split(",") #Obtenez la clé pour chaque ligne
#Obtenez le nom du chanteur, le nom de la chanson, l'ordre de diffusion, le type OPED, le nom de l'anime, le genre comme clés
artist, title, order, oped, anime, genre = trim(keys[7]), trim(keys[6]), trim(keys[4]), trim(keys[3]), trim(keys[2]), trim(keys[1])
buffer.append([artist, title, anime, genre, oped, order])
if i%buffer_size == 0 or i == len(lines) - 1:
cursor.executemany(command, buffer) #Exécution SQL
buffer = []
#Supprimer les données enregistrées en double
cursor.executescript("""
CREATE TEMPORARY TABLE tmp AS SELECT DISTINCT * FROM """ + category + """;
DELETE FROM """ + category + """;
INSERT INTO """ + category + """ SELECT * FROM tmp;
DROP TABLE tmp;
""")
con.commit()
La fonction de découpage est une fonction qui remplace les caractères qui ne sont pas souhaitables lors de la création d'une base de données ou d'une liste de lecture par d'autres caractères, et efface les chaînes de caractères telles que les sauts de ligne et les virgules. En outre, il y avait un problème lors de la création d'une liste de lecture, même avec la différence entre pleine largeur et demi-largeur, donc tous les caractères pouvant être convertis en caractères demi-largeur dans la bibliothèque mojimoji ont été modifiés en caractères demi-largeur.
import mojimoji as moji
def trim(name):
name = name.replace("\n", "").replace('\'', '_').replace(" ", "").replace("\x00", "").replace("\"", "")
name = moji.zen_to_han(name)
return name.lower()
Ensuite, récupérez les informations du fichier musical enregistré sur le PC et enregistrez-le dans la base de données.
Le format du fichier m3u, qui est un fichier de liste de lecture, est le suivant, et la longueur de la chanson, le titre de la chanson et le chemin d'accès au fichier de musique sont nécessaires pour chaque chanson.
#EXTM3U
#EXTINF:Durée de la chanson, titre de la chanson
Chemin absolu vers le fichier
#EXTINF:Durée de la chanson, titre de la chanson
Chemin absolu vers le fichier
:
Dans la fonction MakeMusiclibrary, le chemin du fichier de musique est acquis et le fichier de musique est enregistré dans la base de données de la même manière que les données d'anison. Le processus d'acquisition des données d'anison a changé en un fichier musical, mais le processus de base n'est pas très différent du processus de ↑. J'ai défini la fonction suivante pour obtenir les informations du fichier musical.
from mutagen.flac import FLAC
from mutagen.mp3 import MP3
from mutagen.mp4 import MP4
def getMusicInfo(path):
length, audio, title, artist = 0, "", "", ""
if path.endswith(".flac"):
audio = FLAC(path)
artist = trim(audio.get('artist', [""])[0])
title = trim(audio.get('title', [""])[0])
length = audio.info.length
elif path.endswith(".mp3"):
audio = EasyID3(path)
artist = trim(audio.get('artist', [""])[0])
title = trim(audio.get('title', [""])[0])
length = MP3(path).info.length
elif path.endswith(".m4a"):
audio = MP4(path)
artist = trim(audio.get('\xa9ART', [""])[0])
title = trim(audio.get('\xa9nam', [""])[0])
length = audio.info.length
return audio, artist, title, length
La fonction getMusicInfo obtient le titre de la chanson, le nom du chanteur et la longueur de la chanson à partir du chemin du fichier. Les fichiers qui enregistrent la bibliothèque musicale dans la base de données sont les suivants. Pour le nom et le titre du chanteur, les caractères peu pratiques ont été convertis avec la fonction de découpage.
def makeLibrary(path_music):
music_files = glob.glob(path_music + "/**", recursive=True) #Récupérez tous les fichiers de la bibliothèque
#Créez une table nommée bibliothèque et enregistrez des fichiers musicaux
with sqlite3.connect(self.path_database) as con:
cursor = con.cursor()
#S'il n'y a pas de table de bibliothèque, créez-la
cursor.execute("CREATE TABLE IF NOT EXISTS library(artist, title, length, path)")
#Instruction SQL
command = "INSERT INTO library VALUES(?, ?, ?, ?)"
buffer = []
for i, music_file in tqdm(enumerate(music_files)):
audio, artist, title, length = getMusicInfo(music_file) #Obtenir des informations sur les fichiers musicaux à partir du chemin
if audio != "":
buffer.append(tuple([trim(artist), trim(title), length, music_file]))
if i % 1000 == 0 or i == len(music_files) - 1:
cursor.executemany(command, buffer)
buffer = []
cursor.executescript("""
CREATE TEMPORARY TABLE tmp AS SELECT DISTINCT * FROM library;
DELETE FROM library;
INSERT INTO library SELECT * FROM tmp;
DROP TABLE tmp;
""")
con.commit()
Ensuite, j'expliquerai la fonction qui génère une liste de lecture en utilisant les données jusqu'à présent.
L'explication ici concerne la fonction generatePlaylist dans apg.py (bien que j'aie omis diverses choses pour l'explication ...). Tout d'abord, le nom du chanteur est obtenu à partir des informations d'anison enregistrées dans la base de données. L'instruction SQL et la partie exécution sont les suivantes. category est un nom de table qui peut être anison, game ou sf. Remplacez la liste acquise des noms de chanteurs dans une variable appropriée. (L'accès à la base de données est le même que le programme ci-dessus, il est donc omis)
cursor.execute("SELECT DISTINCT artist FROM '%s'" % category)
artist_db = cursor.fetchall()
De même, obtenez le nom du chanteur dans la bibliothèque musicale.
cursor.execute('SELECT artist FROM library')
artist_lib = sorted(set([artist[0] for artist in cursor.fetchall()]))
Ensuite, découvrez si le nom du chanteur dans la bibliothèque musicale est dans la liste des noms du chanteur dans la base de données anison, c'est-à-dire si le chanteur de la bibliothèque musicale a peut-être chanté anison. Je pense que c'est une culture propre à Anison, mais lorsque la musique est importée d'un CD, le nom du chanteur peut être le nom du personnage (cv. Nom de l'acteur vocal). D'autre part, la liste des chanteurs dans la base de données Anison est (probablement) enregistrée par nom d'acteur vocal, il n'est donc pas possible de rechercher par correspondance exacte du nom du chanteur. Par conséquent, nous avons examiné la similitude entre le chanteur dans la bibliothèque musicale et le chanteur dans la base de données anison, et avons sélectionné le nom du chanteur avec la plus grande similitude et la similitude maximale dépassant le seuil en tant que chanteur qui peut chanter anison. Dans le code (apg.py), cela correspond à la partie suivante.
#Pour tous les artistes de la bibliothèque
for i, artist in artist_lib:
#Calculer la similitude des noms d'artistes
similarities = [difflib.SequenceMatcher(None, artist, a[0]).ratio() for a in artist_db]
if th_artist < max(similarities): #Lorsque la valeur maximale de similitude est supérieure au seuil
#Obtenez toutes les informations sur la chanson de l'artiste cible
info_list = self.getInfoDB('SELECT * FROM library WHERE artist LIKE \'' + artist + '\'', cursor)
Après avoir identifié le chanteur, récupérez toutes les informations sur la chanson de ce chanteur dans la bibliothèque musicale et recherchez les chansons dans la bibliothèque musicale d'Anison. Le fait que les correspondances exactes ne peuvent pas être utilisées pour les noms de chanteurs signifie également que les correspondances exactes ne peuvent pas être utilisées pour les titres de chansons. Par exemple, une chanson telle qu'un nom de chanson (version d'album) est une correspondance exacte et ne sera pas recherchée. Par conséquent, la liste de musique vérifie également la similitude.
#C'est une continuation de l'instruction if de ↑
#Obtenez toutes les chansons du chanteur avec le plus haut degré de similitude de la base de données Anison
cursor.execute("SELECT DISTINCT * FROM '%s' WHERE artist LIKE \'%%%s%%\'" % (category, artist_db[similarities.index(max(similarities))][0]))
title_list = cursor.fetchall() #Liste des chansons d'un artiste spécifique incluses dans la base de données Anison
for info in info_list: #Découvrez si toutes les chansons de votre bibliothèque musicale sont anison
artist, title, length, path = info[0], info[1], info[2], info[3]
title_ratio = [difflib.SequenceMatcher(None, title, t[1]).ratio() for t in title_list] #Calculez la similitude avec les chansons de la base de données Anison
if th_title < max(title_ratio): #Anison si la similitude est au-dessus du seuil
t = title_list[title_ratio.index(max(title_ratio))]
lines.append(['#EXTINF: ' + str(int(length)) + ', ' + title + "\n" + path, t[-1]]) # .Variables pour la sortie du fichier m3u(liste)Ajouter à
Après avoir calculé la similitude de tous les artistes et la similitude des chansons, écrivez les informations de l'anison contenues dans les lignes variables dans un fichier.
path_playlist = "./playlist/AnimeSongs.m3u"
with open(path_playlist, 'w', encoding='utf-16') as pl:
pl.writelines('#EXTM3U \n')
pl.writelines("\n".join([line[0] for line in lines]))
Vous avez maintenant créé une liste de lecture Anison. Pour des raisons d'explication, il existe quelques différences par rapport au code publié sur github, donc si vous êtes intéressé, veuillez vérifier apg.py sur github.
En créant trois fonctions, il est possible de créer une liste de lecture pour le moment, mais je voudrais aborder certains des problèmes survenus dans cette implémentation.
Actuellement, il existe un problème en ce que les chansons qui ne sont pas anison sont également incluses dans la liste de lecture lors de la création de la liste de lecture. Par exemple, si vous définissez l'animation BLEACH comme titre de votre travail, en plus de D-technolife d'UVERworld, une chanson très similaire appelée D-technorize sera ajoutée à la playlist. En plus de Re: I am d'Aimer, si vous essayez de créer une liste de lecture Gundam UC, les chansons Re: far et Re: prier seront également incluses dans la liste de lecture Gundam UC. Dans le cas d'un tel travail seul, il peut être traité en élevant le seuil de similitude des chansons, mais comme le seuil des chansons diffère selon l'animation, il est actuellement difficile de créer une playlist d'anison qui ne se limite pas à une animation spécifique. Il est devenu. Je pense que c'est lié aux problèmes suivants, mais si je trouve une bonne méthode, j'aimerais l'améliorer.
Actuellement, la base de données est devenue simplement un emplacement de stockage temporaire pour les données, et à la fin, elle sera traitée avec l'instruction for. Si je peux écrire SQL plus intelligemment, je pense que le temps de création de la playlist sera réduit, donc j'aimerais réécrire le code lié à la base de données à l'avenir.
C'était trop difficile de créer une liste de lecture Anison, j'ai donc créé un logiciel qui crée automatiquement une liste de lecture Anison. Il y a encore des problèmes, mais je pense que nous avons créé des logiciels avec les fonctions minimales. En regardant en arrière, le résultat était que ** le temps passé à coder dépassait de loin le temps nécessaire pour créer une liste de lecture régulièrement **, mais j'aimerais pouvoir sauver des personnes ayant des problèmes similaires. pensée. Enfin, si vous avez des erreurs ou des améliorations (en particulier concernant le traitement lié à la base de données), je vous serais reconnaissant de bien vouloir commenter. Merci d'avoir lu jusqu'au bout.
2020/03/04 publié
Recommended Posts