Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- """This will take a folder and ffmpeg copy them to whatever directory as whatever extension, maintaining the folder heiarchy. Choose the same input and output folder to have converted files be in the same spot as old ones. You'll need to delete the source files manually if you want to do that because I didn't code that in."""
- """Symbols [? :] will be replaced or removed from file/folder names beacuase ntfs is dumb :/"""
- """Usage: copy_them.py input_folder "input exts" output_ext output_folder [fcdrm]"""
- """Option f: overwrite files that exist.
- Option c: try to use ffmpeg -c copy. If this fails then it will create an empty file of the same name and not tell you there was a problem becuase I don't want to fix that right now.
- Option d: enable debug output"""
- "I know this is a bit of a mess, but it's worked well enough for me lol. I might tinker with this more later when I feel like it."
- import os
- import sys
- import subprocess
- dbg = False
- def help():
- print("""Usage: script.py input-folder ["input exts"] output-ext output-folder [options])
- Options:
- -f force Overwrite files if they exist. Inserts \"-y\" into ffmpeg command"
- -c copy Use ffmpeg -c copy option to copy streams instead of reencoding.
- This inserts "-c -copy -strict experimental" into ffmpeg command.
- "-strict experimental" enables experimental options like inserting opus audio into mp4 containers so that won't cause an error.")
- This will override the "standard" option.
- -s standard Adds the arguments "-c:v libx264 -profile:v high -vf format=yuv420p -c:a aac -ac 2" So that the media will play on my PS3 :D
- Do not use with -copy
- -rm remove Remove source files if conversion seems successful. Success is determined by wether the output file is empty (0 bytes in size) using the "du" command.
- -d debug Enable debug output, showing the command, stdout and stderr for each file operated on.
- -b banner Enable banner with ffmpeg configuration information. By default this information is omitted.
- -l log Generate log file in the current directory.
- """)
- exit()
- def iferr(stderr):
- if not stderr == "": return f"\n{stderr}"
- return ""
- def mkdir_recursive(path):
- arr = path.split("/")
- for i in range(len(arr)):
- try:
- tmp = "/".join(arr[0:i])
- if tmp[-1] != "/": tmp = tmp + "/"
- #print(tmp)
- os.mkdir(tmp)
- except:
- continue
- def main(in_dir, in_exts, out_ext, out_dir, options):
- global dbg
- in_exts = in_exts.split(" ")
- out_dir = out_dir + "/" if out_dir[-1] != "/" else out_dir
- in_dir = in_dir + "/" if in_dir[-1] != "/" else in_dir
- out_ext = out_ext.split(".")[-1]
- walk = list(os.walk(in_dir))
- walk.sort()
- base_dir = in_dir.split("/")[-1] if in_dir[-1] != "/" else in_dir.split("/")[-2]+"/"
- current_file = 0
- total = 0
- existed = 0
- more_args = ""
- banner = " -hide_banner"
- logging = False
- remove = False
- for i in options:
- if "force" in i or "f" in i: more_args += "-y "
- else: more_args += "-n "
- if "debug" in i or "d" in i: dbg = True
- if "delete" in i or "rm" in i: remove = True
- if "copy" in i or "c" in i: more_args += "-c copy -strict experimental "
- if "banner" in i or "b" in i: banner = ""
- if "log" in i or "l" in i: logging = True
- if "standard" in i or "s" in i: more_args += "-c:v libx264 -profile:v high -vf format=yuv420p -c:a aac -ac 2"
- #if "st" in i: more_args += " -acodec mp3 -vcodec libx264"
- if logging:log = open("log.txt","w")
- for i in walk:
- for j in i[2]:
- if j.split(".")[-1].strip() in in_exts:
- total+=1
- for folder in walk:
- in_path = folder[0]+"/"
- if in_path == ".//": in_path = "./"
- #Replace a few symbols that commonly fuck with ntfs, cases I had to deal with. Same with filenames
- rel_path = in_path.split(base_dir)[1].replace('?','').replace(':', ',')
- if rel_path == "/":
- rel_path = ""
- #if not toggle_base_dir:
- #full_path = f"{out_dir}{base_dir}{rel_path}"
- #else:
- full_path = f"{out_dir}{rel_path}"
- files = [i for i in folder[2] if i.split(".")[-1].strip() in in_exts]
- files.sort()
- for file in files:
- newfile = file.replace('?','').replace(':', ',')
- #os.system("clear")
- current_file += 1
- print(f"""[{current_file}/{total}] Processing "{full_path}{file.replace(file.split(".")[-1], out_ext)}" """)
- #try to create the folder heiarchy from the original output so ffmpeg will work
- #ffmpeg really should be able to make whatever folders are in the output file path.
- mkdir_recursive(full_path)
- #REMOVE -c copy TO RE-ENCODE FOR SMALLER FILESIZE derp
- command = f"""ffmpeg{banner} -nostats -i "{in_path}{file}" {more_args} "{full_path}{".".join(newfile.split(".")[0:-1])}.{out_ext}" """
- proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout = proc.stderr.decode("utf-8")
- stderr = proc.stderr.decode("utf-8")
- if remove and not "cannot edit existing files in-place" in stdout:
- size = subprocess.check_output(["du", f"{in_path}{file}"]).decode("utf-8").split("\t")[0]
- if not size == 0: subprocess.run(["rm", f"{in_path}{file}"])
- if stdout == "":print(stderr)
- if "exist" in stdout and not "-y" in more_args:print("[Error] File already exists");existed+=1
- if "cannot edit existing files in-place" in stdout: print("[Error] Source and output file are the same. Skipping...")
- #else:print("Done")
- if dbg:print(f"\n{command}\n\n{stdout}")
- if logging:log.write(f"[{current_file}/{total}] {command}\n{stdout}{iferr(stderr)}\n")
- if existed != 0:print(f"{existed} files already existed")
- if logging: log.close()
- if __name__ == "__main__":
- a = sys.argv
- if "--help" in a[1] or ("-h" in a[1] and len(a[1]) == 2):
- help()
- try:
- main(a[1], a[2], a[3], a[4], a[5:])
- except IndexError:
- print("Malformed arguments list. At least 5 arguments are required.\nFor help type ./script -h or ./script --help.")
- print(a)
Add Comment
Please, Sign In to add comment