2020-09-30 16:38:41 +00:00
|
|
|
import os
|
|
|
|
import getopt
|
|
|
|
import sys
|
|
|
|
import shutil
|
|
|
|
|
2023-06-05 07:26:36 +00:00
|
|
|
import mobject
|
|
|
|
|
2020-09-30 16:38:41 +00:00
|
|
|
total_proc = 0
|
|
|
|
total_succ = 0
|
|
|
|
total_error = 0
|
2023-06-05 07:26:36 +00:00
|
|
|
total_missing_cover = 0
|
2020-09-30 16:38:41 +00:00
|
|
|
|
|
|
|
input_dir = None
|
|
|
|
output_dir = None
|
|
|
|
cover_dir = None
|
|
|
|
cover_arts = []
|
|
|
|
|
2020-09-30 19:28:32 +00:00
|
|
|
UNKNOWN_ARTIST_NAME = "Unknown Artist"
|
2020-09-30 16:38:41 +00:00
|
|
|
UNKNOWN_ALBUM_NAME = "Unknown Album"
|
|
|
|
|
|
|
|
WILDCARD_MATCH_SCORE = 1
|
|
|
|
ARTIST_MATCH_SCORE = 10
|
|
|
|
ALBUM_MATCH_SCORE = 100
|
|
|
|
TITLE_MATCH_SCORE = 1000
|
|
|
|
|
|
|
|
# to get a > 0 score, each field either must match or the cover tuple is wildcare (None)
|
|
|
|
def calc_cover_score(artist: str, album: str, title: str, tup : tuple):
|
|
|
|
score = 0
|
|
|
|
|
|
|
|
if (tup[0] == artist):
|
|
|
|
score += ARTIST_MATCH_SCORE
|
|
|
|
elif (tup[0] == ""):
|
|
|
|
score += WILDCARD_MATCH_SCORE
|
|
|
|
else:
|
|
|
|
# mismatched artist, discard
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if (tup[1] == album):
|
|
|
|
score += ALBUM_MATCH_SCORE
|
|
|
|
elif (tup[1] == ""):
|
|
|
|
score += WILDCARD_MATCH_SCORE
|
|
|
|
else:
|
|
|
|
# mismatched album, discard
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if (tup[2] == title):
|
|
|
|
score += TITLE_MATCH_SCORE
|
|
|
|
elif (tup[2] == ""):
|
|
|
|
score += WILDCARD_MATCH_SCORE
|
|
|
|
else:
|
|
|
|
# mismatched title, discard
|
|
|
|
return 0
|
|
|
|
|
|
|
|
return score
|
|
|
|
|
|
|
|
# returns the idx into cover_arts array.
|
|
|
|
# < 0 means no match
|
|
|
|
def find_best_cover(artist: str, album: str, title: str):
|
|
|
|
best_idx = -1
|
|
|
|
best_score = 0
|
|
|
|
for i in range(0, len(cover_arts)):
|
|
|
|
score = calc_cover_score(artist, album, title, cover_arts[i])
|
|
|
|
if score > best_score:
|
|
|
|
best_idx = i
|
|
|
|
best_score = score
|
|
|
|
|
|
|
|
return best_idx
|
|
|
|
|
|
|
|
|
2020-09-30 19:28:32 +00:00
|
|
|
def parse_triple(f: str):
|
|
|
|
triple = os.path.splitext(os.path.basename(f))[0].split("_")
|
|
|
|
album = ""
|
|
|
|
title = ""
|
|
|
|
artist = triple[0]
|
|
|
|
if len(triple) >= 2:
|
|
|
|
album = triple[1]
|
|
|
|
if len(triple) >= 3:
|
|
|
|
title = triple[2]
|
|
|
|
return artist, album, title
|
|
|
|
|
2020-09-30 16:38:41 +00:00
|
|
|
def load_cover_arts():
|
|
|
|
global cover_arts
|
|
|
|
|
|
|
|
if cover_dir == None:
|
|
|
|
return
|
|
|
|
|
|
|
|
cdir = cover_dir
|
|
|
|
files = os.listdir(cdir)
|
|
|
|
for f in files:
|
|
|
|
try:
|
2020-09-30 19:28:32 +00:00
|
|
|
artist, album, title = parse_triple(f)
|
2020-09-30 16:38:41 +00:00
|
|
|
f = os.path.join(cover_dir, f)
|
|
|
|
print("Processing cover art - " + f)
|
|
|
|
with open(f,'rb') as img:
|
|
|
|
cover_arts.append((artist, album, title, img.read(), os.path.basename(f)))
|
|
|
|
print(" Loading cover art - " + f + " Artist: " + artist + " Album: " + album + " Title: " + title)
|
|
|
|
except Exception as e:
|
|
|
|
print(" Skipping due to Exception - " + str(e))
|
|
|
|
print("")
|
|
|
|
|
|
|
|
|
|
|
|
def usage():
|
|
|
|
print("Usage: python musik.py [options]\n\n\
|
|
|
|
options:\n\
|
|
|
|
-h : show usage.\n\
|
|
|
|
-i input : input directory\n\
|
|
|
|
-o output : output directory\n\
|
|
|
|
-c cover : cover arts page\n")
|
|
|
|
|
|
|
|
def process_file(f: str, odir: str):
|
2023-06-05 07:26:36 +00:00
|
|
|
global total_missing_cover
|
2020-09-30 16:38:41 +00:00
|
|
|
global total_succ
|
|
|
|
global total_error
|
|
|
|
global total_proc
|
|
|
|
try:
|
|
|
|
print("Processing file - " + f)
|
|
|
|
total_proc += 1
|
|
|
|
|
2020-09-30 19:28:32 +00:00
|
|
|
artist, album, title = parse_triple(f)
|
2020-09-30 16:38:41 +00:00
|
|
|
if album == "":
|
|
|
|
album = UNKNOWN_ALBUM_NAME
|
|
|
|
if artist == "":
|
|
|
|
artist = UNKNOWN_ARTIST_NAME
|
2020-09-30 19:28:32 +00:00
|
|
|
if title == "":
|
2020-09-30 16:38:41 +00:00
|
|
|
raise Exception("No title")
|
|
|
|
|
2023-06-05 07:26:36 +00:00
|
|
|
mobj = mobject.create_mobject(f)
|
|
|
|
|
|
|
|
print(f" Artist: \"{mobj.get_artist()}\" -> \"{artist}\"\n" +
|
|
|
|
f" Album: \"{mobj.get_album()}\" -> \"{album}\"\n" +
|
|
|
|
f" Title: \"{mobj.get_title()}\" -> \"{title}\"")
|
|
|
|
|
|
|
|
mobj.set_artist(artist)
|
|
|
|
mobj.set_album(album)
|
|
|
|
mobj.set_title(title)
|
|
|
|
|
|
|
|
if (mobj.get_cover() == None):
|
|
|
|
cover_idx = find_best_cover(artist, album, title)
|
|
|
|
if (cover_idx >= 0):
|
|
|
|
mobj.set_cover(cover_arts[cover_idx][3])
|
|
|
|
print(" Cover: <None> -> <New>")
|
|
|
|
else:
|
|
|
|
total_missing_cover += 1
|
|
|
|
print(" Cover: <None> -> <None>")
|
|
|
|
else:
|
|
|
|
print(" Cover: <Exists>")
|
2020-09-30 16:38:41 +00:00
|
|
|
|
|
|
|
target_dir = os.path.join(odir, artist, album)
|
|
|
|
os.makedirs(target_dir, exist_ok = True)
|
|
|
|
|
|
|
|
target_f = os.path.join(target_dir, os.path.basename(f))
|
2023-06-05 07:26:36 +00:00
|
|
|
with open(target_f, "wb") as tf:
|
|
|
|
tf.write(mobj.get_bytes())
|
|
|
|
print(" Written file to: " + target_f)
|
2020-09-30 19:28:32 +00:00
|
|
|
|
2020-09-30 16:38:41 +00:00
|
|
|
total_succ += 1
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
total_error += 1
|
|
|
|
print(" Skipping due to exception - %s" % str(e))
|
|
|
|
|
|
|
|
print("")
|
|
|
|
|
|
|
|
def process_directory(idir: str, odir: str):
|
|
|
|
print("Processing directory - " + idir)
|
|
|
|
files = os.listdir(idir)
|
|
|
|
for f in files:
|
|
|
|
f = os.path.join(idir, f)
|
|
|
|
if os.path.isdir(f):
|
|
|
|
process_directory(f, odir)
|
|
|
|
else:
|
|
|
|
process_file(f, odir)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
global input_dir
|
|
|
|
global output_dir
|
|
|
|
global cover_dir
|
|
|
|
|
|
|
|
try:
|
|
|
|
opts , _ = getopt.getopt(sys.argv[1:], "hi:o:c:")
|
|
|
|
except getopt.GetoptError as err:
|
|
|
|
print(str(err))
|
|
|
|
usage()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
for o, a in opts:
|
|
|
|
if o == "-h":
|
|
|
|
usage()
|
|
|
|
sys.exit(0)
|
|
|
|
elif o == "-i":
|
|
|
|
input_dir = a
|
|
|
|
elif o == "-o":
|
|
|
|
output_dir = a
|
|
|
|
elif o == "-c":
|
|
|
|
cover_dir = a
|
|
|
|
else:
|
|
|
|
print("Unrecognized option: " + o)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if input_dir == None or output_dir == None:
|
|
|
|
print("Must specify both -i and -o")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
load_cover_arts()
|
|
|
|
process_directory(input_dir, output_dir)
|
|
|
|
|
2023-06-05 07:26:36 +00:00
|
|
|
print("\nSummary - Total Files: " + str(total_proc) + " Total Errors: " + str(total_error) + " Total Missing Covers: " + str(total_missing_cover))
|
2020-09-30 16:38:41 +00:00
|
|
|
|
|
|
|
main()
|