From b8f1ce3b13fd5df15094862b42c64fded8faa76f Mon Sep 17 00:00:00 2001 From: Brandon4466 Date: Sat, 31 May 2025 18:15:25 -0700 Subject: [PATCH] changes to db and added requirements.txt for setup --- main.py | 83 +- movies.db | Bin 376832 -> 385024 bytes requirements.txt | 6 + scan.log | 14801 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 14872 insertions(+), 18 deletions(-) create mode 100644 requirements.txt create mode 100644 scan.log diff --git a/main.py b/main.py index d49d069..be0f28e 100644 --- a/main.py +++ b/main.py @@ -5,12 +5,21 @@ import requests import time import jwt import json +import logging # New import for logging from fastapi import FastAPI, HTTPException, Request, Depends, Header, WebSocket, WebSocketDisconnect, Query from fastapi.responses import StreamingResponse, FileResponse from passlib.context import CryptContext import media_scanner # Import the Rust module from rapidfuzz import fuzz +# Configure logging +logging.basicConfig( + filename="scan.log", # Log file name + filemode="a", # Append mode + format="%(asctime)s - %(levelname)s - %(message)s", + level=logging.INFO +) + # Configuration MOVIES_DIR = r"Z:\plexmediaserver\movies" # Directory containing movie files TV_SHOWS_DIR = r"Z:\plexmediaserver\tv" # Directory containing TV shows and episodes @@ -179,6 +188,9 @@ def fetch_movie_details(title, year=None): response = requests.get('http://www.omdbapi.com/', params=params) data = response.json() if data.get('Response') == 'True': + logging.info(data) + if data['Poster'] == 'N/A': + data['Poster'] = 'https://placehold.co/500x750/jpg?text=No+Poster' return data else: raise ValueError(f"Movie '{title}' not found.") @@ -217,11 +229,15 @@ def add_tv_show_to_db(details): def scan_and_populate(): init_db() processed_shows = set() # Keep track of processed TV shows + log_messages = [] # Collect log messages try: - # Use Rust for scanning movies - print("Scanning movies...") + msg = "Scanning movies..." + print(msg) + logging.info(msg) movie_files = media_scanner.scan_movies(MOVIES_DIR) - print(f"Found movie files: {movie_files}") + msg = f"Found movie files: {movie_files}" + print(msg) + logging.info(msg) for full_path in movie_files: parent = os.path.basename(os.path.dirname(full_path)) match = re.match(r"(.+?)\s*\((\d{4})\)$", parent) @@ -233,20 +249,29 @@ def scan_and_populate(): year = None rel_path = os.path.relpath(full_path, MOVIES_DIR) if movie_exists(rel_path): - print(f"Movie already exists: {title} ({year or 'n/a'})") + msg = f"Movie already exists: {title} ({year or 'n/a'})" + print(msg) + logging.info(msg) continue try: details = fetch_movie_details(title, year) details['filepath'] = rel_path add_movie_to_db(details) - print(f"Added {title} ({year or 'n/a'}) to database.") + msg = f"Added {title} ({year or 'n/a'}) to database." + print(msg) + logging.info(msg) except Exception as e: - print(f"Skipping {title}: {e}") + msg = f"Skipping {title}: {e}" + print(msg) + logging.error(msg) - # Updated logic for scanning TV shows with fuzzy matching - print("Scanning TV shows...") + msg = "Scanning TV shows..." + print(msg) + logging.info(msg) tv_show_files = media_scanner.scan_tv_shows(TV_SHOWS_DIR) - print(f"Found TV show files: {tv_show_files}") + msg = f"Found TV show files: {tv_show_files}" + print(msg) + logging.info(msg) for full_path in tv_show_files: # Extract TV show name from the folder structure: "Show Name\Season X\filename" show_name = os.path.basename(os.path.dirname(os.path.dirname(full_path))) @@ -254,14 +279,18 @@ def scan_and_populate(): season_dir = os.path.basename(os.path.dirname(full_path)) season_match = re.search(r"Season\s*(\d+)", season_dir, re.IGNORECASE) if not season_match: - print(f"Skipping {full_path}: Season number not found in directory '{season_dir}'") + msg = f"Skipping {full_path}: Season number not found in directory '{season_dir}'" + print(msg) + logging.warning(msg) continue season = int(season_match.group(1)) # Extract episode number solely from the SxxEyy pattern in the filename basename = os.path.basename(full_path) ep_match = re.search(r"(?i)S(\d{2})E(\d{2})", basename) if not ep_match: - print(f"Skipping {full_path}: SxxEyy pattern not found in filename") + msg = f"Skipping {full_path}: SxxEyy pattern not found in filename" + print(msg) + logging.warning(msg) continue episode = int(ep_match.group(2)) # Check and add TV show details if not processed yet @@ -270,11 +299,17 @@ def scan_and_populate(): try: tv_details = fetch_tv_show_details(show_name) add_tv_show_to_db(tv_details) - print(f"Added TV show details: {show_name}") + msg = f"Added TV show details: {show_name}" + print(msg) + logging.info(msg) except Exception as e: - print(f"Skipping TV show details for {show_name}: {e}") + msg = f"Skipping TV show details for {show_name}: {e}" + print(msg) + logging.error(msg) else: - print(f"TV show already exists: {show_name}") + msg = f"TV show already exists: {show_name}" + print(msg) + logging.info(msg) processed_shows.add(show_name) rel_path = os.path.relpath(full_path, TV_SHOWS_DIR) conn = sqlite3.connect(DB_PATH) @@ -296,9 +331,13 @@ def scan_and_populate(): break if tv_show_row: tv_show_id = tv_show_row[0] - print(f"Fuzzy matched '{show_name}' to '{tv_show_row[1]}' with score {similarity}") + msg = f"Fuzzy matched '{show_name}' to '{tv_show_row[1]}' with score {similarity}" + print(msg) + logging.info(msg) else: - print(f"TV show id not found for {show_name}") + msg = f"TV show id not found for {show_name}" + print(msg) + logging.warning(msg) conn.close() continue # Use the complete filename (without extension) as the episode title @@ -309,9 +348,17 @@ def scan_and_populate(): ''', (rel_path, tv_show_id, season, episode, title)) conn.commit() conn.close() - print(f"Added episode: {show_name} Season {season} Episode {episode}") + msg = f"Added episode: {show_name} Season {season} Episode {episode}" + print(msg) + logging.info(msg) except Exception as e: - print(f"Error during scanning: {e}") + msg = f"Error during scanning: {e}" + print(msg) + logging.error(msg) + finally: + msg = "Scan and populate completed." + print(msg) + logging.info(msg) def range_streamer(file_path: str, range_header: str = None, chunk_size: int = 1024*1024): file_size = os.path.getsize(file_path) diff --git a/movies.db b/movies.db index 6fe95e98b342b566a302051dd1324497463cd5c4..7e7eab140883a46c62a115e99812ce9c2f695eb2 100644 GIT binary patch delta 8729 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 delta 583 zcmWlWPe@cz6vp2<_r5o8p6_|bCYk}unbE0qH0Pn=pPX_u3c*SSTtxI|w4?-aM08L} zn5RKPP{{-DrXlR#A_$R5Z-v0Z z*x2hcjvGPm7w@dM$6KLH8YwYky<9L9x2{gsOcGPmv$kig&aJz^{OWAAoh^1Jpbh~u5HzP)hxM<23 zK;FF@ujS`H;>P?mYW%l@m3-eZ%<|PwxJ84c5yg|wcsUu6b?FdQtcN8X-YV?_eNIDU w0irUU2_jlXrjXur&ilnPKe=KWM9(YMn(;@^7b5BV`kj0=kwZnkTD{8u0|-l