Move README to README.txt
[ordnung.git] / ordnung.py
blobc550c9467c65809199cc10149f6eb4bb5363cf63
1 # Copyright 2009, Erik Hahn
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 from path import path
17 import fnmatch
18 import os
19 import shutil
20 import sys
22 from optparse import OptionParser, OptionGroup
23 from tag_wrapper import tag
25 ACCEPTEXTS = [".ogg", ".mp3"] # Keep it simple for now
27 def issupportedfile(name):
28 for ext in ACCEPTEXTS:
29 if os.path.splitext(name)[1] == ext:
30 return True
31 return False
34 def mkdir(newdir):
35 if not os.path.isdir(newdir):
36 os.makedirs(newdir)
39 def newpath(file, pattern):
40 # Create the tokens dictionary
41 tokens = {}
42 tags = tag(file)
43 # TODO: add tracknumber, disknumber and possibily compilation
44 for t in ["title", "artist", "album artist", "album", "composer", "genre", "date"]:
45 try:
46 tokens[t] = tags[t]
47 except KeyError:
48 tokens[t] = None
49 # %album artist% is %artist% if nothing can be found in the tags
50 if tokens["album artist"] is None:
51 tokens["album artist"] = tokens["artist"]
53 # Now replace all tokens by their values
54 for i in tokens:
55 repl = "%" + i + "%"
56 if tokens[i] is not None:
57 pattern = pattern.replace(repl, tokens[i][0])
59 # Add the extension and return the new path
60 return pattern + os.path.splitext(file)[1]
63 def safeprint(string):
64 """
65 Print string first trying to normally encode it, sending it to the
66 console in "raw" UTF-8 if it fails.
68 This is a workaround for Windows's broken console
69 """
70 try:
71 print string
72 except UnicodeEncodeError:
73 print string.encode("utf-8")
76 def files_to_move(base_dir, pattern, recursive=False):
77 # Figure out which files to move where
78 basepath = path(base_dir)
79 if recursive:
80 files = basepath.walkfiles()
81 else:
82 files = basepath.files()
84 files_return = []
86 for file in files:
87 if issupportedfile(file):
88 t = [ file, newpath(file, pattern) ]
89 files_return.append(t)
91 return files_return
93 def main():
94 # Pseudo-enum for actions
95 COPY = 0
96 MOVE = 1
97 PREVIEW = 2
99 # Handle arguments
100 usage = "Usage: %prog [options] directory pattern"
101 parser = OptionParser(usage=usage)
102 parser.add_option("-r", "--recursive", action="store_true",
103 dest="recursive", help="also move/copy files from sub-directories", default=False)
105 actions = OptionGroup(parser, "Possible actions")
106 actions.add_option("--preview", "-p", action="store_const",
107 const=PREVIEW, dest="action", help="preview, don't make any changes (default)")
108 actions.add_option("--copy", "-c", action="store_const",
109 const=COPY, dest="action", help="copy files")
110 actions.add_option("--move", "-m", action="store_const",
111 const=MOVE, dest="action", help="move files")
112 parser.add_option_group(actions)
113 (options, args) = parser.parse_args()
115 try:
116 base = args[0]
117 except IndexError:
118 print "You must specify a directory"
119 sys.exit()
121 try:
122 pattern = args[1]
123 except IndexError:
124 print "You must specify a pattern"
125 sys.exit()
127 # Do stuff
128 for i in files_to_move(base_dir=base,
129 pattern=pattern, recursive=options.recursive):
130 if options.action == MOVE:
131 mkdir(os.path.split(i[1])[0])
132 shutil.move(i[0], i[1])
133 elif options.action == COPY:
134 mkdir(os.path.split(i[1])[0])
135 shutil.copy2(i[0], i[1])
136 else:
137 safeprint (i[0] + " --> " + i[1])
140 if __name__ == "__main__":
141 main()