| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- 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"""<?xml version="1.0" encoding="utf-8" standalone="yes"?>
- <movie>
- <title>{video_data['title']}</title>
- <plot>{video_data['description']}</plot>
- <year>{video_data['published_at'][:4]}</year>
- <premiered>{video_data['published_at']}</premiered>
- <studio>{video_data['channel_title']}</studio>
- </movie>
- """
- 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()
|