from mutagen.id3 import ID3, APIC, TIT2, TPE1, TPE2, 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) -> list[str]: raise Exception("unimplemented") def get_album(self) -> list[str]: raise Exception("unimplemented") def get_album_artist(self) -> list[str]: raise Exception("unimplemented") def get_artist(self) -> list[str]: raise Exception("unimplemented") def get_cover(self) -> bytes: raise Exception("unimplemented") def set_artist(self, val : list[str]) -> None: raise Exception("unimplemented") def set_album_artist(self, val : list[str]) -> None: raise Exception("unimplemented") def set_album(self, val : list[str]) -> None: raise Exception("unimplemented") def set_title(self, val : list[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__(file) self._id3 = ID3() self._id3.load(self._file_io, translate = True) return def get_title(self) -> list[str]: return self._id3.get("TIT2") def set_title(self, val : list[str]) -> None: self._id3.delall("TIT2") self._id3.add(TIT2(text = val)) self._file_io.seek(0) self._id3.save(self._file_io) def get_album(self) -> list[str]: return self._id3.get("TALB") def set_album(self, val : list[str]) -> None: self._id3.delall("TALB") self._id3.add(TALB(text = val)) self._file_io.seek(0) self._id3.save(self._file_io) def get_artist(self) -> list[str]: return self._id3.get("TPE1") def set_artist(self, val : list[str]): self._id3.delall("TPE1") self._id3.add(TPE1(text = val)) self._file_io.seek(0) self._id3.save(self._file_io) def get_album_artist(self) -> list[str]: return self._id3.get("TPE2") def set_album_artist(self, val : list[str]) -> None: self._id3.delall("TPE2") self._id3.add(TPE2(text = val)) self._file_io.seek(0) self._id3.save(self._file_io) def get_cover(self) -> bytes: cover = self._id3.getall("APIC") if (cover == None or len(cover) == 0): return None return cover[0].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._file_io.seek(0) self._id3.save(self._file_io) class MFLACObject(MObject): _flac : FLAC def __init__(self, file : bytes): super().__init__(file) self._flac = FLAC(self._file_io) return def get_title(self) -> list[str]: return self._flac.get("TITLE") def set_title(self, val : list[str]) -> None: self._flac["TITLE"] = val[0] self._file_io.seek(0) self._flac.save(self._file_io) def get_album(self) -> list[str]: return self._flac.get("ALBUM") def set_album(self, val : list[str]) -> None: self._flac["ALBUM"] = val[0] self._file_io.seek(0) self._flac.save(self._file_io) def get_album_artist(self) -> list[str]: return self._flac.get("ALBUMARTIST") def set_album_artist(self, val : list[str]) -> None: self._flac["ALBUMARTIST"] = val self._file_io.seek(0) self._flac.save(self._file_io) def get_artist(self) -> list[str]: return self._flac.get("ARTIST") def set_artist(self, val : list[str]): self._flac["ARTIST"] = val self._file_io.seek(0) self._flac.save(self._file_io) 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._file_io.seek(0) self._flac.save(self._file_io) 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