files/tag-mp3s.py

99 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
import getopt
import glob
import mutagen.id3
import mutagen.mp3
import os
import sys
import re
min_mp3s_for_album = 4
dry_run = False
def walk_tree(base_dir, visit_function):
visit_function(base_dir)
for ent in os.listdir(base_dir):
if ent.startswith("."):
next
path = "%s/%s" % (base_dir, ent)
if os.path.isdir(path):
walk_tree(path, visit_function)
def process_dir(path):
mp3s = glob.glob("%s/*.mp3" % path)
jpgs = glob.glob("%s/*.jpg" % path)
artwork_path = choose_artwork(mp3s, jpgs)
for mp3 in mp3s:
process_mp3(mp3, artwork_path)
def choose_artwork(mp3s, jpgs):
if len(mp3s) < min_mp3s_for_album:
return None
if len(jpgs) == 0:
sys.stderr.write("No .jpg files found\n")
return None
if len(jpgs) > 1:
sys.stderr.write("Multiple .jpg album artwork files found\n")
return None
return jpgs[0]
def read_file(fname):
f = open(fname, "rb")
data = f.read()
f.close()
return data
def clean_title(title):
new_title = re.sub(r'[\[\(]((explicit\s+)?album\s+version|explicit|clean)[\]\)]', '', title, flags = re.IGNORECASE)
new_title = re.sub(r'\s\s+', ' ', new_title)
return new_title.strip()
def clean_tag(mp3, tagname):
if tagname in mp3:
tag = mp3[tagname]
if tag is not None:
orig_text = tag.text[0]
new_text = clean_title(orig_text)
if new_text != orig_text:
sys.stdout.write("Changing %s from \"%s\" to \"%s\"\n" % (tagname, orig_text, new_text))
tag.text = [new_text]
return True
return False
def process_mp3(mp3_path, artwork_path):
mp3 = mutagen.mp3.MP3(mp3_path)
current_tags = mp3.tags
changed = False
changed = clean_tag(mp3, "TIT2") or changed
changed = clean_tag(mp3, "TALB") or changed
if artwork_path is not None:
apic_tags = [tag for tag in current_tags if tag == "APIC" or tag.startswith("APIC:")]
if len(apic_tags) < 1:
print("Adding APIC tag to %s..." % mp3_path)
jpg_data = read_file(artwork_path)
apic = mutagen.id3.APIC(0, "image/jpeg", 0, "", jpg_data)
mp3.tags.add(apic)
changed = True
if changed and not dry_run:
sys.stdout.write("Writing %s\n" % mp3_path)
mp3.save()
def main(argv):
base_dir = "."
opts, args = getopt.getopt(argv, 'd:n')
for opt, val in opts:
if opt == '-d':
base_dir = val
elif opt == '-n':
global dry_run
dry_run = True
if len(args) > 0:
sys.stderr.write("Usage: %s\n" % (sys.argv[0]))
return
walk_tree(base_dir, process_dir)
if __name__ == "__main__":
main(sys.argv[1:])