Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- """shuffle, a script to shuffle the names of music files.
- Description:
- Shuffle renames all the files in a given directory so that they appear in
- a random order on an MP3 player which lacks a shuffle feature. This is done
- by generating a sequence of numbers, randomly assigning those numbers
- to the files and renaming those files to begin with prefix strings based
- on those numbers. Files which already have prefixes of the sort Shuffle
- might generate have their existing prefixes recomputed.
- Author:
- Daniel Neville, creamygoat@gmail.com
- Copyright:
- None
- Licence:
- Public domain
- """
- #-------------------------------------------------------------------------------
- import sys
- import os
- import re
- import random
- from os.path import join as pj
- #-------------------------------------------------------------------------------
- def main(args):
- rc = 0
- do_clean = False
- cmd_name = args[0]
- margs = args[1:]
- if len(margs) >= 1 and "--help" in margs:
- print("Usage: {} [--clean] [--help] path".format(cmd_name))
- return 0
- s = "--clean"
- while s in margs:
- margs.remove(s)
- do_clean = True
- if len(margs) > 1:
- print("{}: Too many arguments.".format(cmd_name))
- return 1
- if len(margs) < 1:
- print("{}: A directory path must be supplied.".format(cmd_name))
- return 1
- path = margs[0] if len(margs) >= 1 else "."
- if os.path.exists(path):
- if os.path.isdir(path):
- if not os.access(path, os.R_OK | os.W_OK | os.X_OK):
- print("{}: \"{}\" lacks full permissions.".format(cmd_name, path))
- return 2
- else:
- print("{}: \"{}\" is not a directory.".format(cmd_name, path))
- return 2
- else:
- print("{}: The path \"{}\" does not exist.".format(cmd_name, path))
- return 2
- # Build a list of file to be shiffled and sequence numbers to be avoided
- # because they may contribute to renaming collisions.
- files = []
- reserved_nums = []
- seq_pat = re.compile("^_\d+_")
- for f in os.listdir(path):
- do_shuffle = False
- if os.path.isfile(pj(path, f)):
- if len(f) > 0 and f[0] != '.':
- do_shuffle = True
- if do_shuffle:
- files.append(f)
- else:
- m = seq_pat.match(f)
- if m:
- s = f[m.span()[0] : m.span()[1]]
- i = int(s[1:-1])
- reserved_nums.append(i)
- # Exit if there is not even one file to shuffle.
- n = len(files)
- if n < 1:
- return rc
- # Build a list of safe numbers, one for each file to be shuffled and
- # one for use in a temporary filename in case a swap is needed. Take
- # note of the maximum field width needed.
- seq_start = 1
- nums = []
- x = seq_start
- for i in range(n + 1):
- while x in reserved_nums:
- x += 1
- nums.append(x)
- x += 1
- w = len(str(x - 1))
- temp_num = nums.pop()
- random.shuffle(nums)
- # Build a list of new filenames with sequence numbers prepended or
- # re-written.
- nfiles = []
- for i, f in enumerate(files):
- s = "_{:0>{}}_".format(nums[i], w)
- m = seq_pat.match(f)
- if do_clean:
- if m:
- b = f[m.span()[1]:]
- if len(b) < 1 or b[0] == '.':
- new_f = f
- elif os.path.exists(pj(path, b)) or b in files or b in nfiles:
- new_f = f
- else:
- new_f = b
- else:
- new_f = f
- else:
- new_f = s + f[m.span()[1]:] if m else s + f
- nfiles.append(new_f)
- temp_prefix = "_{:0>{}}_".format(temp_num, w)
- # Rename the files to be shuffled, taking care to swap files if necessary.
- # Even if a name swap is interrupted, the files names must be left in a
- # valid state for re-shuffling and their extensions must be preserved.
- # The list of filenames is kept up-to-date.
- i = 0
- while i < n:
- f = files[i]
- nf = nfiles[i]
- if f != nf:
- old_pf = pj(path, f)
- new_pf = pj(path, nf)
- if nf in files:
- x = files.index(nf)
- temp_pf = pj(path, temp_prefix + nf[len(temp_prefix):])
- os.rename(new_pf, temp_pf)
- os.rename(old_pf, new_pf)
- os.rename(temp_pf, old_pf)
- files[i], files[x] = files[x], files[i]
- else:
- os.rename(old_pf, new_pf)
- files[i] = nf
- i += 1
- return rc
- #-------------------------------------------------------------------------------
- if __name__ == "__main__":
- exit(main(sys.argv))
- #-------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement