def get_activation_bytes(checksum: str) -> Optional[str]: if not is_rcrack_enabled(): return None logging.debug(f"Getting activation on {checksum}") has_rtc = len([x for x in listdir(RCRACK_DIR) if x.endswith(".rtc")]) > 0 rcrack_command = ["./rcrack", "." if has_rtc else "*.rt", "-h", checksum] rcrack_process = Popen(rcrack_command, stdout=PIPE, stderr=PIPE, cwd=RCRACK_DIR) rcrack_result = rcrack_process.communicate()[0] if isinstance(rcrack_result, bytes): rcrack_result = rcrack_result.decode("utf-8") rcrack_result = [ x.strip() for x in rcrack_result.split(linesep) if len(x.strip()) > 0 ][-1] rcrack_result = rcrack_result[re_search(r"hex:", rcrack_result).end( ):].strip() logging.debug(f"Activation for {checksum} is {rcrack_result}") return rcrack_result
def prepare_file(self, selected_file: str) -> str: new_file = os.path.join(self.get_temp_dir(), str(uuid4())) logging.debug( f"Starting download of {selected_file} from {self._host}") self._oc.get_file(selected_file, new_file) logging.debug( f"Finished download of {selected_file} from {self._host}") return new_file
def run(self) -> None: logging.debug( f"Starting interruptable thread with {self.__time_out}s as timeout" ) if not hasattr(self, "__run"): self.__run = AtomicType(init_value=True) while self.__run.get(): run_result = self.one_run() if (run_result is None) or (not run_result): time.sleep(self.__time_out)
def __mkdir_recursive(self, path_parts: List[str]) -> Optional[str]: logging.debug( f"Trying to create directory {os.path.join(*path_parts)}") for i in range(1, len(path_parts) + 1, 1): try: self._oc.mkdir(os.path.join(*path_parts[:i])) except owncloud.owncloud.HTTPResponseError as e: if e.status_code != 405: return None return os.path.join(*path_parts)
def simple_conversion(audiobook: AudioBook, target_path: str, output_format: str = "mp3"): try: logging.info(f"Converting {audiobook}") temporary_out_name = f"{target_path}.conv" ffmpeg_result, (stdout, stderr) = ffmpeg( input_file=audiobook.get_input_file(), output_file=temporary_out_name, quality_level=2, output_format=output_format, activation_bytes=audiobook.get_activation_bytes()) logging.info(f"Job for book {audiobook} exited good: {ffmpeg_result}") if ffmpeg_result: if audiobook.get_cover() is not None: logging.debug( f"Adding cover to {audiobook} -> {audiobook.get_cover()}") add_cover(temporary_out_name, audiobook.get_cover()) rename(temporary_out_name, target_path) return target_path else: error_name = f"/tmp/error_{uuid.uuid4()}.json" with open(error_name, "w") as f_err: if isinstance(stdout, bytes): stdout = stdout.decode("utf-8") else: stdout = str(stdout) if isinstance(stderr, bytes): stderr = stderr.decode("utf-8") else: stderr = str(stderr) json.dump({"stdout": stdout, "stderr": stderr}, f_err) logging.notify("FFMPEG had an error during conversion", extra={ "notification_title": "FFMPEG-ERROR", "attach": error_name }) remove(temporary_out_name) remove(error_name) except: pass return None
def one_run(self) -> bool: all_files = self.get_file_list(current_element=self._watch_folder, recursive=self._recursive) all_files = [x for x in all_files if x.lower().endswith(".aax") or x.lower().endswith(".mp3") or x.lower().endswith(".aaxc")] if len(all_files) <= 0: return False work_file = self.prepare_file(selected_file=all_files[0]) audiobook = get_audiobook_by_file(work_file) if audiobook is None: self.broken_input(selected_file=all_files[0], work_file=work_file) logging.notify(f"Audiobook conversion of {os.path.basename(all_files[0])} failed. " f"Has been awarded 'broken' :(") return True if self.audiobook_already_exists(audiobook=audiobook, target_folder=self._target_folder) is None: logging.info(f"Audiobook {audiobook} already exists. Deleting and carrying on") self.cleanup(audiobook=audiobook, final_file=None, selected_file=all_files[0]) return True cover = audiobook.get_cover() _extra = {"notification_title": "Conversion started"} if cover is not None: _extra["attach"] = cover logging.notify(message=f"Conversion of {audiobook} initiated", extra=_extra) try: _ = audiobook.get_activation_bytes(create_if_missing=True) except TypeError: pass converted_file = simple_conversion(audiobook=audiobook, target_path=f"{work_file}.mp3") logging.debug(message=f"Conversion of {audiobook} finished. Saved to \"{converted_file}\"") if not self.finalize_file(final_file=converted_file, audiobook=audiobook, target_folder=self._target_folder): logging.info(f"Finalization of {audiobook} failed") logging.notify(message=f"Conversion of {audiobook} failed", extra={"notification_title": "Conversion failed"}) self.stale_input(selected_input=all_files[0]) else: logging.info(f"Finalization of {audiobook} succeeded. Going to clean up") logging.success(message=f"Conversion and upload of {audiobook} secceded", extra={"notification_title": "Conversion successful"}) self.cleanup(audiobook=audiobook, final_file=converted_file, selected_file=all_files[0]) return True
def ffmpeg(input_file: str, output_file: str, activation_bytes: Optional[str] = None, quality_level: int = 2, output_format: str = None) -> Tuple[bool, Tuple[AnyStr, AnyStr]]: if not isfile(input_file) or isfile(output_file): return False, ("", "") ffmpeg_process = [FFMPEG_COMMAND] if activation_bytes is not None: ffmpeg_process += ["-activation_bytes", activation_bytes] ffmpeg_process += ["-i", input_file] ffmpeg_process = ffmpeg_process + ["-q:a", quality_level, "-vn"] if isinstance(output_format, str): ffmpeg_process = ffmpeg_process + ["-f", output_format] ffmpeg_process = ffmpeg_process + [output_file] logging.debug( f"Executing ffmpeg process {' '.join(str(x) for x in ffmpeg_process)}") ffmpeg_process = Popen([str(x) for x in ffmpeg_process], stdout=PIPE, stderr=PIPE) stdout, stderr = ffmpeg_process.communicate() return ffmpeg_process.returncode == 0, (stdout, stderr)
def generate_activation_bytes(self) -> str: logging.debug(f"Generating activation bytes for {self}") self.set_activation_bytes(get_activation_bytes(self.get_checksum())) return self.get_activation_bytes()