import os import time import datetime import pickle from googleapiclient.discovery import build import subprocess from google.auth.transport.requests import Request import signal import sys # Constants OUTPUT_DIR = "/media/media/YouTube" # Change this to your Emby folder DAYS_BACK = 5 # Videos published in the last 5 days DAYS_TO_KEEP = 10 # Delete videos older than 10 days TOKEN_FILE = "youtube_token.pickle" # Token file from the OAuth script EXIT_TIME = datetime.time(6, 0) # Exit the script at 06:00 def authenticate_with_token(): """Authenticate using the saved token.""" if not os.path.exists(TOKEN_FILE): raise FileNotFoundError(f"Token file '{TOKEN_FILE}' not found. Please run the token retrieval script first.") with open(TOKEN_FILE, "rb") as token: creds = pickle.load(token) # Refresh the token if needed if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) youtube = build("youtube", "v3", credentials=creds) return youtube def get_subscribed_channels(youtube): """Fetch the list of subscribed channels.""" channels = [] request = youtube.subscriptions().list( part="snippet", mine=True, maxResults=50 ) while request: response = request.execute() for item in response["items"]: channels.append(item["snippet"]["resourceId"]["channelId"]) request = youtube.subscriptions().list_next(request, response) return channels def get_recent_videos(youtube, channel_id): """Fetch videos from a channel published in the last `DAYS_BACK` days.""" recent_videos = [] published_after = (datetime.datetime.now() - datetime.timedelta(days=DAYS_BACK)).isoformat("T") + "Z" request = youtube.search().list( part="snippet", channelId=channel_id, publishedAfter=published_after, maxResults=50, type="video", order="date" ) response = request.execute() for item in response["items"]: recent_videos.append({ "video_id": item["id"]["videoId"], "title": item["snippet"]["title"], "description": item["snippet"]["description"], "published_at": item["snippet"]["publishedAt"], "channel_title": item["snippet"]["channelTitle"] }) return recent_videos def download_video(video_id, output_path): """Download a YouTube video as mp4 using yt-dlp.""" command = [ "yt-dlp", "-f", "bestvideo+bestaudio[ext=mp4]/best[ext=mp4]/best", # Ensure highest quality as MP4 f"https://www.youtube.com/watch?v={video_id}", "-o", os.path.join(output_path, "%(title)s.%(ext)s") ] subprocess.run(command, check=True) def create_nfo_file(video_data, file_path): """Create an Emby-compatible NFO file.""" nfo_content = f""" {video_data['title']} {video_data['description']} {video_data['published_at'][:4]} {video_data['published_at']} {video_data['channel_title']} """ with open(file_path, "w", encoding="utf-8") as nfo_file: nfo_file.write(nfo_content) def delete_old_videos(folder, days=10): """Delete video files and corresponding NFO files older than `days`.""" now = time.time() cutoff = now - (days * 86400) # Convert days to seconds for root, dirs, files in os.walk(folder): for file in files: file_path = os.path.join(root, file) if os.path.isfile(file_path): # Check the file's last modification time if os.path.getmtime(file_path) < cutoff: print(f"Deleting: {file_path}") os.remove(file_path) def video_exists(output_path, video_id): """Check if a video already exists in the directory.""" return os.path.exists(os.path.join(output_path, video_id)) def check_exit_time(): """Check if the current time is past the exit time.""" now = datetime.datetime.now().time() if now >= EXIT_TIME: print("Current time exceeds exit time. Terminating script.") sys.exit(0) def main(): # Authenticate YouTube API print("Authenticating with token...") youtube = authenticate_with_token() if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) # Clean up old videos print(f"Deleting videos older than {DAYS_TO_KEEP} days in {OUTPUT_DIR}...") delete_old_videos(OUTPUT_DIR, days=DAYS_TO_KEEP) # Fetch subscribed channels print("Fetching subscribed channels...") channels = get_subscribed_channels(youtube) # Fetch and process recent videos for channel_id in channels: print(f"Fetching recent videos for channel: {channel_id}") videos = get_recent_videos(youtube, channel_id) for video in videos: # Check the exit time before processing each video check_exit_time() print(f"Processing video: {video['title']}") video_dir = os.path.join(OUTPUT_DIR, video["video_id"]) # Check if the video already exists if os.path.exists(video_dir): print(f"Skipping download, already exists: {video['title']} ({video['video_id']})") continue os.makedirs(video_dir, exist_ok=True) # Download the video download_video(video["video_id"], video_dir) # Create the NFO file nfo_file_path = os.path.join(video_dir, "movie.nfo") create_nfo_file(video, nfo_file_path) print("All videos processed successfully!") if __name__ == "__main__": main()