[PYTHON] Eine Geschichte, die es ermöglichte, automatisch eine Anison-Wiedergabeliste aus Ihren Musikdateien zu erstellen

Einführung

Ich nahm Musik (hauptsächlich Anison) von einer CD und hörte sie mit Walkman, aber bevor ich es wusste, überstiegen meine Dateien 8000 Songs. Selbst wenn ich darüber nachdenke, eine Wiedergabeliste zu erstellen, ** dauert es sehr lange, meinen Lieblingsanison in die Wiedergabeliste zu werfen **, die Verbindungsinformationen aus der Künstlerliste zu überprüfen, Songs hinzuzufügen usw. ** Der Urlaub ist vorbei **. (Ich denke nicht, dass es für jemanden relevant ist, der Spotify, Apple Music usw. verwendet.) Es wäre schön, wenn ich diese Art von Arbeit genießen könnte, aber da ich es leid war, Wiedergabelisten zu erstellen, stellte ich fest, dass ** ich überhaupt nicht für die Erstellung von Wiedergabelisten geeignet war **. Glücklicherweise wurde mir klar, dass ** ich keine Wiedergabelisten erstellen kann, aber ich kann Programme schreiben **, also habe ich ein Programm erstellt, das automatisch Anison-Wiedergabelisten erstellt, aber es gab viele Dinge, die nicht funktionierten, also habe ich Informationen ausgetauscht. Ich habe auch einen Artikel geschrieben.

Implementiert

Obwohl die Einführung lang geworden ist, ist das diesmal erstellte Programm ein Programm, das ** anison Wiedergabeliste (m3u-Datei) ** aus ** vorhandenen Musikdateien (m4a, mp3, flac-Dateien) ** erstellt. Der Inhalt des Prozesses ist

  1. Holen Sie sich Anison-Informationen aus der CSV-Datei
  2. Holen Sie sich Songinformationen aus Musikdateien, die auf Ihrem PC gespeichert sind
  3. Vergleichen Sie die in 1. und 2. registrierten Daten und geben Sie die passende als Wiedergabeliste (m3u-Datei) aus. Ich habe auch die folgende GUI mit einer einfachen erstellt. (Der GUI-Teil wird in diesem Artikel weggelassen.) apg_ui.png

Wenn Sie einen beliebigen Pfad angeben und die Schaltfläche Ausführen drücken, wird der auf dem PC gespeicherte Anison extrahiert und die Wiedergabelistendatei ausgegeben. Es ist auch möglich, eine Wiedergabeliste zu erstellen, indem Sie eine bestimmte Animation angeben, indem Sie den Arbeitsnamen angeben. Der Quellcode und die ausführbare Datei (für Windows) befinden sich auf GitHub. Überprüfen Sie sie daher ebenfalls.

Programmablauf

Der Basiscode des Wiedergabelistengenerators lautet apg.py in dem auf github veröffentlichten Code. Ich habe auch den in PyQt5 implementierten GUI-Code apg_gui.py implementiert. Da dies jedoch nur die in apg.py definierte Klasse aufruft, können Sie eine Wiedergabeliste nur mit apg.py erstellen. In apg.py wird ** A ** nison ** P ** laylist ** G ** enerator als APG-Klasse abgekürzt und hat Funktionen, die 1 bis 3 der obigen Implementierung entsprechen. Ich werde. Die Details jedes Prozesses werden unten erklärt.

Holen Sie sich Anison-Informationen aus der CSV-Datei

Die Funktion MakeAnisonDatabase in apg.py wird erklärt. Hier werden die Informationen von Anison in der Datenbank gespeichert. Der Grund für die Verwendung der Datenbank besteht darin, dass es sinnlos ist, jedes Mal, wenn Sie eine Wiedergabeliste erstellen, Anison-Daten und Musik zu erfassen. Sobald Sie eine Datenbank erstellt haben, können Sie die Zeit reduzieren, die zum Erstellen der zweiten und nachfolgender Wiedergabelisten erforderlich ist. Es ist das Ergebnis des Denkens. Ich muss es nur verschieben, also implementiere ich es, ohne tief über die Struktur der Datenbank nachzudenken (obwohl ich einfach keine Kenntnisse über die Datenbank habe ...). Die verwendete Bibliothek ist sqlite3. Der spezifische Code lautet wie folgt. Rufen Sie zunächst den Pfad der DL-CSV-Datei von Anison Generation ab. DL verfügt über drei Zip-Dateien, die in einer Datei namens anison.csv für Animationen, game.csv für Spiele und sf.csv für Spezialeffekte gespeichert sind (der ursprüngliche Zweck ist Animation, aber es ist eine große Sache. Ich benutze auch Spiele und Spezialeffekte. Wenn Sie den entpackten Ordner in den Datenordner legen, ist dies wie folgt.


./data/ --- anison/ -- anison.csv #Anime
         |          └ readme.txt
         ├ game/ --- game.csv    #Spiel
         |         └ readme.txt
         └ sf/--- sf.csv         #Spezialeffekte
               └ readme.txt

Jeder Ordner enthält auch eine Textdatei. Wenn Sie jedoch den folgenden Code ausführen, können Sie nur die CSV-Datei abrufen, selbst wenn Sie den entpackten Ordner so wie er ist in ./data ablegen.


path_data = "./data" #Ordner, in dem die von Anison Generation heruntergeladene CSV-Datei gespeichert wird
file_paths = [i for i in glob.glob(path_data + "/**", recursive=True) if os.path.splitext(i)[-1] == ".csv"] #Holen Sie sich nur den Pfad der CSV-Datei rekursiv

Registrieren Sie anschließend die Informationen in der CSV-Datei in der Datenbank. Da es nur drei CSV-Zieldateien gibt, anison.csv, game.csv und sf.csv, lesen Sie keine anderen Dateien. Der folgende Code erstellt Tabellen mit den Namen anison, game und sf und registriert 1000 Zeilen in der Datenbank. (Ich habe auf eine Website verwiesen, aber ich habe das Gefühl, dass sie sich nicht mit oder ohne ändert.)


data_name = ["anison.csv", "game.csv", "sf.csv"] #Der Name der von Anison Generation heruntergeladenen CSV-Datei
for file_path in file_paths:
       if os.path.basename(file_path) in data_name: #Der Name der CSV-Datei lautet anison.csv, game.csv, sf.Wenn einer von csv
            category = os.path.splitext(os.path.basename(file_path))[0]

            # anison, game,Erstellen Sie eine Tabelle mit dem Namen sf
            with sqlite3.connect(self.path_database)as con, open(file_path, "r", encoding="utf-8") as f:
                cursor = con.cursor()
                #Erstellen, wenn keine Tabelle vorhanden ist
                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(?, ?, ?, ?, ?, ?)" #SQL-Anweisungsdefinition
                
                lines = f.readlines() #CSV-Datei lesen
                buffer = []           #Variablen zum gemeinsamen Registrieren von Daten
                buffer_size = 1000    #Registrieren Sie 100 Artikel gleichzeitig

                for i, line in tqdm(enumerate(lines[1:])): #Lesen Sie die CSV-Datei Zeile für Zeile
                   *keys, = line.split(",")  #Holen Sie sich den Schlüssel für jede Zeile
                    #Holen Sie sich den Namen des Sängers, den Namen des Songs, die Sendereihenfolge, den OPED-Typ, den Anime-Namen und das Genre als Schlüssel
                    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) #SQL-Ausführung
                        buffer = []
                

                #Löschen Sie doppelt registrierte Daten
                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()

Die Trimmfunktion ist eine Funktion, die Zeichen, die beim Erstellen einer Datenbank oder Wiedergabeliste nicht erwünscht sind, durch andere Zeichen ersetzt und Zeichenfolgen wie Zeilenumbrüche und Kommas löscht. Außerdem gab es ein Problem beim Erstellen einer Wiedergabeliste, selbst wenn es einen Unterschied zwischen voller Breite und halber Breite gab. Daher wurden alle Zeichen, die in der Mojimoji-Bibliothek in Zeichen halber Breite konvertiert werden können, in Zeichen halber Breite geändert.


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()

Holen Sie sich als Nächstes die Informationen der auf dem PC gespeicherten Musikdatei und registrieren Sie sie in der Datenbank.

Holen Sie sich Songinformationen aus Musikdateien, die auf Ihrem PC gespeichert sind

Das Format der m3u-Datei, bei der es sich um eine Wiedergabelistendatei handelt, lautet wie folgt. Die Länge des Songs, der Titel des Songs und der Pfad zur Musikdatei sind für jeden Song erforderlich.

 #EXTM3U
 #EXTINF:Songlänge, Songtitel
Absoluter Pfad zur Datei
 #EXTINF:Songlänge, Songtitel
Absoluter Pfad zur Datei
        :

In der Funktion MakeMusiclibrary wird der Pfad der Musikdatei erfasst und die Musikdatei auf die gleiche Weise wie die Anison-Daten in der Datenbank registriert. Der Prozess des Erfassens von Anison-Daten hat sich in eine Musikdatei geändert, aber der grundlegende Prozess unterscheidet sich nicht wesentlich vom Prozess von ↑. Ich habe die folgende Funktion definiert, um die Informationen der Musikdatei zu erhalten.

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

Die Funktion getMusicInfo ruft den Songtitel, den Sängernamen und die Songlänge aus dem Dateipfad ab. Die Dateien, die die Musikbibliothek in der Datenbank registrieren, lauten wie folgt. Für den Namen und den Titel des Sängers wurden unbequeme Zeichen mit der Trimmfunktion konvertiert.


    def makeLibrary(path_music):
        music_files = glob.glob(path_music + "/**", recursive=True) #Holen Sie sich alle Dateien in der Bibliothek
        
        #Erstellen Sie eine Tabelle mit dem Namen Bibliothek und registrieren Sie Musikdateien
        with sqlite3.connect(self.path_database) as con:
            cursor = con.cursor()
            #Wenn keine Bibliothekstabelle vorhanden ist, erstellen Sie diese
            cursor.execute("CREATE TABLE IF NOT EXISTS library(artist, title, length, path)")
            #SQL-Anweisung
            command = "INSERT INTO library VALUES(?, ?, ?, ?)"

            buffer = []
            for i, music_file in tqdm(enumerate(music_files)):
                audio, artist, title, length = getMusicInfo(music_file) #Informationen zu Musikdateien aus dem Pfad abrufen
                
                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()

Als nächstes werde ich die Funktion erklären, die eine Wiedergabeliste unter Verwendung der bisherigen Daten ausgibt.

Wiedergabeliste ausgeben (.m3u-Datei)

Die Erklärung hier bezieht sich auf die Funktion generatePlaylist in apg.py (ich habe verschiedene Dinge zur Erklärung weggelassen ...). Zunächst wird der Name des Sängers aus den in der Datenbank registrierten Anison-Informationen ermittelt. Die SQL-Anweisung und der Ausführungsteil lauten wie folgt. Kategorie ist ein Tabellenname, der anison, game oder sf sein kann. Ersetzen Sie die erfasste Liste der Sängernamen durch eine entsprechende Variable. (Der Zugriff auf die Datenbank ist der gleiche wie im obigen Programm, daher wird er weggelassen.)

cursor.execute("SELECT DISTINCT artist FROM '%s'" % category)
artist_db = cursor.fetchall()

In ähnlicher Weise erhalten Sie den Namen des Sängers in der Musikbibliothek.


cursor.execute('SELECT artist FROM library')
artist_lib = sorted(set([artist[0] for artist in cursor.fetchall()]))

Stellen Sie als Nächstes fest, ob der Name des Sängers in der Musikbibliothek in der Liste der Sängernamen in der Anison-Datenbank enthalten ist, dh ob der Sänger in der Musikbibliothek möglicherweise den Anison gesungen hat. Ich denke, es ist eine Kultur, die Anison eigen ist, aber wenn Musik von einer CD importiert wird, kann der Name des Sängers der Charaktername sein (vgl. Name des Synchronsprechers). Andererseits wird die Sängerliste in der Anison-Datenbank (wahrscheinlich) nach dem Namen des Synchronsprechers registriert, sodass es nicht möglich ist, nach der genauen Übereinstimmung des Sängernamens zu suchen. Daher untersuchten wir die Ähnlichkeit zwischen dem Sänger in der Musikbibliothek und dem Sänger in der Anison-Datenbank und wählten den Sängernamen mit der höchsten Ähnlichkeit und der maximalen Ähnlichkeit, die den Schwellenwert überschreitet, als den Sänger, der möglicherweise Anison singt. Im Code (apg.py) entspricht es dem folgenden Teil.

#Für alle Künstler in der Bibliothek
for i, artist in artist_lib:
    #Berechnen Sie die Ähnlichkeit von Künstlernamen
    similarities = [difflib.SequenceMatcher(None, artist, a[0]).ratio() for a in artist_db]

    if th_artist < max(similarities): #Wenn der maximale Ähnlichkeitswert über dem Schwellenwert liegt
        #Holen Sie sich alle Song-Informationen des Zielkünstlers
        info_list = self.getInfoDB('SELECT * FROM library WHERE artist LIKE \'' + artist + '\'', cursor)

Nachdem Sie den Sänger identifiziert haben, rufen Sie alle Songinformationen dieses Sängers in der Musikbibliothek ab und suchen Sie die Songs in der Musikbibliothek nach Anison. Die Tatsache, dass genaue Übereinstimmungen nicht für Sängernamen verwendet werden können, bedeutet auch, dass genaue Übereinstimmungen nicht für Songtitel verwendet werden können. Beispielsweise stimmt ein Titel wie ein Songname (Albumver.) Genau überein und wird nicht durchsucht. Daher überprüft die Musikliste auch die Ähnlichkeit.


        #Es ist eine Fortsetzung der if-Anweisung von ↑
        #Holen Sie sich alle Songs des Sängers mit dem höchsten Grad an Ähnlichkeit aus der Anison-Datenbank
        cursor.execute("SELECT DISTINCT * FROM '%s' WHERE artist LIKE \'%%%s%%\'" % (category, artist_db[similarities.index(max(similarities))][0]))
        title_list = cursor.fetchall() #Liste der Songs eines bestimmten Künstlers in der Anison-Datenbank

        for info in info_list: #Finden Sie heraus, ob alle Songs in Ihrer Musikbibliothek anison sind
            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] #Berechnen Sie die Ähnlichkeit mit den Songs in der Anison-Datenbank
 
            if th_title < max(title_ratio): #Anison, wenn die Ähnlichkeit über der Schwelle liegt
                t = title_list[title_ratio.index(max(title_ratio))]
                lines.append(['#EXTINF: ' + str(int(length)) + ', ' + title + "\n" + path, t[-1]]) # .Variablen für die Ausgabe der m3u-Datei(aufführen)Hinzufügen

Nachdem Sie die Ähnlichkeit aller Künstler und die Ähnlichkeit der Songs berechnet haben, schreiben Sie die Informationen des in den variablen Zeilen enthaltenen Anison in eine Datei.

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]))

Sie haben jetzt eine Anison-Wiedergabeliste erstellt. Zur Erklärung gibt es einige Unterschiede zu dem auf github veröffentlichten Code. Wenn Sie also interessiert sind, überprüfen Sie bitte apg.py auf github.

Problem

Durch das Erstellen von drei Funktionen ist es möglich, vorerst eine Wiedergabeliste zu erstellen, aber ich möchte auf einige der Probleme eingehen, die bei dieser Implementierung aufgetreten sind.

Songs, die nicht anison sind, werden auch als anison hinzugefügt

Derzeit besteht das Problem, dass Songs, die nicht anison sind, beim Erstellen der Wiedergabeliste auch in die Wiedergabeliste aufgenommen werden. Wenn Sie beispielsweise die Animation BLEACH als Titel Ihrer Arbeit festlegen, wird zusätzlich zu UVERworlds D-technolife ein sehr ähnliches Lied namens D-technorize zur Wiedergabeliste hinzugefügt. Wenn Sie versuchen, eine Gundam UC-Wiedergabeliste zu erstellen, werden neben Aimers Re: I auch die Songs Re: far und Re: pray in die Gundam UC-Wiedergabeliste aufgenommen. Im Falle einer solchen Arbeit allein kann dies durch Erhöhen der Ähnlichkeitsschwelle von Liedern behoben werden. Da sich die Schwelle von Liedern jedoch je nach Animation unterscheidet, ist es derzeit schwierig, eine Wiedergabeliste von Anison zu erstellen, die nicht auf eine bestimmte Animation beschränkt ist. Es ist geworden. Ich denke, es hängt mit den folgenden Problemen zusammen, aber wenn ich eine gute Methode finde, würde ich sie gerne verbessern.

Die Generierung von Wiedergabelisten ist langsam

Derzeit ist die Datenbank nur ein temporärer Speicherort für Daten und wird am Ende mit der for-Anweisung verarbeitet. Wenn ich SQL intelligenter schreiben kann, wird sich die Erstellungszeit für Wiedergabelisten meiner Meinung nach verkürzen. Daher möchte ich den Code für die Datenbank in Zukunft neu schreiben.

Zusammenfassung

Es war zu schwierig, eine Anison-Wiedergabeliste zu erstellen, daher habe ich eine Software erstellt, die automatisch eine Anison-Wiedergabeliste erstellt. Es gibt immer noch einige Probleme, aber ich denke, wir haben Software mit den minimalen Funktionen erstellt. Rückblickend war das Ergebnis, dass ** die Zeit, die für das Codieren aufgewendet wurde, die Zeit, die zum Erstellen einer Wiedergabeliste benötigt wurde, bei weitem überstieg **, aber ich wünschte, ich könnte Leute retten, die ähnliche Probleme haben. habe gedacht. Last but not least, wenn Sie Fehler oder Verbesserungen haben (insbesondere in Bezug auf die datenbankbezogene Verarbeitung), würde ich mich freuen, wenn Sie einen Kommentar abgeben könnten. Vielen Dank für das Lesen bis zum Ende.

Änderungsprotokoll

2020/03/04 veröffentlicht

Recommended Posts

Eine Geschichte, die es ermöglichte, automatisch eine Anison-Wiedergabeliste aus Ihren Musikdateien zu erstellen
Eine Geschichte, die es ermöglichte, automatisch eine Anison-Wiedergabeliste aus Ihren Musikdateien zu erstellen
Ich habe ein Tool erstellt, mit dem das Erstellen und Installieren eines öffentlichen Schlüssels etwas einfacher ist.
Ich habe ein Tool erstellt, um eine Wortwolke aus Wikipedia zu erstellen
Ich habe ein Tool erstellt, um automatisch ein einfaches ER-Diagramm aus der Anweisung CREATE TABLE zu generieren
Eine Geschichte, die ich süchtig danach war, Lambda von AWS Lambda anzurufen.
Erstellen Sie mit Mecab aus Python3 ein Tool, das Furigana automatisch mit HTML schüttelt
Verwenden Sie Discord Bot, um .eml von Ihrem Smartphone zu lesen
Eine Geschichte über das Schreiben eines Programms, das Ihre eigenen Asset-Übergänge automatisch zusammenfasst
Eine Geschichte, die unter einem Unterschied im Betriebssystem litt, als sie versuchte, ein Papier zu implementieren
So erstellen Sie einen Klon aus Github
So erstellen Sie ein Repository aus Medien
Ich habe ein System erstellt, das automatisch entscheidet, ob es morgen mit Python ausgeführt wird, und es zu Google Kalender hinzufügt.
[Python] Ich habe ein Skript erstellt, das Dateien auf dem lokalen PC automatisch ausschneidet und auf eine externe SSD einfügt.
[Django] Erstellen Sie ein Formular, das automatisch die Adresse aus der Postleitzahl ausfüllt
Eine Geschichte, der ich nach der SFTP-Kommunikation mit Python verfallen war
Ich habe ein Paket erstellt, um eine ausführbare Datei aus dem Hy-Quellcode zu erstellen
Bearbeiten Sie Excel in Python, um eine Pivot-Tabelle zu erstellen
So erstellen Sie ein Funktionsobjekt aus einer Zeichenfolge
Automatische Erstellung einer Ansible-Konfigurationsdatei (vars) aus Excel (Ansible)
Eine Geschichte, die fehlgeschlagen ist, als versucht wurde, das Suffix mit rstrip aus einem String zu entfernen
Ich habe ein Docker-Image erstellt, das RSS liest und automatisch regelmäßig twittert, und es veröffentlicht.
Ein einfaches System, das automatisch mit Objekterkennung aufnimmt und an LINE sendet