Skip to content

Commit

Permalink
existing renamer
Browse files Browse the repository at this point in the history
  • Loading branch information
hollanbm committed Apr 28, 2024
1 parent 4b7d278 commit 133a085
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 24 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ black = "^24.4.2"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
build-backend = "poetry.core.masonry.api"
7 changes: 5 additions & 2 deletions src/config/schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from schema import Use, And, Optional
from schema import And, Optional, Use

CONFIG_SCHEMA = {
"sonarr": And(
Expand Down Expand Up @@ -28,7 +28,10 @@
"hourly_job": bool,
Optional("hours_before_air", default=4): int,
},
"tba_renamer": {"enabled": bool, "hourly_job": bool},
"existing_renamer": {
"enabled": bool,
"hourly_job": bool,
},
}
],
),
Expand Down
82 changes: 82 additions & 0 deletions src/existing_renamer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from os import path
from typing import List

from loguru import logger
from pycliarr.api import SonarrCli
from pycliarr.api.base_api import json_data


class ExistingRenamer:
def __init__(self, name, url, api_key):
self.name = name
self.sonarr_cli = SonarrCli(url, api_key)

def scan(self):
with logger.contextualize(instance=self.name):
logger.info("Starting Existing Renamer")

series = self.sonarr_cli.get_serie()

if series is []:
logger.error("Sonarr returned empty series list")
else:
logger.debug("Retrieved series list")
for show in sorted(series, key=lambda s: s.title):
with logger.contextualize(series=show.title):
episode_list = self.sonarr_cli.get_episode(show.id)

if episode_list is []:
logger.error("Error fetching episode list")
continue
else:
logger.debug("Retrieved episode list")
# generic dict, used to batch up files for renaming, as well as a user friendly output for logging
files_to_rename: dict = {"episode_ids": [], "log_msg": []}

for episode in self.__aired_episode_list_with_titles(episode_list):
file_info = self.sonarr_cli.get_episode_file(
episode_id=episode["id"]
)
season_episode_number = f'S{episode['seasonNumber']:02}E{episode['episodeNumber']:02}'

# file on disk, doesn't contain episode name
if episode["title"] not in path.basename(file_info["path"]):
files_to_rename["episode_ids"].append(file_info["id"])
files_to_rename["log_msg"].append(season_episode_number)
logger.info(
f"{season_episode_number} filename does not contain episode name"
)
logger.info(f"{season_episode_number} Queing for rename")

# TODO: Submit PR to original repo updating rename payload for episode rename method to work
self.sonarr_cli._sendCommand(
{
"name": "RenameFiles",
"files": files_to_rename["episode_ids"],
"seriesId": show.id,
}
)

logger.info(f'Renaming {', '.join(files_to_rename["log_msg"])}')
logger.info("Finished Existing Renamer")

def __aired_episode_list_with_titles(self, episode_list: List[json_data]):
"""
Filters episode list, removing all episodes that have not aired
Parameters:
episode_list (List[json_data]):The episode list to be filered.
Returns:
List[json_data]
"""
return sorted(
[
e
for e in episode_list
if e.get("seasonNumber") > 0
and e.get("title") != "TBA"
and e.get("hasFile")
],
key=lambda e: e.get("episodeNumber"),
)
46 changes: 36 additions & 10 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from series_scanner import SeriesScanner
from config.schema import CONFIG_SCHEMA
from loguru import logger
from os import path
from pycliarr.api import CliServerError
from pyconfigparser import configparser, ConfigError, ConfigFileNotFoundError
from sys import stdout
from time import sleep

import schedule
from time import sleep
from sys import stdout
from config.schema import CONFIG_SCHEMA
from existing_renamer import ExistingRenamer
from loguru import logger
from pycliarr.api import CliServerError
from pyconfigparser import ConfigError, ConfigFileNotFoundError, configparser
from series_scanner import SeriesScanner


def job(sonarr_config):
def series_scanner_job(sonarr_config):
try:
SeriesScanner(
name=sonarr_config.name,
Expand All @@ -23,11 +24,34 @@ def job(sonarr_config):


def schedule_series_scanner(sonarr_config):
job(sonarr_config)
series_scanner_job(sonarr_config)

if sonarr_config.series_scanner.hourly_job:
# Add a random delay of +-5 minutes between jobs
schedule.every(55).to(65).minutes.do(job, sonarr_config=sonarr_config)
schedule.every(55).to(65).minutes.do(
series_scanner_job, sonarr_config=sonarr_config
)


def existing_renamer_job(sonarr_config):
try:
ExistingRenamer(
name=sonarr_config.name,
url=sonarr_config.url,
api_key=sonarr_config.api_key,
).scan()
except CliServerError as exc:
logger.error(exc)


def schedule_existing_renamer(sonarr_config):
existing_renamer_job(sonarr_config)

if sonarr_config.existing_renamer.hourly_job:
# Add a random delay of +-5 minutes between jobs
schedule.every(55).to(65).minutes.do(
existing_renamer_job, sonarr_config=sonarr_config
)


def loguru_config():
Expand Down Expand Up @@ -60,6 +84,8 @@ def loguru_config():
for sonarr_config in config.sonarr:
if sonarr_config.series_scanner.enabled:
schedule_series_scanner(sonarr_config)
if sonarr_config.existing_renamer.enabled:
schedule_existing_renamer(sonarr_config)

if schedule.get_jobs():
while True:
Expand Down
20 changes: 9 additions & 11 deletions src/series_scanner.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
from datetime import datetime, timezone

from dateutil import parser
from pycliarr.api import SonarrCli
from loguru import logger
from pycliarr.api import SonarrCli


class SeriesScanner:
def __init__(self, name, url, api_key, hours_before_air):
self.name = name
self.url = url
self.api_key = api_key
self.sonarr_cli = SonarrCli(url, api_key)
self.hours_before_air = min(hours_before_air, 12)

def scan(self):
with logger.contextualize(instance=self.name):
logger.info("Starting Series Scan")

sonarr_cli = SonarrCli(self.url, self.api_key)

series = sonarr_cli.get_serie()
series = self.sonarr_cli.get_serie()

if series is []:
logger.error("Sonarr returned empty series list")
Expand All @@ -27,7 +25,7 @@ def scan(self):
for show in sorted(series, key=lambda s: s.title):
with logger.contextualize(series=show.title):
if show.status.lower() == "continuing":
episode_list = sonarr_cli.get_episode(show.id)
episode_list = self.sonarr_cli.get_episode(show.id)

if episode_list is []:
logger.error("Error fetching episode list")
Expand All @@ -44,14 +42,14 @@ def scan(self):
logger.info(
f"Found TBA episode, airing within the next {self.hours_before_air} hours"
)
sonarr_cli.refresh_serie(show.id)
self.sonarr_cli.refresh_serie(show.id)
logger.info("Series rescan triggered")
break
elif self.__has_episode_already_aired(episode_air_date_utc):
logger.info(
"Found previously aired episode with TBA title"
)
sonarr_cli.refresh_serie(show.id)
self.sonarr_cli.refresh_serie(show.id)
logger.info("Series rescan triggered")
break
logger.debug("Finished Processing")
Expand All @@ -64,10 +62,10 @@ def __filter_episode_list(self, episode_list):
Filters episode list, removing all episodes that have a title, or no airDate
Parameters:
episode_list (List[SonarrSerieItem]):The episode list to be filered.
episode_list (List[json_data]):The episode list to be filered.
Returns:
List[SonarrSerieItem]
List[json_data]
"""
return [
e
Expand Down

0 comments on commit 133a085

Please sign in to comment.