2 Commits

Author SHA1 Message Date
phoenix fa8538339c Merge remote-tracking branch 'origin/master' into phoenix 2024-12-26 15:12:44 +08:00
phoenix 4cdd1ef457 ppp 2024-12-26 15:06:12 +08:00
4 changed files with 144 additions and 252 deletions
-1
View File
@@ -1 +0,0 @@
LOG_ENABLED=true
-155
View File
@@ -1,155 +0,0 @@
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.") """
-96
View File
@@ -1,96 +0,0 @@
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()
+144
View File
@@ -0,0 +1,144 @@
#!/bin/bash
# Plex TV Shows Cleanup Script with Sonarr Integration for Unraid
# Configuration
PLEX_TOKEN="uZn42JMVkQpyb_duFsvT" # Replace with your Plex API token
PLEX_SERVER_URL="https://192.168.50.111:32400" # Replace with your Plex server URL
TV_SHOWS_PATH="/mnt/user/stuff/videos/tvshows" # Replace with your TV shows directory path
SONARR_API_KEY="2537de37fded4874ae83da9cf3c14f34" # Replace with your Sonarr API key
SONARR_URL="http://192.168.50.111:8989" # Replace with your Sonarr server URL
SHOWS_LIST=("Agatha All Along" "Arcane") # Replace with your TV show names
# Log File Configuration
LOG_DIR="/mnt/user/appdata/customlog" # Directory for log files
LOG_FILE="$LOG_DIR/plex_cleanup_$(date '+%Y-%m-%d').log" # Daily log file
# Ensure dependencies
# command -v curl >/dev/null 2>&1 || { echo "curl is not installed. Exiting."; exit 1; }
# command -v jq >/dev/null 2>&1 || { echo "jq is not installed. Exiting."; exit 1; }
# Ensure log directory exists
mkdir -p "$LOG_DIR"
# Function to log messages
log() {
local message="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" | tee -a "$LOG_FILE"
}
# Function to fetch the Plex library section ID for TV Shows
get_tv_shows_section_id() {
log "Fetching TV Shows section ID"
local plex_section_id
plex_section_id=$(curl -s -X GET "$PLEX_SERVER_URL/library/sections" -H "X-Plex-Token: $PLEX_TOKEN" | \
jq -r '.MediaContainer.Directory[] | select(.type == "show") | .key')
if [[ -z "$plex_section_id" ]]; then
log "Could not find TV Shows section ID. Exiting."
exit 1
fi
echo "$plex_section_id"
}
# Function to fetch watched status for a show
fetch_watched_episodes() {
local show_name="$1"
local plex_section_id="$2"
local show_id
local watched_episodes
log "Fetching watched episodes for: $show_name"
# Get the show ID for the specific show
show_id=$(curl -s -X GET "$PLEX_SERVER_URL/library/sections/$plex_section_id/all" -H "X-Plex-Token: $PLEX_TOKEN" | \
jq -r ".MediaContainer.Metadata[] | select(.title == \"$show_name\") | .ratingKey")
if [[ -z "$show_id" ]]; then
log "Could not find show ID for $show_name. Skipping."
return
fi
# Fetch watched episodes for the specific show
watched_episodes=$(curl -s -X GET "$PLEX_SERVER_URL/library/metadata/$show_id/allLeaves" -H "X-Plex-Token: $PLEX_TOKEN" | \
jq '.MediaContainer.Metadata[] | select(.viewCount != null) | .title')
echo "$watched_episodes"
}
# Function to delete old seasons and mark unmonitored in Sonarr
delete_and_unmonitor_seasons() {
local show_name="$1"
local show_path="$2"
log "Processing directory: $show_path"
for season_dir in "$show_path"/*; do
if [[ -d "$season_dir" ]]; then
season_name=$(basename "$season_dir")
if [[ "$season_name" =~ ^Season[[:space:]][[:digit:]]+$ ]]; then
log "Deleting watched season: $season_name"
rm -rf "$season_dir"
# Mark as unmonitored in Sonarr
season_number=$(echo "$season_name" | grep -oE '[0-9]+')
mark_unmonitored_in_sonarr "$show_name" "$season_number"
fi
fi
done
}
# Function to mark a season as unmonitored in Sonarr
mark_unmonitored_in_sonarr() {
local show_name="$1"
local season_number="$2"
local series_id
local seasons_data
log "Marking $show_name - Season $season_number as unmonitored in Sonarr."
# Get the series ID
series_id=$(curl -s "$SONARR_URL/api/v3/series" -H "X-Api-Key: $SONARR_API_KEY" | \
jq -r ".[] | select(.title==\"$show_name\") | .id")
if [[ -z "$series_id" ]]; then
log "Could not find series ID for $show_name in Sonarr. Skipping."
return
fi
# Fetch seasons data
seasons_data=$(curl -s "$SONARR_URL/api/v3/series/$series_id" -H "X-Api-Key: $SONARR_API_KEY")
# Update the monitored status for the specific season
updated_seasons=$(echo "$seasons_data" | jq ".seasons | map(if .seasonNumber == $season_number then .monitored = false else . end)")
# Send the updated data back to Sonarr
curl -s -X PUT "$SONARR_URL/api/v3/series/$series_id" \
-H "X-Api-Key: $SONARR_API_KEY" \
-H "Content-Type: application/json" \
--data "$(echo "$seasons_data" | jq ".seasons = $updated_seasons")" > /dev/null
log "Marked $show_name - Season $season_number as unmonitored in Sonarr."
}
# Main Script Execution
log "Starting Plex TV Shows Cleanup with Sonarr Integration"
plex_section_id=$(get_tv_shows_section_id)
for show in "${SHOWS_LIST[@]}"; do
log "Checking show: $show"
watched=$(fetch_watched_episodes "$show" "$plex_section_id")
if [[ "$watched" -gt 0 ]]; then
log "Show '$show' has watched episodes. Cleaning up..."
show_path="$TV_SHOWS_PATH/$show"
delete_and_unmonitor_seasons "$show" "$show_path"
else
log "No watched episodes for '$show'. Skipping cleanup."
fi
done
log "Plex TV Shows Cleanup with Sonarr Integration completed"