add script “clean-tags.py”

This commit is contained in:
coderkun 2016-07-26 21:48:05 +02:00
commit 51e703e41c

165
clean-tags.py Executable file
View file

@ -0,0 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Dependencies:
# python-mutagen
import argparse
import logging
import os
from mutagen.id3 import ID3
from mutagen import MutagenError
class Styling:
"""Output styling constants."""
ENDC = '\x1b[0m'
BOLD = '\x1b[1m'
class TagCleaner:
"""
Class to check audio files for unwanted tags and provide routines to clean
them.
"""
INDENTATION = " "
FILE_EXTENSIONS = ['.mp3']
TAGS_ID3 = ['TALB', 'TDRC', 'TIT2', 'TPE1', 'TRCK']
def __init__(self, folder):
"""Construct a new tag cleaner instancce."""
self._logger = logging.getLogger(__class__.__name__)
self._dry = False
self._folder = folder
self._files = []
self._read_files(folder)
def set_dry(self, dry):
"""Set dry mode (do not save any file)."""
self._dry = dry
def clean_files(self):
"""Clean all found files."""
self._logger.info("Clean files")
for filename in self._files:
self._clean_file(filename)
def _read_files(self, folder):
self._logger.info("Read files from \"{}\"".format(folder))
for dirname, dirnames, filenames in os.walk(folder):
for filename in filenames:
if filename.startswith("."):
continue
(name, ext) = os.path.splitext(filename)
if ext.lower() not in TagCleaner.FILE_EXTENSIONS:
continue
self._logger.debug("Found file \"%s\"", os.path.join(dirname, filename))
self._files.append(os.path.join(dirname, filename))
self._logger.info("Found %d files".format(len(self._files)))
def _clean_file(self, filename):
"""Clean a file."""
self._logger.info("Clean file \"%s\"", filename)
if os.path.isfile(filename):
# ID3
self._clean_id3(filename)
else:
self._logger.info("Not a file: \"%s\"", filename)
def _clean_id3(self, filename):
"""Clean ID3 tags."""
self._logger.info("Clean ID3")
try:
tags = ID3(filename)
print(Styling.BOLD + filename[len(self._folder):] + Styling.ENDC)
print("ID3", "v{}.{}.{}".format(*tags.version))
valid = True
# Check version
if tags.version != (2, 4, 0):
valid = False
# Unknown tags
if tags.unknown_frames:
valid = False
print("Unknown frames:")
for frame in tags.unknown_frames:
print(frame)
# Invalid tags
invalid_tags = []
for tag in tags:
if len(tag) > 4:
tag = tag[0:4]
if tag not in TagCleaner.TAGS_ID3:
invalid_tags.append(tag)
if invalid_tags:
valid = False
print("Unwanted tags:")
for tag in invalid_tags:
for frame in tags.getall(tag):
if hasattr(frame, 'text'):
for value in frame.text:
print("{}{}: {}".format(TagCleaner.INDENTATION, tag, value))
else:
print("{}{}:".format(TagCleaner.INDENTATION, tag), frame)
# Save
if not valid:
# Delete tags
for tag in invalid_tags:
print("Delete", tag)
tags.delall(tag)
# Save file
if not self._dry:
try:
tags.save()
print("File saved")
except Exception as e:
self._logger.error("Saving of file \"%s\" failed: %s", filename, e)
else:
print("File not saved (running in dry mode)")
else:
self._logger.info("Clean, nothing to do")
except MutagenError as e:
self._logger.error("Cleaning of ID3 tags failed: %s", e)
if __name__ == "__main__":
# Setup command line
parser = argparse.ArgumentParser("Clean unwanted tags from audio files to keep your music library clean.")
parser.add_argument('-d', '--dry', dest='dry', action='store_true', default=False, help="dry run, do not modify any file, just print information")
parser.add_argument('-v', '--verbose', dest='verbosity', action='count', default=0, help="be verbose, show more information")
parser.add_argument('-l', '--logfile', dest='logfile', help="specify name of logfile")
parser.add_argument('folder', help="source folder to read audio files from")
args = parser.parse_args()
# Setup logging
logging.basicConfig(
filename=args.logfile,
level=logging.ERROR-(10*args.verbosity),
format="%(asctime)s %(levelname)s: %(message)s"
)
# Create tag cleaner instance
tag_cleaner = TagCleaner(args.folder)
tag_cleaner.set_dry(args.dry)
# Run action
tag_cleaner.clean_files()