wav support!

This commit is contained in:
Lynne Megido 2020-10-26 23:34:04 +10:00
parent 5d6ac79cd1
commit 16ddf2118c
Signed by: lynnesbian
GPG key ID: F0A184B5213D9F90

56
bcao.py
View file

@ -29,7 +29,7 @@ from mutagen.oggvorbis import OggVorbis
from mutagen.mp3 import MP3 from mutagen.mp3 import MP3
from mutagen.mp4 import MP4, MP4Cover from mutagen.mp4 import MP4, MP4Cover
# noinspection PyProtectedMember # noinspection PyProtectedMember
from mutagen.id3 import APIC, PictureType from mutagen.id3 import APIC, PictureType, Frame, TRCK, TPE1, TIT2, TALB, TPE2
from PIL import Image from PIL import Image
@ -37,7 +37,7 @@ fully_supported: List[str] = ["ogg", "flac", "mp3", "m4a", "wav"]
MutagenFile = Union[MP3, FLAC, OggVorbis, mutagen.FileType] MutagenFile = Union[MP3, FLAC, OggVorbis, mutagen.FileType]
MutagenTags = Union[mutagen.id3.ID3Tags, mutagen.mp4.Tags, mutagen.oggvorbis.OggVCommentDict] MutagenTags = Union[mutagen.id3.ID3Tags, mutagen.mp4.Tags, mutagen.oggvorbis.OggVCommentDict]
args: argparse.Namespace args: argparse.Namespace
tmp_dir: tempfile.TemporaryDirectory[Any] tmp_dir: tempfile.TemporaryDirectory # type: ignore
class SongInfo: class SongInfo:
tag_lookup: Dict[str, Dict[str, str]] = { tag_lookup: Dict[str, Dict[str, str]] = {
@ -49,15 +49,17 @@ class SongInfo:
} }
format_lookup: Dict[str, str] = { format_lookup: Dict[str, str] = {
"mp3": "id3", "mp3": "id3",
"m4a": "m4a", "m4a": "m4a",
"ogg": "vorbis", "ogg": "vorbis",
"flac": "vorbis" "flac": "vorbis",
"wav": "id3"
} }
def __init__(self, file_name: Path): def __init__(self, file_name: Path):
self.m_file: MutagenFile = mutagen.File(file_name) self.m_file: MutagenFile = mutagen.File(file_name)
self.m_tags: MutagenTags = self.m_file.tags self.m_tags: MutagenTags = self.m_file.tags
self.file_name = str(file_name.name) self.file_name = str(file_name.name)
self.format = path.splitext(file_name)[1][1:] self.format = path.splitext(file_name)[1][1:]
self.fallback = False self.fallback = False
@ -73,7 +75,7 @@ class SongInfo:
# set default values for the tags, in case the file is missing any (or all!) of them # set default values for the tags, in case the file is missing any (or all!) of them
self.tags: Dict[str, str] = { self.tags: Dict[str, str] = {
"track": fallbacks.group("track"), "track": str(int(fallbacks.group("track"))), # convert to int and str again to turn e.g. "01" into "1"
"artist": fallbacks.group("artist"), "artist": fallbacks.group("artist"),
"title": fallbacks.group("title"), "title": fallbacks.group("title"),
"album": fallbacks.group("album"), "album": fallbacks.group("album"),
@ -84,8 +86,19 @@ class SongInfo:
self.list_tags: Dict[str, List[str]] = dict((x[0], [x[1]]) for x in self.tags.items()) self.list_tags: Dict[str, List[str]] = dict((x[0], [x[1]]) for x in self.tags.items())
if self.m_tags is None: if self.m_tags is None:
# file has no tags
# generate empty tags
self.m_file.add_tags()
self.m_tags = self.m_file.tags
self.fallback = True self.fallback = True
# write fallback tags to file
for standard_name, tag_set in self.tag_lookup.items():
tag = tag_set[self.format_lookup[self.format]]
self.m_tags[tag] = self.new_id3_tag(standard_name, self.tags[standard_name])
self.m_file.save()
else: else:
for standard_name, tag_set in self.tag_lookup.items(): for standard_name, tag_set in self.tag_lookup.items():
tag = tag_set[self.format_lookup[self.format]] tag = tag_set[self.format_lookup[self.format]]
@ -112,6 +125,26 @@ class SongInfo:
self.tags[standard_name] = value_list[0] self.tags[standard_name] = value_list[0]
self.list_tags[standard_name] = value_list self.list_tags[standard_name] = value_list
@staticmethod
def new_id3_tag(tag: str, value: str) -> Frame:
if tag == "track":
return TRCK(encoding=3, text=value)
elif tag == "artist":
return TPE1(encoding=3, text=value)
elif tag == "title":
return TIT2(encoding=3, text=value)
elif tag == "album":
return TALB(encoding=3, text=value)
elif tag == "album_artist":
return TPE2(encoding=3, text=value)
else:
raise ValueError(f"Unknown tag type {tag}!")
def get_target_name(self, zeroes: int) -> str: def get_target_name(self, zeroes: int) -> str:
return f"{self.tags['track'].zfill(zeroes)} {self.tags['title']}.{self.format}" return f"{self.tags['track'].zfill(zeroes)} {self.tags['title']}.{self.format}"
@ -122,7 +155,7 @@ class SongInfo:
if self.format == "flac": if self.format == "flac":
return len(self.m_file.pictures) != 0 return len(self.m_file.pictures) != 0
if self.format == "mp3": if self.format == "mp3" or self.format == "wav":
apics: List[APIC] = self.m_tags.getall("APIC") apics: List[APIC] = self.m_tags.getall("APIC")
for apic in apics: for apic in apics:
if apic.type == PictureType.COVER_FRONT: if apic.type == PictureType.COVER_FRONT:
@ -141,7 +174,7 @@ class SongInfo:
elif self.format == "flac": elif self.format == "flac":
self.m_file.clear_pictures() self.m_file.clear_pictures()
self.m_file.add_picture(to_embed) self.m_file.add_picture(to_embed)
elif self.format == "mp3": elif self.format in ["mp3", "wav"]:
self.m_tags.add(to_embed) self.m_tags.add(to_embed)
elif self.format == "m4a": elif self.format == "m4a":
self.m_tags['covr'] = [to_embed] self.m_tags['covr'] = [to_embed]
@ -157,6 +190,9 @@ def log(message: str, importance: int = 0) -> None:
def die(message: str, code: int = 1) -> None: def die(message: str, code: int = 1) -> None:
print(message) print(message)
if tmp_dir is not None:
tmp_dir.cleanup()
sys.exit(code) sys.exit(code)
def sanitise(in_str: str) -> str: def sanitise(in_str: str) -> str:
@ -279,7 +315,7 @@ def main() -> None:
embed_cover.height = image.size[1] embed_cover.height = image.size[1]
embed_cover.depth = image.bits embed_cover.depth = image.bits
elif song_format == "mp3": elif song_format in ["mp3", "wav"]:
# apparently APIC files get compressed on save if they are "large": # apparently APIC files get compressed on save if they are "large":
# https://mutagen.readthedocs.io/en/latest/api/id3_frames.html#mutagen.id3.APIC # https://mutagen.readthedocs.io/en/latest/api/id3_frames.html#mutagen.id3.APIC
# i don't know what that means (lossless text compression? automatic JPEG conversion?) and i don't know if or how # i don't know what that means (lossless text compression? automatic JPEG conversion?) and i don't know if or how