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 os
import mutagen
from mutagen.easyid3 import EasyID3
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB
import getopt import getopt
import sys import sys
import shutil import shutil
import mobject
total_proc = 0 total_proc = 0
total_succ = 0 total_succ = 0
total_error = 0 total_error = 0
total_cover = 0 total_missing_cover = 0
input_dir = None input_dir = None
output_dir = None output_dir = None
@ -108,10 +107,8 @@ def usage():
-o output : output directory\n\ -o output : output directory\n\
-c cover : cover arts page\n") -c cover : cover arts page\n")
no_match = []
def process_file(f: str, odir: str): def process_file(f: str, odir: str):
global total_cover global total_missing_cover
global total_succ global total_succ
global total_error global total_error
global total_proc global total_proc
@ -120,51 +117,41 @@ def process_file(f: str, odir: str):
total_proc += 1 total_proc += 1
artist, album, title = parse_triple(f) artist, album, title = parse_triple(f)
# id3 = ID3(f)
# album = str(id3.get("TALB") if id3.get("TALB") != None else "")
if album == "": if album == "":
album = UNKNOWN_ALBUM_NAME album = UNKNOWN_ALBUM_NAME
# artist = str(id3.get("TPE1") if id3.get("TPE1") != None else "")
if artist == "": if artist == "":
artist = UNKNOWN_ARTIST_NAME artist = UNKNOWN_ARTIST_NAME
# title = str(id3.get("TIT2") if id3.get("TIT2") != None else "")
if title == "": if title == "":
raise Exception("No 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) target_dir = os.path.join(odir, artist, album)
os.makedirs(target_dir, exist_ok = True) os.makedirs(target_dir, exist_ok = True)
target_f = os.path.join(target_dir, os.path.basename(f)) target_f = os.path.join(target_dir, os.path.basename(f))
try: with open(target_f, "wb") as tf:
shutil.copyfile(f, target_f) tf.write(mobj.get_bytes())
except shutil.SameFileError: print(" Written file to: " + target_f)
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)
total_succ += 1 total_succ += 1
@ -218,8 +205,6 @@ def main():
load_cover_arts() load_cover_arts()
process_directory(input_dir, output_dir) process_directory(input_dir, output_dir)
print("\nSummary - Total Files: " + str(total_proc) + " Total Errors: " + str(total_error) + " Total Covers: " + str(total_cover)) print("\nSummary - Total Files: " + str(total_proc) + " Total Errors: " + str(total_error) + " Total Missing Covers: " + str(total_missing_cover))
for each in no_match:
print("No match: " + each)
main() main()