summaryrefslogtreecommitdiff
path: root/ffmagick/ffmagick.py
diff options
context:
space:
mode:
authorMetroWind <chris.corsair@gmail.com>2025-11-02 21:10:32 -0800
committerMetroWind <chris.corsair@gmail.com>2025-11-02 21:10:32 -0800
commitc9170be038ebdf2afab1b7583e2eabb27000dab9 (patch)
treeb0e7e4547e151511cb7cf1f31a8d8606eb910ba6 /ffmagick/ffmagick.py
parentfbd38acebbced481c0487e15313dabc924da2cb3 (diff)
ffmagick: support processing directories.
Diffstat (limited to 'ffmagick/ffmagick.py')
-rw-r--r--ffmagick/ffmagick.py61
1 files changed, 45 insertions, 16 deletions
diff --git a/ffmagick/ffmagick.py b/ffmagick/ffmagick.py
index 794bb4d..3d28bbe 100644
--- a/ffmagick/ffmagick.py
+++ b/ffmagick/ffmagick.py
@@ -15,8 +15,7 @@ class ProgressBar:
15 15
16 def next(self): 16 def next(self):
17 self.current += 1 17 self.current += 1
18 print("\r{} {}/{}".format(self.text, self.current, self.max), flush=True, 18 print(f"\r{self.text} {self.current}/{self.max}", flush=True, end="")
19 end="")
20 19
21 def finish(self): 20 def finish(self):
22 print(flush=True) 21 print(flush=True)
@@ -47,8 +46,8 @@ class Profile:
47 return cls(p) 46 return cls(p)
48 47
49 def __str__(self): 48 def __str__(self):
50 return "{} ({}): {}\n{}".format(self.name, self.processor.name, 49 return f"{self.name} ({self.processor.name}): {self.desc}\n" \
51 self.desc, self.command) 50 f"{self.command}"
52 51
53def getConfigFiles(): 52def getConfigFiles():
54 files = [] 53 files = []
@@ -140,33 +139,54 @@ def runOnce(config, profile, input_file, output_dir):
140 if not os.path.exists(output_dir): 139 if not os.path.exists(output_dir):
141 os.makedirs(output_dir) 140 os.makedirs(output_dir)
142 if profile.processor == Processor.FFMPEG: 141 if profile.processor == Processor.FFMPEG:
143 cmd = "\"{}\" -y -i \"{}\" {} \"{}\"".format( 142 cmd = f"\"{config.ffmpeg_bin}\" -y -i \"{input_file}\"" \
144 config.ffmpeg_bin, input_file, profile.command, output_file) 143 f" {profile.command} \"{output_file}\""
145 elif profile.processor == Processor.IMAGEMAGICK: 144 elif profile.processor == Processor.IMAGEMAGICK:
146 cmd = "\"{}\" \"{}\" {} \"{}\"".format( 145 cmd = f"\"{config.imagemagick_bin}\" \"{input_file}\""\
147 config.imagemagick_bin, input_file, profile.command, output_file) 146 f" {profile.command} \"{output_file}\""
148 return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 147 return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
149 text=True) 148 text=True)
150 149
151def runAll(config, profile, input_files, output_dir): 150def runAll(config, profile, input_files, output_dir, ignore_error=False):
152 bar = Progress("Processing", max=len(input_files)) 151 bar = Progress("Processing", max=len(input_files))
152 failed = []
153 for f in input_files: 153 for f in input_files:
154 bar.next() 154 bar.next()
155 result = runOnce(config, profile, f, output_dir) 155 result = runOnce(config, profile, f, output_dir)
156 if result.returncode != 0: 156 if result.returncode != 0:
157 failed.append(f)
158 if ignore_error:
159 continue
157 bar.finish() 160 bar.finish()
158 print("ERROR: failed to process {}. Log:\n") 161 print("ERROR: failed to process {}. Log:\n")
159 print(result.stdout) 162 print(result.stdout)
160 return False 163 return failed
161 bar.finish() 164 bar.finish()
162 return True 165 return failed
166
167# Return a list of files found in paths, which is a list of files or
168# directories. For each element in “paths”, if it is a file, add it to the
169# result; if it is a directory, add all the files (not recursively) in it to the
170# result.
171def getFilesFromPaths(paths):
172 files = []
173 for p in paths:
174 if os.path.isdir(p):
175 for entry in os.listdir(p):
176 f = os.path.join(p, entry)
177 if os.path.isfile(f):
178 files.append(f)
179 else:
180 files.append(p)
181 return files
163 182
164def main(): 183def main():
165 import argparse 184 import argparse
166 parser = argparse.ArgumentParser( 185 parser = argparse.ArgumentParser(
167 prog='FFmagick', description='What the program does') 186 prog='FFmagick', description='What the program does')
168 parser.add_argument('files', metavar="FILE", nargs='*', 187 parser.add_argument('files', metavar="FILE", nargs='*',
169 help="File to process") 188 help="File to process. If FILE is a directory, "
189 "all files in it are processed (but not recursively).")
170 parser.add_argument('-p', "--profile", metavar="PROFILE", dest="profile", 190 parser.add_argument('-p', "--profile", metavar="PROFILE", dest="profile",
171 help="Specify the profile to process the files") 191 help="Specify the profile to process the files")
172 parser.add_argument("-l", "--list-profiles", action="store_true", 192 parser.add_argument("-l", "--list-profiles", action="store_true",
@@ -200,11 +220,20 @@ def main():
200 output_dir = None 220 output_dir = None
201 if "output_dir" in args: 221 if "output_dir" in args:
202 output_dir = args.output_dir 222 output_dir = args.output_dir
203 if not runAll(config, config.getProfile(args.profile), args.files,
204 output_dir):
205 return 1
206 223
207 return 0 224 input_files = getFilesFromPaths(args.files)
225 ignore_error = False
226 if len(input_files) > len(args.files):
227 ignore_error = True
228 failed = runAll(config, config.getProfile(args.profile), input_files,
229 output_dir, ignore_error)
230 if failed:
231 print("Failed files:")
232 for f in failed:
233 print(f)
234 return 1
235 else:
236 return 0
208 237
209if __name__ == "__main__": 238if __name__ == "__main__":
210 sys.exit(main()) 239 sys.exit(main())