diff --git a/kodi-nfo-feeder.py b/kodi-nfo-feeder.py index 0c70148..6276426 100644 --- a/kodi-nfo-feeder.py +++ b/kodi-nfo-feeder.py @@ -169,6 +169,146 @@ def setup_watch( return inotify +def generate_nfo( + title: str, + raw_file_name: str) -> lxml.builder.ElementMaker: + + season_ep_str = raw_file_name.split(" - ")[0] + + data = lxml.builder.ElementMaker() + ep_details_tag = data.episodedetails + title_tag = data.title + id_tag = data.id + nfo_data = ep_details_tag( + title_tag(title), + id_tag(f"{season_ep_str} - {title}") + ) + return nfo_data + + +def get_basic_cleaned_title( + section_name: str, + config_obj: configparser.ConfigParser(), + dirty_title: str) -> str: + + regex_search_pattern = config_obj.get(section_name, "title_regex_search") + regex_replace_pattern = config_obj.get(section_name, "title_regex_replace") + if regex_search_pattern: + log.debug(regex_search_pattern) + log.debug(f"Doing basic title cleaning ...") + pattern = re.compile(regex_search_pattern) + clean_title = re.sub(pattern, regex_replace_pattern, dirty_title) + log.debug(f"""Title's now "{clean_title}".""") + quit() + return clean_title + else: + return dirty_title + + +def get_season_and_episode( + section_name: str, + config_obj: configparser.ConfigParser(), + raw_file_name: str) -> dict: + + file_name_ext_split = os.path.splitext(raw_file_name) + season_ep_str = file_name_ext_split[0].split(" - ", 1) + ext = file_name_ext_split[1] + season_episode = re.split("[S|E]", season_ep_str[0]) + season = f"Season {season_episode[1]}" + title = season_ep_str[1] + basic_cleaned_title = get_basic_cleaned_title(section_name, config_obj, title) + + got_season_and_episode = { + "season_str": season, + "title_str": basic_cleaned_title, + "season_ep_list": season_ep_str, + "ext": ext + } + log.debug(f"""Identified {got_season_and_episode["season_str"]}, """ + f"""title "{got_season_and_episode["title_str"]}" """ + f"and episode object {season_ep_str} " + f"with extension '{ext}'.") + return got_season_and_episode + + +def get_target_file_list( + target_dir: str) -> list: + + log.debug(f"Generating list of files in '{target_dir}' ...") + onlyfiles = [f for f in os.listdir(target_dir) if os.path.isfile(os.path.join(target_dir, f))] + filtered_files = [f for f in onlyfiles if not f.endswith(tuple(ignored_target_file_exts))] + log.debug(f"Files in '{target_dir}' filtered for extensions we're ignoring " + f"{ignored_target_file_exts}: {filtered_files}") + return filtered_files + + +def move_file_to_target_dir( + section_name: str, + config_obj: configparser.ConfigParser(), + raw_file_name: str, + season_ep_str: dict) -> str: + + this_watch_dir = config_obj.get(section_name, "watch_dir") + source_abs_path = os.path.join(this_watch_dir, raw_file_name) + + target_dir = config_obj.get(section_name, "output_dir") + target_file_list = get_target_file_list(target_dir) + + target_file_name = season_ep_str["season_ep_list"][0] + target_ext = season_ep_str["ext"] + target_file_name_plus_ext = f"{target_file_name}{target_ext}" + + if target_file_name_plus_ext in target_file_list: + log.debug(f"File name already exists in target dir, incrementing counter ...") + episode_minus_counter = target_file_name[:-2] + counter = target_file_name[-2:] + counter_length = len(counter) + counter_stripped = int(counter.lstrip("0")) + counter_stripped += 1 + target_file_name = f"{episode_minus_counter}{str(counter_stripped).zfill(counter_length)}" + target_abs_path = os.path.join(target_dir, f"{target_file_name}{target_ext}") + + try: + log.debug(f"Moving '{source_abs_path}' to '{target_abs_path}' ...") + # shutil.move(source_abs_path, target_abs_path) + except OSError as ose: + log.error(f"Failed moving file with an OSError:\n" + f"{ose}\n" + f"Continuing file watch ...") + return "" + else: + return target_file_name + + +def write_nfo_to_disk( + nfo_data: lxml.builder.ElementMaker, + target_file_name: str, + output_dir_name: str) -> bool: + + target_dir = output_dir_name + target_nfo_name = f"{target_file_name}.nfo" + target_abs_path = os.path.join(target_dir, target_nfo_name) + + nfo_str = lxml.etree.tostring( + nfo_data, + pretty_print=True, + xml_declaration=True, + standalone=True, + encoding="UTF-8") + try: + with open(target_abs_path, 'wb') as nfo_file: + log.debug(f"Writing NFO data to '{target_abs_path}':\n" + f"""{nfo_str.decode("UTF-8")}""") + nfo_file.write(nfo_str) + except OSError as ose: + log.error(f"Failed writing NFO file '{target_abs_path}' with an OSError:\n" + f"{ose}\n" + f"Continuing file watch ...") + return False + else: + return True + + if __name__ == '__main__': validate_default_section(config) if config_has_valid_section(config): diff --git a/requirements.in b/requirements.in index acb0c11..331fe2c 100644 --- a/requirements.in +++ b/requirements.in @@ -1,3 +1,4 @@ rich inflect -inotify_simple \ No newline at end of file +inotify_simple +lxml \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fa8ad65..fabb7ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,8 @@ inflect==5.4.0 # via -r requirements.in inotify-simple==1.3.5 # via -r requirements.in +lxml==4.8.0 + # via -r requirements.in pygments==2.11.2 # via rich rich==12.0.0