From 66e40ff07704d641b95a148494f7f517a361979b Mon Sep 17 00:00:00 2001 From: Phoenix Date: Thu, 26 Dec 2024 15:02:04 +0800 Subject: [PATCH] Add environment configuration and media processing scripts - Create .env file for environment variables - Implement mediascheduler.py for managing TV shows in Plex and Sonarr - Add mediatask.py for processing series and movies with Telegram notifications --- .env | 1 + mediascheduler.py | 155 ++++++++++++++++++++++++++++++++++++++++++++++ mediatask.py | 96 ++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 .env create mode 100644 mediascheduler.py create mode 100644 mediatask.py diff --git a/.env b/.env new file mode 100644 index 0000000..fedbdf2 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +LOG_ENABLED=true \ No newline at end of file diff --git a/mediascheduler.py b/mediascheduler.py new file mode 100644 index 0000000..c5dec70 --- /dev/null +++ b/mediascheduler.py @@ -0,0 +1,155 @@ +import os +from dotenv import load_dotenv +from plexapi.server import PlexServer +import requests +import logging +# Load environment variables from .env file +load_dotenv() +LOG_ENABLED= False +PLEX_TOKEN = os.getenv("PLEX_TOKEN") +PLEX_SERVER_URL = os.getenv("PLEX_SERVER_URL") +SONARR_API_KEY = os.getenv("SONARR_API_KEY") +SONARR_SERVER_URL = os.getenv("SONARR_SERVER_URL") +TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") +TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID") + +# Set up logging +if LOG_ENABLED: + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +else: + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + #logging.getLogger().setLevel(logging.CRITICAL) + +PLEX_TOKEN = "uZn42JMVkQpyb_duFsvT" +PLEX_SERVER_URL = "http://192.168.50.111:32400" +SONARR_API_KEY = "2537de37fded4874ae83da9cf3c14f34" +SONARR_SERVER_URL = "http://192.168.50.111:8989" +plex = PlexServer(PLEX_SERVER_URL, PLEX_TOKEN) +tv_shows = plex.library.section('TV Shows') +# List of TV show titles to exclude +exclude_shows = ["Stargate SG-1", "Space Sheriff Gavan", "Spider-Man and His Amazing Friends","Super Sentai", "Superman & Lois", "UFO Robot Grendizer","Zorro", +"Saved by the Bell: The College Years","Saber Rider and the Star Sheriffs","Prison Break","Power Rangers","The Outer Limits (1995)","MacGyver","Knight Rider", +"Chuck","Breaking Bad","Amazing Stories (1985)","Airwolf","The Adventures of Superboy (1988)"] +def unmonitor_all_excluded_shows(): + for show_title in exclude_shows: + show = tv_shows.get(title=show_title) + if LOG_ENABLED: + logging.info(f"Unmonitor Title: {show.title}") + tvdb_id = get_tvdb_id(show) + series_id = get_series_id_from_tvdb(tvdb_id) + seasons = show.seasons() + for season in seasons: + mark_season_unmonitored(series_id, season.index) + logging.info(f"All seasons of '{show_title}' have been marked as unmonitored.") +# Function to check if the last 3 episodes of a season are watched +def last_3_episodes_watched(season): + episodes = sorted(season.episodes(), key=lambda ep: ep.index) + return all(ep.isWatched for ep in episodes[-3:]) +# Function to check if the first 3 episodes of a season are watched +def first_3_episodes_watched(season): + episodes = sorted(season.episodes(), key=lambda ep: ep.index) + return all(ep.isWatched for ep in episodes[:3]) +# Function to check if Sonarr API is alive and the token is correct +def verify_sonarr_api(): + url = f"{SONARR_SERVER_URL}/api/v3/system/status?apikey={SONARR_API_KEY}" + try: + response = requests.get(url) + response.raise_for_status() + if LOG_ENABLED: + logging.info("Sonarr API is alive and the token is correct.") + except requests.exceptions.RequestException as e: + logging.error(f"Failed to verify Sonarr API: {e}") + raise +# Function to get the series ID from the TVDB ID +def get_series_id_from_tvdb(tvdb_id): + url = f"{SONARR_SERVER_URL}/api/v3/series/lookup?term=tvdb:{tvdb_id}&apikey={SONARR_API_KEY}" + response = requests.get(url) + response.raise_for_status() + series = response.json() + if series: + if LOG_ENABLED: + logging.info(f"Series found: {series[0]['title']} (ID: {series[0]['id']})") + return series[0]['id'] + else: + raise ValueError(f"No series found for TVDB ID: {tvdb_id}") +# Function to mark a season as unmonitored in Sonarr v4 +def mark_season_unmonitored(series_id, season_number): + url = f"{SONARR_SERVER_URL}/api/v3/series/{series_id}?apikey={SONARR_API_KEY}" + response = requests.get(url) + response.raise_for_status() + series = response.json() + for season in series['seasons']: + if season['seasonNumber'] == season_number: + season['monitored'] = False + response = requests.put(url, json=series) + response.raise_for_status() + logging.info(f"Season {season_number} marked as unmonitored for series ID {series_id}.") +def get_tvdb_id(show): + for guid in reversed(show.guids): + if guid.id.startswith("tvdb"): + return guid.id.split("://")[1] + raise ValueError(f"No TVDB ID found for show: {show.title}") +def get_total_seasons(show): + return len(show.seasons()) +def verify_total_seasons_from_tvdb(show, series_id): + url = f"{SONARR_SERVER_URL}/api/v3/series/{series_id}?apikey={SONARR_API_KEY}" + response = requests.get(url) + response.raise_for_status() + series_data = response.json() + # logging.info(series_data) + season_count = series_data.get('statistics', {}).get('seasonCount') + if LOG_ENABLED: + logging.info(f"Total seasons for {show.title} from TVDB ({season_count}) instead Available on Plex ({len(show.seasons())})") + +# Verify Sonarr API before proceeding +verify_sonarr_api() +# Call this function after processing the main shows +# unmonitor_all_excluded_shows() +# Iterate over all TV shows and apply the deletion rules +for show in tv_shows.all(): + try: + if show.title not in exclude_shows: + logging.info(f"Processing TV Show: {show.title}") + + # Verify total seasons from TVDB + tvdb_id = get_tvdb_id(show) + series_id = get_series_id_from_tvdb(tvdb_id) + verify_total_seasons_from_tvdb(show, series_id) + + seasons = sorted(show.seasons(), key=lambda s: s.index) + + if len(seasons) > 1: # Ensure there is a previous season to delete + latest_season = seasons[-1] + + if len(latest_season.episodes()) >= 3 and first_3_episodes_watched(latest_season): + logging.info(f"TVDB ID: {tvdb_id}") + + for season in seasons[:-1]: # Excluding the latest season + mark_season_unmonitored(series_id, season.index) + logging.info(f" - Marking Season {season.index} as unmonitored and ready to delete") + else: + for episode in latest_season.episodes(): + if episode.isWatched: + logging.info(f" - Watched Episode: {episode.title} (Episode Number: {episode.episodeNumber})") + except Exception as e: + logging.error(f"Error processing show '{show.title}': {e}") + #break + + +# Send a report message with the list of TV series and movies being processed +""" report_message = "TV Series and Movies Being Processed:\n\n" +report_message += "* Number of Shows: {}\n".format(len(tv_shows.all())) +for show in tv_shows.all(): + report_message += "- {} (Last Season)\n".format(show.title) +logging.info("Sending Telegram message with the report...") +response = requests.post( + "https://api.telegram.org/bot{}/sendMessage".format(TELEGRAM_BOT_TOKEN), + data={ + 'chat_id': TELEGRAM_CHAT_ID, + 'text': report_message + } +) +if response.status_code == 200: + logging.info("Telegram message sent successfully.") +else: + logging.error("Failed to send Telegram message.") """ diff --git a/mediatask.py b/mediatask.py new file mode 100644 index 0000000..560648b --- /dev/null +++ b/mediatask.py @@ -0,0 +1,96 @@ +import requests +import datetime +import telegram + +# Configuration +SONARR_API_URL = 'http://localhost:8989/api' +SONARR_API_KEY = 'your_sonarr_api_key' +RADARR_API_URL = 'http://localhost:7878/api' +RADARR_API_KEY = 'your_radarr_api_key' +PLEX_API_URL = 'http://localhost:32400' +PLEX_API_KEY = 'your_plex_api_key' +TELEGRAM_BOT_TOKEN = 'your_telegram_bot_token' +TELEGRAM_CHAT_ID = 'your_telegram_chat_id' +EXCEPTION_SERIES = ['Series1', 'Series2'] # Add your exception series here + +# Initialize Telegram bot +bot = telegram.Bot(token=TELEGRAM_BOT_TOKEN) + +def get_plex_last_watched(): + # Implement function to get last watched date from Plex + pass + +def disable_series_in_sonarr(series_id): + url = f"{SONARR_API_URL}/series/{series_id}" + headers = {'X-Api-Key': SONARR_API_KEY} + data = {'monitored': False} + response = requests.put(url, json=data, headers=headers) + return response.status_code == 200 + +def disable_movie_in_radarr(movie_id): + url = f"{RADARR_API_URL}/movie/{movie_id}" + headers = {'X-Api-Key': RADARR_API_KEY} + data = {'monitored': False} + response = requests.put(url, json=data, headers=headers) + return response.status_code == 200 + +def list_non_hd_movies(): + # Implement function to list non-HD movies from Radarr + pass + +def send_telegram_message(message): + bot.send_message(chat_id=TELEGRAM_CHAT_ID, text=message, parse_mode=telegram.ParseMode.MARKDOWN) + +def process_series(): + # Get all series from Sonarr + response = requests.get(f"{SONARR_API_URL}/series", headers={'X-Api-Key': SONARR_API_KEY}) + series_list = response.json() + + processed_series = [] + for series in series_list: + if series['title'] in EXCEPTION_SERIES: + continue + last_watched = get_plex_last_watched(series['title']) + if last_watched and (datetime.datetime.now() - last_watched).days > 90: + if disable_series_in_sonarr(series['id']): + processed_series.append(series['title']) + + return processed_series + +def process_movies(): + # Get all movies from Radarr + response = requests.get(f"{RADARR_API_URL}/movie", headers={'X-Api-Key': RADARR_API_KEY}) + movie_list = response.json() + + processed_movies = [] + for movie in movie_list: + if get_plex_last_watched(movie['title']): + if disable_movie_in_radarr(movie['id']): + processed_movies.append(movie['title']) + + return processed_movies + +def main(): + # Process series and movies + processed_series = process_series() + processed_movies = process_movies() + + # List non-HD movies + non_hd_movies = list_non_hd_movies() + + # Send Telegram message + message = "*Processed TV Series and Movies*\n\n" + message += "*TV Series:*\n" + for i, series in enumerate(processed_series, 1): + message += f"{i}. {series}\n" + message += "\n*Movies:*\n" + for i, movie in enumerate(processed_movies, 1): + message += f"{i}. {movie}\n" + message += "\n*Non-HD Movies:*\n" + for movie in non_hd_movies: + message += f"- {movie}\n" + + send_telegram_message(message) + +if __name__ == "__main__": + main() \ No newline at end of file