Created
April 13, 2018 21:03
-
-
Save egordm/0345045c15a722493c85fb5217a80d8f to your computer and use it in GitHub Desktop.
Converting all flacs and copying all meta. All folders & files are mirrored including images. Run like this `python drop-the-bytes-music.py "D:\Library\Music" "D:\Library\PhoneMusic" -v -j 4`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
from mutagen import File | |
from mutagen.flac import FLAC | |
from mutagen.easyid3 import EasyID3 | |
import os | |
import shutil | |
from subprocess import call | |
from multiprocessing import Pool | |
from mutagen.id3 import ID3NoHeaderError | |
def main(): | |
parser = argparse.ArgumentParser(description=__doc__) | |
parser.add_argument('source_dir', metavar='source_dir', type=str, help='Path to a directory full of flacs.') | |
parser.add_argument('dest_dir', metavar='dest_dir', type=str, help='Path where you want your mp3\'s to be dropped.') | |
parser.add_argument('-j', '--threads', type=int, default=os.cpu_count(), help='How much threads do you want to run.') | |
parser.add_argument('-v', '--verbose', action="store_true", help='Display the resulting set of tags when done.') | |
args = parser.parse_args() | |
sync_folder(args.source_dir, args.dest_dir, args.threads, args.verbose) | |
def sync_folder(source, destination, verbose=False, threads=os.cpu_count(), level=0): | |
if not os.path.exists(destination): os.makedirs(destination, exist_ok=True) | |
files = os.listdir(source) | |
convert_queue = [] | |
for file in files: | |
file_source = os.path.join(source, file) | |
file_dest = os.path.join(destination, file) | |
if os.path.exists(file_dest) and not os.path.isdir(file_source): | |
if verbose: print(('\t' * level) + f'File: {file} already exists. Skipping') | |
continue | |
if os.path.isdir(file_source): | |
if verbose: print(('\t' * level) + f'Syncing folder: {file}') | |
sync_folder(file_source, file_dest, verbose, threads, level + 1) | |
elif file_source.endswith('.flac'): | |
pre, ext = os.path.splitext(file_dest) | |
file_dest = pre + '.mp3' | |
if os.path.exists(file_dest): continue | |
if verbose: print(('\t' * level) + f'Converting file: {file}') | |
convert_queue.append(tuple([file_source, file_dest])) | |
else: | |
if verbose: print(('\t' * level) + f'Copying file: {file}') | |
shutil.copy2(file_source, file_dest) | |
if verbose: print(('\t' * level) + f'Starting convert jobs:') | |
pool = Pool(threads) | |
pool.starmap(convert_flac, convert_queue) | |
def convert_flac(source, destination): | |
try: | |
call(f'flac --silent --decode --stdout "{source}" | lame --quiet --preset extreme - "{destination}"', shell=True) | |
copy_id3(source, destination) | |
except Exception as e: print(f'Failed converting: {source}') | |
def copy_id3(srcname, destname, verbose=False): | |
try: | |
meta = EasyID3(destname) | |
except ID3NoHeaderError: | |
meta = File(destname, easy=True) | |
meta.add_tags() | |
meta.save() | |
src = FLAC(srcname) | |
dest = EasyID3(destname) | |
for tag in src: | |
if tag in EasyID3.valid_keys.keys(): dest[tag] = src[tag] | |
dest.save() | |
if verbose: | |
print("Copied ID3 tags from %(srcname)r to %(destname)r--result:" % locals()) | |
print(dest.pprint()) | |
if __name__ == "__main__": | |
main() |
FLAC and LAME are required btw
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
python drop-the-bytes-music.py "D:\Library\Music" "D:\Library\PhoneMusic" -v -j 4
Source Destination Verbose ThreadCount