music-library-converter/main.py

79 lines
3.6 KiB
Python

from pydub import AudioSegment
from pydub.utils import mediainfo
from pydub.exceptions import CouldntDecodeError
import os
import shutil
import argparse
from ansicodes import style, fg, bg, util
try:
os.system("") # enables ansi escape characters in terminal
# Argument parser code go here
parser = argparse.ArgumentParser()
parser.add_argument("source", help="The directory containing the music library you want to convert")
parser.add_argument("target", help="The directory where the converted library should go. Will be created if it does not exist. Defaults to <source>_<target format>")
parser.add_argument("-f", "--format", help="Target format. Defaults to mp3.")
parser.add_argument("-b", "--bitrate", help="Target bitrate. Not specified by default.")
parser.add_argument("-k", "--keepotherfiles", help="Also copy over files that aren't audio", action="store_true")
parser.add_argument("-s", "--stripmetadata", help="Strip metadata", action="store_true")
args = parser.parse_args()
targetFormat = "mp3"
if(args.format):
targetFormat = args.format
keepOtherFiles = args.keepotherfiles
preserveMetadata = not args.stripmetadata
startDir = args.source
outDir = args.target
filecount = 0
for path,dirs,files in os.walk(startDir):
for filename in files:
filecount += 1
print(style.bold+"Converting library of"+style.reset,filecount,style.bold+"files in"+style.reset,startDir,style.bold+"to"+style.reset,targetFormat,style.bold+"in"+style.reset,outDir)
print()
for path,dirs,files in os.walk(startDir):
for dirname in dirs:
outdirname = os.path.join(outDir,os.path.join(path,dirname)[len(startDir):])
if not os.path.exists(outdirname):
os.makedirs(outdirname)
for filename in files:
inFile = os.path.join(path,filename)[len(startDir):]
inPath = os.path.join(path,filename)
outPath = os.path.join(outDir,inFile)
convertedPath = outPath[:outPath.rfind(".")]+"."+targetFormat
print(style.bold+"Processing"+style.reset,inFile)
if(os.path.isfile(outPath) or os.path.isfile(convertedPath)):
print("\u001b[1F\u001b[K Exists",convertedPath[len(outDir):])
else:
try: # Here I check if a file is music or not by just attempting to open it as an audio file and handling the file like a non-audio file if it fails. The main benefit to this approach is I don't have to check against a hardcoded list of formats, which makes having at least bare minimum support for the maximum amount of formats possible much easier.
song = AudioSegment.from_file(inPath)
if(preserveMetadata): # Maybe you want to use this to strip the metadata from your audio. I don't know your life
if(args.bitrate):
song.export(convertedPath+".tmp", format=targetFormat, bitrate=args.bitrate, tags=mediainfo(inPath).get('TAG',None))
else:
song.export(convertedPath+".tmp", format=targetFormat, tags=mediainfo(inPath).get('TAG',None))
else:
if(args.bitrate):
song.export(convertedPath+".tmp", format=targetFormat, bitrate=args.bitrate)
else:
song.export(convertedPath+".tmp", format=targetFormat)
os.rename(convertedPath+".tmp", convertedPath)
print("\u001b[1F\u001b[K Converted",convertedPath[len(outDir):])
except (IndexError, CouldntDecodeError):
if(keepOtherFiles):
shutil.copy(inPath, outPath)
print("\u001b[1F\u001b[K Copied",inFile)
else:
print("\u001b[1F\u001b[K Ignored",inFile)
except KeyboardInterrupt:
print(util.clearline+fg.red+"KeyboardInterrupt"+style.reset)