はじめに
- ライブラリだと文字化けするので使わずに作成
- 持っている音楽のアーティスト、歌手、曲の重複数をコマンドプロンプトに表示
- 音楽ジャンルはVOCALOIDを想定していますが、他ジャンルが入っていても動きます
環境
- Windows11
- Visual Studio 2022 (Community)
- Python 3.9(64bit)
VOCALOIDジャンル特有のファイル構造(他ジャンルでも同じ?)
- mp3タグの文字コードがバラバラ(タグを解析するライブラリを使うと文字化けする)
- アーティスト名に別名が存在する人が多い(例:ラマーズPとゴジマジP) また、表記ゆれもある
- アーティスト名の表記形式は、○○ Feat.△△ (だいたいこれ) ○○ loves △△(デッドボールPのアルバム) の2種類が存在
- 名前の区切りは、 X,Y(だいたいこれ) X+Y X・Y X&Y X、Y(一部のアルバム)
変数の準備など
-- coding: shift-jis -- は、パスに日本語(マルチバイト文字)がある場合に必要
import os を先に書く
import os
# -*- coding: shift-jis -*-
dir_path = r"ミュージックフォルダまでのパス"
files = []
res = {}
res2 = {}
songs = {}
mp3ファイルを取得
ジャケット画像を設定している場合はjpgファイル、ミュージックフォルダにはdesktop.iniがあるので拡張子からそれらを弾く
自分の持っているファイルの曲番号は2桁か3桁(01,001など)なので、空白位置からどっちか調べ、番号を消した状態で曲名をsongsに追加する(曲別ランキングに使用)
def add_file(path):
for name in os.listdir(path):
if len(name) > 4:
if name[-4:] == ".mp3":
if name[2] == ' ':
if name[3:-4] in songs:
songs[name[3:-4]] += 1
else:
songs[name[3:-4]] = 1
elif name[3] == ' ':
if name[4:-4] in songs:
songs[name[4:-4]] += 1
else:
songs[name[4:-4]] = 1
files.append(path + "\\" + name)
continue
elif name[-4:] == ".jpg" or name[-4:] == ".ini":
continue
add_file(path + "\\" + name)
mp3ファイルのTPE1タグを取得
TPE1タグにアーティスト情報が載っている(○○ Feat.△△ など)
TPE1タグを取得するライブラリは存在するが、文字化けするので使用しない。
今のところ、文字コードは UTF-8,Shift-JIS,UTF-16のいずれかで対応できたので、try-exceptを使いしらみつぶしに変換する
ヌル文字はここで削除する(utf-16を除く)
def get_tpe1(path):
target = "TPE1".encode("utf-8")
with open(path,"br") as f:
data = f.read()
i = data.find(target) + 7
tmp = data[i + 4:i + 3 + data[i]]
rt = ""
if not i == -1:
try:
return tmp.replace(b"\x00",b"").decode("utf-8")
except Exception:
try:
return tmp.replace(b"\x00",b"").decode("shift-jis")
except Exception:
return tmp.decode("utf-16")
else:
return ""
最終仕上げ
取得したデータをソートして、ランキング(多い順)で表示する
アーティスト名とFeat以降の区切りを見つける
アーティスト名のみ(l = -1 + 5 つまり4)の場合は、アーティスト名のみを取得
replace()を使いアーティスト名の統一、名前の区切りの統一をしておく(例:ゴジマジP→ラマーズP Feat.初音ミク&鏡音リン→Feat.初音ミク,鏡音リン)
鏡音リン・レンを鏡音リン・鏡音レンに直す(後でランキングをつけるため)
add_file(dir_path)
print("曲数: ",len(files))
print("種類: ",len(songs))
for path in files:
ats = get_tpe1(path)
if not ats == "":
if "loves" in ats:
l = ats.lower().find("loves") + 5
else:
l = ats.lower().find("feat.") + 5
if not l == 4:
artist = ats[:l - 6] if ats[l - 6] == " " else ats[:l - 5]
artist = artist.replace("ryo","supercell").replace("ゴジマジP","ラマーズP").replace("ピノキオP","ピノキオピー").replace("ちょむP","TakeponG (ちょむP)").replace("1640mP","40mP").replace("じん (自然の敵P)","じん").replace("wowaka (現実逃避P)","wowaka").replace("マチゲリータP","マチゲリータ")
feats = ats[l:].replace(" ","").replace("x",",").replace("&",",").replace("+",",").replace("・",",").replace("、",",")
if ("鏡音リン" in feats) and (not ("鏡音レン" in feats)) and ("レン" in feats):
feats = feats.replace("レン","鏡音レン")
featsl = feats.split(",")
if artist in res2:
res2[artist] += 1
else:
res2[artist] = 1
for feat in featsl:
if feat in res:
res[feat] += 1
else:
res[feat] = 1
elif not len(ats) == 0:
artist = ats[:-1] if ats[-1] == " " else ats
artist = artist.replace("ryo","supercell").replace("ゴジマジP","ラマーズP").replace("ピノキオP","ピノキオピー").replace("ちょむP","TakeponG (ちょむP)").replace("1640mP","40mP").replace("じん (自然の敵P)","じん").replace("wowaka (現実逃避P)","wowaka").replace("マチゲリータP","マチゲリータ")
if artist in res2:
res2[artist] += 1
else:
res2[artist] = 1
sigma = [sum(res.values()),sum(res2.values())]
res = sorted(res.items(), key = lambda x : x[1], reverse = True)
res2 = sorted(res2.items(), key = lambda x : x[1], reverse = True)
songs = sorted(songs.items(), key = lambda x : x[1], reverse = True)
print("")
print("歌手別ランキング")
for result in res:
print(result," ",result[1] / sigma[0] * 100,"%")
print("")
print("アーティスト名ランキング")
for result2 in res2:
print(result2," ",result2[1] / sigma[1] * 100,"%")
print("")
print("曲別ランキング")
for song in songs:
print(song)
input()
完成形
import os
# -*- coding: shift-jis -*-
dir_path = r"ミュージックフォルダまでのパス"
files = []
res = {}
res2 = {}
songs = {}
def add_file(path):
for name in os.listdir(path):
if len(name) > 4:
if name[-4:] == ".mp3":
if name[2] == ' ':
if name[3:-4] in songs:
songs[name[3:-4]] += 1
else:
songs[name[3:-4]] = 1
elif name[3] == ' ':
if name[4:-4] in songs:
songs[name[4:-4]] += 1
else:
songs[name[4:-4]] = 1
files.append(path + "\\" + name)
continue
elif name[-4:] == ".jpg" or name[-4:] == ".ini":
continue
add_file(path + "\\" + name)
def get_tpe1(path):
target = "TPE1".encode("utf-8")
with open(path,"br") as f:
data = f.read()
i = data.find(target) + 7
tmp = data[i + 4:i + 3 + data[i]]
rt = ""
if not i == -1:
try:
return tmp.replace(b"\x00",b"").decode("utf-8")
except Exception:
try:
return tmp.replace(b"\x00",b"").decode("shift-jis")
except Exception:
return tmp.decode("utf-16")
else:
return ""
add_file(dir_path)
print("曲数: ",len(files))
print("種類: ",len(songs))
for path in files:
ats = get_tpe1(path)
if not ats == "":
if "loves" in ats:
l = ats.lower().find("loves") + 5
else:
l = ats.lower().find("feat.") + 5
if not l == 4:
artist = ats[:l - 6] if ats[l - 6] == " " else ats[:l - 5]
artist = artist.replace("ryo","supercell").replace("ゴジマジP","ラマーズP").replace("ピノキオP","ピノキオピー").replace("ちょむP","TakeponG (ちょむP)").replace("1640mP","40mP").replace("じん (自然の敵P)","じん").replace("wowaka (現実逃避P)","wowaka").replace("マチゲリータP","マチゲリータ")
feats = ats[l:].replace(" ","").replace("x",",").replace("&",",").replace("+",",").replace("・",",").replace("、",",")
if ("鏡音リン" in feats) and (not ("鏡音レン" in feats)) and ("レン" in feats):
feats = feats.replace("レン","鏡音レン")
featsl = feats.split(",")
if artist in res2:
res2[artist] += 1
else:
res2[artist] = 1
for feat in featsl:
if feat in res:
res[feat] += 1
else:
res[feat] = 1
elif not len(ats) == 0:
artist = ats[:-1] if ats[-1] == " " else ats
artist = artist.replace("ryo","supercell").replace("ゴジマジP","ラマーズP").replace("ピノキオP","ピノキオピー").replace("ちょむP","TakeponG (ちょむP)").replace("1640mP","40mP").replace("じん (自然の敵P)","じん").replace("wowaka (現実逃避P)","wowaka").replace("マチゲリータP","マチゲリータ")
if artist in res2:
res2[artist] += 1
else:
res2[artist] = 1
sigma = [sum(res.values()),sum(res2.values())]
res = sorted(res.items(), key = lambda x : x[1], reverse = True)
res2 = sorted(res2.items(), key = lambda x : x[1], reverse = True)
songs = sorted(songs.items(), key = lambda x : x[1], reverse = True)
print("")
print("歌手別ランキング")
for result in res:
print(result," ",result[1] / sigma[0] * 100,"%")
print("")
print("アーティスト名ランキング")
for result2 in res2:
print(result2," ",result2[1] / sigma[1] * 100,"%")
print("")
print("曲別ランキング")
for song in songs:
print(song)
input()
結果
曲数: 2937
種類: 2275
歌手別ランキング
('初音ミク', 1359) 52.5725338491296 %
('鏡音リン', 294) 11.37330754352031 %
('鏡音レン', 200) 7.7369439071566735 %
...(略)...
アーティスト名ランキング
('DECO*27', 119) 4.051753489955737 %
('OSTER project', 97) 3.302689819543752 %
('40mP', 83) 2.826012938372489 %
...(略)...
曲別ランキング
('[Secret Track]', 10)
('ロミオとシンデレラ', 10)
('ココロ', 10)
...(略)...