|
|
@@ -2,10 +2,10 @@ import os
|
|
|
import time
|
|
|
import datetime
|
|
|
import pickle
|
|
|
+import threading
|
|
|
from googleapiclient.discovery import build
|
|
|
import subprocess
|
|
|
from google.auth.transport.requests import Request
|
|
|
-import signal
|
|
|
import sys
|
|
|
|
|
|
# Constants
|
|
|
@@ -14,6 +14,14 @@ 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
|
|
|
+POPULAR_VIDEOS_MAX_RESULTS = 10 # Number of popular videos to fetch (you can change this)
|
|
|
+REGION_CODES = ["US", "GB", "LU"] # Regions to fetch popular videos from
|
|
|
+
|
|
|
+def update_yt_dlp():
|
|
|
+ """Update yt-dlp to the latest version."""
|
|
|
+ print("Updating yt-dlp to the latest version...")
|
|
|
+ subprocess.run(["pip", "install", "--upgrade", "yt-dlp"], check=True)
|
|
|
+ print("yt-dlp updated successfully!")
|
|
|
|
|
|
def authenticate_with_token():
|
|
|
"""Authenticate using the saved token."""
|
|
|
@@ -69,15 +77,53 @@ def get_recent_videos(youtube, channel_id):
|
|
|
})
|
|
|
return recent_videos
|
|
|
|
|
|
+def get_popular_videos(youtube, region_code):
|
|
|
+ """Fetch the most popular videos for a given region."""
|
|
|
+ popular_videos = []
|
|
|
+
|
|
|
+ request = youtube.videos().list(
|
|
|
+ part="snippet,statistics",
|
|
|
+ chart="mostPopular",
|
|
|
+ regionCode=region_code, # Region code passed here
|
|
|
+ maxResults=POPULAR_VIDEOS_MAX_RESULTS
|
|
|
+ )
|
|
|
+ response = request.execute()
|
|
|
+ for item in response["items"]:
|
|
|
+ popular_videos.append({
|
|
|
+ "video_id": item["id"],
|
|
|
+ "title": item["snippet"]["title"],
|
|
|
+ "description": item["snippet"]["description"],
|
|
|
+ "published_at": item["snippet"]["publishedAt"],
|
|
|
+ "channel_title": item["snippet"]["channelTitle"]
|
|
|
+ })
|
|
|
+ return popular_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)
|
|
|
+ """Download a YouTube video in the best quality, handling errors gracefully."""
|
|
|
+ try:
|
|
|
+ command = [
|
|
|
+ "yt-dlp",
|
|
|
+ "-f", "bestvideo+bestaudio/best", # Best available format
|
|
|
+ f"https://www.youtube.com/watch?v={video_id}",
|
|
|
+ "-o", os.path.join(output_path, "%(title)s.%(ext)s")
|
|
|
+ ]
|
|
|
+ subprocess.run(command, check=True)
|
|
|
+ except subprocess.CalledProcessError as e:
|
|
|
+ print(f"Error downloading video {video_id}: {e}")
|
|
|
+ return False # Return False to indicate failure
|
|
|
+ return True # Return True if download is successful
|
|
|
+
|
|
|
+# Temporarily commented out video conversion functionality
|
|
|
+# def convert_to_mp4(input_file):
|
|
|
+# """Convert a video to mp4 and delete the original file."""
|
|
|
+# mp4_file = os.path.splitext(input_file)[0] + ".mp4"
|
|
|
+# print(f"Converting {input_file} to {mp4_file}...")
|
|
|
+# command = ["ffmpeg", "-i", input_file, "-c:v", "libx264", "-preset", "fast", "-c:a", "aac", mp4_file]
|
|
|
+# subprocess.run(command, check=True)
|
|
|
+# print(f"Conversion completed: {mp4_file}")
|
|
|
+# if os.path.exists(mp4_file):
|
|
|
+# os.remove(input_file)
|
|
|
+# print(f"Original file deleted: {input_file}")
|
|
|
|
|
|
def create_nfo_file(video_data, file_path):
|
|
|
"""Create an Emby-compatible NFO file."""
|
|
|
@@ -119,6 +165,9 @@ def check_exit_time():
|
|
|
sys.exit(0)
|
|
|
|
|
|
def main():
|
|
|
+ # Update yt-dlp
|
|
|
+ update_yt_dlp()
|
|
|
+
|
|
|
# Authenticate YouTube API
|
|
|
print("Authenticating with token...")
|
|
|
youtube = authenticate_with_token()
|
|
|
@@ -134,7 +183,7 @@ def main():
|
|
|
print("Fetching subscribed channels...")
|
|
|
channels = get_subscribed_channels(youtube)
|
|
|
|
|
|
- # Fetch and process recent videos
|
|
|
+ # Fetch and process recent videos from subscribed channels
|
|
|
for channel_id in channels:
|
|
|
print(f"Fetching recent videos for channel: {channel_id}")
|
|
|
videos = get_recent_videos(youtube, channel_id)
|
|
|
@@ -154,7 +203,55 @@ def main():
|
|
|
os.makedirs(video_dir, exist_ok=True)
|
|
|
|
|
|
# Download the video
|
|
|
- download_video(video["video_id"], video_dir)
|
|
|
+ if not download_video(video["video_id"], video_dir):
|
|
|
+ print(f"Skipping video {video['video_id']} due to download error.")
|
|
|
+ continue # Skip this video if download failed
|
|
|
+
|
|
|
+ # Temporarily comment out conversion, but keep it in the code for future use
|
|
|
+ # video_file = next(
|
|
|
+ # (f for f in os.listdir(video_dir) if not f.endswith(".mp4")),
|
|
|
+ # None
|
|
|
+ # )
|
|
|
+ # if video_file:
|
|
|
+ # input_path = os.path.join(video_dir, video_file)
|
|
|
+ # threading.Thread(target=convert_to_mp4, args=(input_path,)).start()
|
|
|
+
|
|
|
+ # Create the NFO file
|
|
|
+ nfo_file_path = os.path.join(video_dir, "movie.nfo")
|
|
|
+ create_nfo_file(video, nfo_file_path)
|
|
|
+
|
|
|
+ # Fetch and process most popular videos worldwide (from multiple regions)
|
|
|
+ for region_code in REGION_CODES:
|
|
|
+ print(f"Fetching the most popular videos from {region_code}...")
|
|
|
+ popular_videos = get_popular_videos(youtube, region_code)
|
|
|
+
|
|
|
+ for video in popular_videos:
|
|
|
+ # Check the exit time before processing each video
|
|
|
+ check_exit_time()
|
|
|
+
|
|
|
+ print(f"Processing popular video: {video['title']} ({region_code})")
|
|
|
+ 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 popular video
|
|
|
+ if not download_video(video["video_id"], video_dir):
|
|
|
+ print(f"Skipping popular video {video['video_id']} due to download error.")
|
|
|
+ continue # Skip this video if download failed
|
|
|
+
|
|
|
+ # Temporarily comment out conversion, but keep it in the code for future use
|
|
|
+ # video_file = next(
|
|
|
+ # (f for f in os.listdir(video_dir) if not f.endswith(".mp4")),
|
|
|
+ # None
|
|
|
+ # )
|
|
|
+ # if video_file:
|
|
|
+ # input_path = os.path.join(video_dir, video_file)
|
|
|
+ # threading.Thread(target=convert_to_mp4, args=(input_path,)).start()
|
|
|
|
|
|
# Create the NFO file
|
|
|
nfo_file_path = os.path.join(video_dir, "movie.nfo")
|