79 lines
3.6 KiB
Python
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) |