Created
September 2, 2017 04:19
-
-
Save kaitwalla/d38427855c73e1d2ba30a5a338a779f6 to your computer and use it in GitHub Desktop.
A small utility for copying music to a folder with a limit on the number of files per folder (copying music to a USB drive for use in a car)
This file contains 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
{"Folders" : | |
{ | |
"Comedy": false, | |
"Famous": false, | |
"Mellow": false, | |
"Mixes": ["Youtube Mixes"], | |
"Musicals": false, | |
"OST - Instrumental": false, | |
"Standup": false, | |
"XMas": false | |
} | |
} |
This file contains 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
''' This little command-line utility takes music in an existing folder structure and copies it to a | |
destination, flattening it out to a single level in the process. | |
The specific use case is I wanted to copy my music from my collection to the USB drive for my car, | |
which has a limit of 255 files in a folder. There's an optional third argument if you want to exclude | |
top or second-level folders; just build a JSON file, and pass the file location | |
as the third argument. | |
Exmaple usage: | |
music_to_usb.py '/Volumes/HDD/Music' '/Volumes/CAR_USB' | |
music_to_usb.py '/Volumes/HDD/Music' '/Volumes/CAR_USB' 'folders_to_skip.json' | |
In the JSON file, if you want to exclude second-level folders, just include | |
them as an array as the parameter of the top-level folder; the top-level folder will not be skipped, | |
only the specified subfolders. If you want the whole top-level folder skipped, the value | |
should be false. | |
skip_folder_json_template: | |
{"Folders : | |
{ | |
"Top Level Folder 1": false, | |
"Only Skip Second Level Folders" : [ "Sub Folder 1", "Sub Folder 2" ], | |
"Only One Subfolder" : ['Sub Folder 1" ], | |
"Whole Folder" : false | |
} | |
} | |
''' | |
import os | |
import sys | |
import json | |
import re | |
import shutil | |
if (len(sys.argv) < 3): | |
print('You need to provide a destination and source folder') | |
exit() | |
regex_hidden_folder = '^\..*' | |
folder_to_copy_from = sys.argv[1] | |
folder_to_copy_to = sys.argv[2] | |
def true_false(): | |
while True: | |
prompt = 'Make sure ' + folder_to_copy_to + ' is empty, otherwise it will fail if there are folders with the same name. To continue, type "Yes" > ' | |
answer = input(prompt).lower() | |
if answer == 'yes': | |
return True | |
else: | |
return False | |
if not true_false(): | |
exit() | |
def make_destination_folder(destination, source, folder_count): | |
os.makedirs(destination + '/' + source + '-' + str(folder_count) ) | |
def copy_folder(source): | |
copy_from = folder_to_copy_from + '/' + source | |
folder_count = 0 | |
file_count = 0 | |
for root, dirs, files in os.walk(copy_from): | |
for f in files: | |
# Hidden files | |
if f[0] == '.': | |
continue | |
# If not audio files that can be played in most cars | |
if f[-3:] != 'mp3' and f[-3:] != 'm4a': | |
continue | |
if source in folders_with_ignored_subfolder.keys(): | |
# Get the folder of the file we're working in | |
current_folder = root.split(source+'/')[1] | |
if current_folder in folders_with_ignored_subfolder[source]: | |
continue | |
#If we're just starting out, we need to create our destination folder | |
if file_count == 0: | |
folder_count += 1 | |
make_destination_folder(folder_to_copy_to, source, folder_count) | |
# My car only recognizes 255 files in a folder, so we have to start new folders after we've reached the limit | |
if file_count == 255: | |
folder_count += 1 | |
make_destination_folder(folder_to_copy_to, source, folder_count) | |
file_count = 0 | |
file_count += 1 | |
old_path = root + '/' + f | |
new_path = folder_to_copy_to + '/' + source + '-' + str(folder_count) + '/' + f | |
shutil.copy2(old_path,new_path) | |
if ( len(sys.argv) == 4): | |
folders_to_ignore = sys.argv[3] | |
else: | |
folders_to_ignore = False | |
if not (os.path.isdir(folder_to_copy_from) and os.path.isdir(folder_to_copy_to) ): | |
print('Please check your source and destination folders to make sure they exist.') | |
exit() | |
if folders_to_ignore: | |
if os.path.isfile(folders_to_ignore): | |
with open(folders_to_ignore, 'r') as json_file: | |
folder_list = json.load(json_file)['Folders'] | |
folders_to_ignore = [] | |
folders_with_ignored_subfolder = {} | |
for folder, has_subfolder in folder_list.items(): | |
if not has_subfolder: | |
folders_to_ignore.append(folder) | |
else: | |
folders_with_ignored_subfolder[folder] = [] | |
for subfolder in has_subfolder: | |
folders_with_ignored_subfolder[folder].append(subfolder) | |
folders_to_copy = os.listdir(folder_to_copy_from) | |
for folder in folders_to_copy: | |
if not folders_to_ignore: | |
if not re.match(regex_hidden_folder, folder): | |
copy_folder(folder) | |
else: | |
# If we need to ignore the folder, or it's a system folder | |
if (folder in folders_to_ignore or re.match(regex_hidden_folder, folder) ): | |
continue | |
else: | |
copy_folder(folder) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment