This commit is contained in:
quackerd 2023-06-05 09:26:36 +02:00
parent 08098695cc
commit fdeb1c4289
2 changed files with 168 additions and 43 deletions

140
mobject.py Normal file
View File

@ -0,0 +1,140 @@
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB, Encoding, PictureType
from mutagen.flac import FLAC, Picture
from pathlib import Path
import io
class MObject:
_file_bytes : bytes
_file_io : io.BytesIO
def __init__(self, fb : bytes):
self._file_bytes = fb
self._file_io = io.BytesIO(fb)
return
def get_bytes(self) -> bytes:
return self._file_io.getbuffer()
def get_title(self) -> str:
raise Exception("unimplemented")
def get_album(self) -> str:
raise Exception("unimplemented")
def get_artist(self) -> str:
raise Exception("unimplemented")
def get_cover(self) -> bytes:
raise Exception("unimplemented")
def set_artist(self, val : str) -> None:
raise Exception("unimplemented")
def set_album(self, val : str) -> None:
raise Exception("unimplemented")
def set_title(self, val : str) -> None:
raise Exception("unimplemented")
def set_cover(self, val : bytes, png : bool = False) -> None:
raise Exception("unimplemented")
class MMP3Object(MObject):
_id3 : ID3
def __init__(self, file : bytes):
super().__init__(self, file)
self._id3 = ID3()
self._id3.load(self._file_io, translate = True)
return
def get_title(self) -> str:
return self._id3.get("TIT2", default = TIT2(text = None)).text
def set_title(self, val : str) -> None:
self._id3.delall("TIT2")
self._id3.add(TIT2(text = val))
self._id3.save()
def get_album(self) -> str:
return self._id3.get("TALB", default = TALB(text = None)).text
def set_album(self, val : str) -> None:
self._id3.delall("TALB")
self._id3.add(TALB(text = val))
self._id3.save()
def get_artist(self) -> str:
return self._id3.get("TPE1", default = TPE1(text = None)).text
def set_artist(self, val : str):
self._id3.delall("TPE1")
self._id3.add(TPE1(text = val))
self._id3.save()
def get_cover(self) -> bytes:
cover = self._id3.get("APIC", default=APIC(encoding = Encoding.UTF8, mime = "image/jpeg", type=PictureType.COVER_FRONT, desc=u"Cover", data = None))
return cover.data
def set_cover(self, val : bytes, png : bool = False) -> None:
self._id3.delall("APIC")
self._id3.add(APIC(encoding = Encoding.UTF8, mime = "image/png" if png else "image/jpeg", type=PictureType.COVER_FRONT, desc=u"Cover", data = val))
self._id3.save()
class MFLACObject(MObject):
_flac : FLAC
def __init__(self, file : bytes):
super().__init__(self, file)
self._flac = FLAC(self._file_io)
return
def get_title(self) -> str:
return self._flac.get("TITLE", default = None)
def set_title(self, val : str) -> None:
self._flac["TITLE"] = val
self._flac.save()
def get_album(self) -> str:
return self._flac.get("ALBUM", default = None)
def set_album(self, val : str) -> None:
self._flac["ALBUM"] = val
self._flac.save()
def get_artist(self) -> str:
return self._flac.get("ARTIST", default = None)
def set_artist(self, val : str):
self._flac["ARTIST"] = val
self._flac.save()
def get_cover(self) -> bytes:
pics = self._flac.pictures
if len(pics) > 0:
return pics[0].data
else:
return None
def set_cover(self, val : bytes, png : bool = False) -> None:
self._flac.clear_pictures()
pic = Picture()
pic.type = PictureType.COVER_FRONT
pic.mime = "image/png" if png else "image/jpeg"
pic.desc = "Cover"
pic.data = val
self._flac.add_picture(pic)
self._flac.save()
def create_mobject(filepath : str) -> MObject:
fp = Path(filepath)
with open(fp, "rb") as f:
buf = f.read()
if (fp.suffix == "mp3"):
return MMP3Object(buf)
if (fp.suffix == "flac"):
return MFLACObject(buf)
return None

View File

@ -1,15 +1,14 @@
import os
import mutagen
from mutagen.easyid3 import EasyID3
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB
import getopt
import sys
import shutil
import mobject
total_proc = 0
total_succ = 0
total_error = 0
total_cover = 0
total_missing_cover = 0
input_dir = None
output_dir = None
@ -108,10 +107,8 @@ def usage():
-o output : output directory\n\
-c cover : cover arts page\n")
no_match = []
def process_file(f: str, odir: str):
global total_cover
global total_missing_cover
global total_succ
global total_error
global total_proc
@ -120,51 +117,41 @@ def process_file(f: str, odir: str):
total_proc += 1
artist, album, title = parse_triple(f)
# id3 = ID3(f)
# album = str(id3.get("TALB") if id3.get("TALB") != None else "")
if album == "":
album = UNKNOWN_ALBUM_NAME
# artist = str(id3.get("TPE1") if id3.get("TPE1") != None else "")
if artist == "":
artist = UNKNOWN_ARTIST_NAME
# title = str(id3.get("TIT2") if id3.get("TIT2") != None else "")
if title == "":
raise Exception("No title")
print(" Identified artist: " + artist + " album: " + album + " title: " + title)
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>")
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))
try:
shutil.copyfile(f, target_f)
except shutil.SameFileError:
pass
print(" Copied file to: " + target_f)
cover_idx = find_best_cover(artist, album, title)
audio = mutagen.File(f)
print(f" File info: {audio.info.pprint()}")
audio["title"] = title
audio["artist"] = artist
audio["album"] = album
audio.save()
# if cover_idx >= 0:
# # install cover
# id3.delall("APIC")
# id3.add(APIC(3, "image/jpeg", 3, "front cover", cover_arts[cover_idx][3]))
# total_cover += 1
# print(f" Written metadata for {f} with cover art - " + cover_arts[cover_idx][4])
# else:
# no_match.append(target_f)
with open(target_f, "wb") as tf:
tf.write(mobj.get_bytes())
print(" Written file to: " + target_f)
total_succ += 1
@ -218,8 +205,6 @@ def main():
load_cover_arts()
process_directory(input_dir, output_dir)
print("\nSummary - Total Files: " + str(total_proc) + " Total Errors: " + str(total_error) + " Total Covers: " + str(total_cover))
for each in no_match:
print("No match: " + each)
print("\nSummary - Total Files: " + str(total_proc) + " Total Errors: " + str(total_error) + " Total Missing Covers: " + str(total_missing_cover))
main()