def get_files(parent: str) -> Union[list, List[str]]: """Get the members of the given folder.""" try: files: List[str] = Str(parent).listdir() except OSError as err: if errors.osraise(errors.ENOENT, errors.ENOTDIR, err=err): raise print(err) return [] hidden: bool = x.OPTS.hidden exclude: Set[str] = set(x.OPTS.exclude) only: Set[str] = set(x.OPTS.only) done: Set[str] = set(get_files_from_cache()) use: bool = x.OPTS.use_cache for member in files.copy(): if any([ Str(member).isdir(), all([not hidden, Str(member).ishidden()]), all([ bool(exclude), any(Str(member).endsext(_) for _ in exclude) ]), all([ bool(only), not any(Str(member).endsext(_) for _ in only) ]), all([use, Str(member).sha256() in done]), ]): files.remove(member) return files
def save_to_cache_as_done(file: str) -> None: """Save the hash of the given file to the cache.""" try: with open(consts.FILE_CACHE, "a", encoding=U8, errors=XML) as cache: cache.write(Str(file).sha256() + "\n") except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise
def attrs(self) -> int: """Retrieve file attributes from the given string.""" try: return os.stat(self.abs()).st_file_attributes except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise return int(False)
def get_files_from_cache() -> Union[list, List[str]]: """Get hashes from the cache.""" try: with open(consts.FILE_CACHE, "r", encoding=U8) as cache: return [hash_.strip() for hash_ in cache.readlines()] except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise return []
def fcleaner(*containers: Dict[str, str]) -> None: """Delete files that to be deleted on exit.""" for container in containers: for output in container.values(): try: os.remove(Str(output).abs()) except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise continue
def dcleaner(*containers: List[str]) -> None: # avsub: N2204 """Delete folders that to be deleted on exit.""" for container in containers: for folder in container: try: if folder is not None: os.rmdir(Str(folder).abs()) except OSError as err: if errors.osraise(errors.ENOENT, errors.ENOTEMPTY, err=err): raise continue
def create_startup_program() -> bool: """Create a startup program to auto check for updates.""" if Str(consts.FILE_STARTUP).isfile() and not x.OPTS.fix_startup: return True try: with open(consts.FILE_STARTUP, "w", encoding=U8) as bat: bat.write("avsub\n" "pause\n") except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise return False return True
def logger() -> int: """Print results to the terminal and then save them to a file.""" log: List[str] = [] status: int = 0 for member in x.SUCCEEDED: msg: Template = Template("[+] Job completed: '$member'") print(msg.substitute(member=Str(member).base())) log.append(msg.substitute(member=Str(member).abs())) for member in x.DEL_ON_EXIT: if member in x.FATAL_FFMPEG: # avsub: C2203 continue msg = Template("[-] Not completed: '$member'") print(msg.substitute(member=Str(member).base())) log.append(msg.substitute(member=Str(member).abs())) status = 2 for member in x.NOT_PROCESSED: msg = Template("[ ] Not processed: '$member'") print(msg.substitute(member=Str(member).base())) log.append(msg.substitute(member=Str(member).abs())) status = 2 for member in x.FATAL_FFMPEG: msg = Template("[F] Fatal, FFmpeg: '$member'") print(msg.substitute(member=Str(member).base())) log.append(msg.substitute(member=Str(member).abs())) status = 3 if x.OPTS.log: try: with open(x.LOG_FILE, "a", encoding=U8, errors=XML) as file: date_format: str = "%m/%d/%Y - %H:%M:%S" date: str = datetime.now().strftime(date_format) line: str = Str("=").line(col=len(date)) file.write(f"{line}\n{date}\n{line}\n") log.reverse() # avsub: C2200 for message in log: file.write(message + "\n") except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise print("[!] Logging error:", err) else: print("[*] Results saved:", f"'{file.name}'") return status
def main() -> None: """Main function.""" SigHandler(consts.SIGNALS).capture(stop) checker() fff: ffmpeg.FFmpeg = ffmpeg.FFmpeg() fff.build() # Start creating the ultimate FFmpeg command try: x.THE_TEMP = Str(x.OPTS.temp).abs() x.OUTS = Str(x.THE_TEMP).join("Outs") # avsub: F2400 dmaker(x.THE_TEMP, x.OUTS, consts.DIR_CONFS, consts.DIR_LOGS) x.A_TEMP = tempfile.mkdtemp(prefix="avsub-", dir=x.OUTS) x.DEL_ON_EXIT_TEMP_FOLDER.append(x.A_TEMP) except OSError as err: # avsub: F2210,F2220 if errors.osraise(errors.EEXIST, errors.ENOENT, err=err): raise print(err) print("[F] Required folders could not be created") sys.exit(3) else: x.LOG_FILE = Str(consts.DIR_LOGS).join(f"{x.A_TEMP}.log") if OS.nt and create_startup_program(): # avsub: N2400 reg: registry.Registry = registry.Registry() reg.set() del reg # MANUAL OPERATION? if Str(x.OPTS.input).isfile(): files: List[str] = [Str(x.OPTS.input).abs()] # HARDSUB MANUAL OPERATION? if x.OPTS.embed: # Note: New TEMP subtitle to -almost- avoid the escaping nonsense tempsub: str = Str(x.A_TEMP).join(x.A_TEMP) x.DEL_ON_EXIT_TEMP.update({tempsub: tempsub}) try: shutil.copyfile(Str(x.OPTS.embed).abs(), tempsub) except OSError as err: if errors.osraise(errors.ENOENT, err=err): raise print(err) print("[F] Required TEMP subtitle file could not be created") dcleaner(x.DEL_ON_EXIT_TEMP_FOLDER) sys.exit(3) # Add a new level of escaping for TEMP subtitle pathname sub_escaped: str = tempsub.replace("\\", "/").replace(":", "\\\\:") fff.build_hardsub(subpath=sub_escaped) # AUTOMATIC OPERATION? else: print("[*] Getting files...") files = get_files(parent=x.OPTS.input) if not files: print("[-] Exiting, no files to process with current options") dcleaner(x.DEL_ON_EXIT_TEMP_FOLDER) sys.exit(2) print("[*] Getting ready to start...") mark_as_not_processed(parent=x.A_TEMP, files=files) x.FULL_CLEAN_AFTER_STOP = True ffmpeg.execute(fff.cmd, files=files)