Distinguish The Files
The first task on our plan is distinguishing files that are missing ID3 data and also do not follow our predefined file structure pattern. We'll use the code from the previous article to check for missing ID3 data, as well as our previously devised comparison that checks if the input directory and the output directory are the same. However, rather than checking if the directories match, we will use an else condition to determine the directories do not match, which would mean the file does not necessarily follow our predefined pattern.
Code:
The first task on our plan is distinguishing files that are missing ID3 data and also do not follow our predefined file structure pattern. We'll use the code from the previous article to check for missing ID3 data, as well as our previously devised comparison that checks if the input directory and the output directory are the same. However, rather than checking if the directories match, we will use an else condition to determine the directories do not match, which would mean the file does not necessarily follow our predefined pattern.
Code:
#!/usr/bin/python import sys, os, fnmatch, shutil, argparse, re from mutagen.easyid3 import EasyID3 from mutagen.id3 import ID3, TIT2 def getTrackNumber(track): if track.find("/") > -1: return getTrackNumber(track[0:track.find("/")]) elif track.isdigit(): return track.zfill(2) def getID3FromFilename(file, id3info): filename = os.path.basename(file) m = re.match(r"(?P<trackNumber>\d{2})\. (?P<artist>((?! -).)+) - (?P<title>[^\.]+)\.mp3", filename) id3info["tracknumber"] = m.group('trackNumber') id3info["artist"] = m.group('artist') id3info["title"] = m.group('title') id3info["album"] = file.split('/')[-2] id3info.save() def move(output, file, dirMatch): # Check if there are ID3 tags to begin with, if not, it will complain try: tag = ID3(file) except: tag = ID3() tag.add(TIT2(encoding=3, text=["Title"])) tag.save(file) id3info = EasyID3(file) try: _trackNumber = getTrackNumber(id3info["tracknumber"][0]) _artist = id3info["artist"][0] _title = id3info["title"][0] _album = id3info["album"][0] except KeyError: if dirMatch: getID3FromFilename(file, id3info) return else: print "ID3 info missing and directories do not match for file: ", file return outputDir = output + "/" + _artist + "/" + _album + "/" outputFile = _trackNumber + ". " + _artist + " - " + _title + ".mp3" if not os.path.exists(outputDir): os.makedirs(outputDir) shutil.move(file, outputDir + outputFile) def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', '--directory', nargs=1, required=True, help='') parser.add_argument('-o', '--output', nargs=1, required=True, help='') args = parser.parse_args() directory = os.path.abspath(args.directory[0]) output = os.path.abspath(args.output[0]) dirMatch = (directory == output) for root, subFolders, filenames in os.walk(directory): for filename in fnmatch.filter(filenames, '*.mp3'): move(output, os.path.join(root, filename), dirMatch) main()Result:
$ ./mp3-tagger.py -d /UntamedMusic/ -o /Music/ ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - Moving Mountains.mp3 ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - Child Of Dust.mp3 ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - The Earth Isnt Humming.mp3 ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - Digging My Own Grave.mp3 ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - The Lion And The Wolf.mp3 ID3 info missing and directories do not match for file: /UntamedMusic/The Alchemy Index Vol. 4 - Earth/Thrice - Come All You Weary.mp3As you can see, the files I'm working with are not in the predefined pattern, so the ID3 data cannot be determined by file path alone. You can also see from the results that at least some of the ID3 info is missing. The files I'm using to test have the Artist and Title tags filled in only.