Murad Jabir 1 an în urmă
părinte
comite
5e172ee3b7
1 a modificat fișierele cu 330 adăugiri și 74 ștergeri
  1. 330 74
      main.py

+ 330 - 74
main.py

@@ -1,6 +1,7 @@
 import os
 import os
 import time
 import time
 import datetime
 import datetime
+from datetime import datetime, time as dt_time
 import pickle
 import pickle
 import threading
 import threading
 import queue
 import queue
@@ -11,12 +12,40 @@ from google.auth.transport.requests import Request
 import sys
 import sys
 from auth import get_token, get_token_non_interactive, get_service_account_token
 from auth import get_token, get_token_non_interactive, get_service_account_token
 
 
+# Home Assistant Integration
+try:
+    from homeassistant_integration import (
+        init_homeassistant_integration, 
+        update_homeassistant_stats, 
+        stop_homeassistant_integration,
+        set_service_waiting,
+        set_service_running,
+        set_service_completed,
+        set_service_error
+    )
+    HOMEASSISTANT_ENABLED = True
+    print("🏠 Home Assistant integration available")
+except ImportError:
+    HOMEASSISTANT_ENABLED = False
+    print("⚠️ Home Assistant integration not available (install paho-mqtt and psutil)")
+    
+    # Dummy functions if Home Assistant is not available
+    def set_service_waiting(next_run): pass
+    def set_service_running(): pass
+    def set_service_completed(): pass
+    def set_service_error(): pass
+    
+    # Dummy functions if not available
+    def init_homeassistant_integration(*args, **kwargs): return None
+    def update_homeassistant_stats(*args, **kwargs): pass
+    def stop_homeassistant_integration(*args, **kwargs): pass
+
 # Constants
 # Constants
 OUTPUT_DIR = "/media/media/YouTube"  # Change this to your Emby folder
 OUTPUT_DIR = "/media/media/YouTube"  # Change this to your Emby folder
 DAYS_BACK = 5  # Videos published in the last 5 days
 DAYS_BACK = 5  # Videos published in the last 5 days
 DAYS_TO_KEEP = 10  # Delete videos older than 10 days
 DAYS_TO_KEEP = 10  # Delete videos older than 10 days
 TOKEN_FILE = "youtube_token.pickle"  # Token file from the OAuth script
 TOKEN_FILE = "youtube_token.pickle"  # Token file from the OAuth script
-EXIT_TIME = datetime.time(6, 0)  # Exit the script at 06:00
+EXIT_TIME = dt_time(6, 0)  # Exit the script at 06:00
 POPULAR_VIDEOS_MAX_RESULTS = 10  # Number of popular videos to fetch (you can change this)
 POPULAR_VIDEOS_MAX_RESULTS = 10  # Number of popular videos to fetch (you can change this)
 REGION_CODES = ["US", "GB", "LU", "LK"]  # Regions to fetch popular videos from
 REGION_CODES = ["US", "GB", "LU", "LK"]  # Regions to fetch popular videos from
 
 
@@ -24,10 +53,30 @@ REGION_CODES = ["US", "GB", "LU", "LK"]  # Regions to fetch popular videos from
 MAX_CONCURRENT_CONVERSIONS = 2  # Maximum number of simultaneous video conversions
 MAX_CONCURRENT_CONVERSIONS = 2  # Maximum number of simultaneous video conversions
 CONVERSION_QUEUE_SIZE = 50       # Maximum items in conversion queue
 CONVERSION_QUEUE_SIZE = 50       # Maximum items in conversion queue
 
 
+# FFmpeg/FFprobe paths
+FFPROBE_PATH = "/usr/bin/ffprobe"
+FFMPEG_PATH = "/usr/bin/ffmpeg"
+
 # Global conversion queue and executor
 # Global conversion queue and executor
 conversion_queue = queue.Queue(maxsize=CONVERSION_QUEUE_SIZE)
 conversion_queue = queue.Queue(maxsize=CONVERSION_QUEUE_SIZE)
 conversion_executor = ThreadPoolExecutor(max_workers=MAX_CONCURRENT_CONVERSIONS, thread_name_prefix="VideoConverter")
 conversion_executor = ThreadPoolExecutor(max_workers=MAX_CONCURRENT_CONVERSIONS, thread_name_prefix="VideoConverter")
 
 
+# Progress tracking
+download_stats = {
+    'total_videos': 0,
+    'completed_videos': 0,
+    'current_video': '',
+    'download_speed': 0,
+    'active_downloads': 0
+}
+
+conversion_stats = {
+    'active_conversions': 0,
+    'completed_conversions': 0,
+    'current_conversion': '',
+    'conversion_progress': 0
+}
+
 def update_yt_dlp():
 def update_yt_dlp():
     """Update yt-dlp to the latest version."""
     """Update yt-dlp to the latest version."""
     print("Updating yt-dlp to the latest version...")
     print("Updating yt-dlp to the latest version...")
@@ -117,27 +166,56 @@ def get_popular_videos(youtube, region_code):
         })
         })
     return popular_videos
     return popular_videos
 
 
-def download_video(video_id, output_path):
+def download_video(video_id, output_path, video_title="Unknown"):
     """Download a YouTube video with quality priority - downloads 4K VP9/AV1 if needed for conversion."""
     """Download a YouTube video with quality priority - downloads 4K VP9/AV1 if needed for conversion."""
+    global download_stats
+    
     try:
     try:
+        # Update stats
+        download_stats['active_downloads'] += 1
+        download_stats['current_video'] = video_title[:50] + "..." if len(video_title) > 50 else video_title
+        
+        # Update Home Assistant
+        update_homeassistant_stats(
+            download_queue=download_stats['total_videos'] - download_stats['completed_videos'],
+            conversion_queue=conversion_queue.qsize(),
+            download_progress=round((download_stats['completed_videos'] / max(download_stats['total_videos'], 1)) * 100, 1),
+            active_downloads=download_stats['active_downloads'],
+            active_conversions=conversion_stats['active_conversions']
+        )
+        
         # Quality-priority format selection:
         # Quality-priority format selection:
-        # 1. First try: Apple TV compatible codecs at any resolution
-        # 2. Fallback: Download highest quality available (including 4K VP9/AV1 for conversion)
-        # 3. Last resort: Best available format
         command = [
         command = [
             "yt-dlp",
             "yt-dlp",
             "-f", "(bv[vcodec~='^(avc|h264|hevc|h265)'] / bv[height>=2160] / bv[height>=1080] / best) + (ba[acodec~='^(aac|mp4a)'] / ba)",
             "-f", "(bv[vcodec~='^(avc|h264|hevc|h265)'] / bv[height>=2160] / bv[height>=1080] / best) + (ba[acodec~='^(aac|mp4a)'] / ba)",
             "--merge-output-format", "mp4",
             "--merge-output-format", "mp4",
             "--no-mtime",
             "--no-mtime",
+            "--newline",  # Better for parsing progress
             f"https://www.youtube.com/watch?v={video_id}",
             f"https://www.youtube.com/watch?v={video_id}",
             "-o", os.path.join(output_path, "%(title)s.%(ext)s")
             "-o", os.path.join(output_path, "%(title)s.%(ext)s")
         ]
         ]
-        subprocess.run(command, check=True)
+        
+        result = subprocess.run(command, check=True, capture_output=True, text=True)
+        
+        # Update completed count
+        download_stats['completed_videos'] += 1
+        download_stats['active_downloads'] -= 1
+        
         print(f"Successfully downloaded video {video_id} (Quality priority - will convert VP9/AV1 if needed)")
         print(f"Successfully downloaded video {video_id} (Quality priority - will convert VP9/AV1 if needed)")
+        
+        # Update Home Assistant with completion
+        update_homeassistant_stats(
+            download_queue=download_stats['total_videos'] - download_stats['completed_videos'],
+            download_progress=round((download_stats['completed_videos'] / max(download_stats['total_videos'], 1)) * 100, 1),
+            active_downloads=download_stats['active_downloads']
+        )
+        
+        return True
+        
     except subprocess.CalledProcessError as e:
     except subprocess.CalledProcessError as e:
+        download_stats['active_downloads'] -= 1
         print(f"Error downloading video {video_id}: {e}")
         print(f"Error downloading video {video_id}: {e}")
         return False
         return False
-    return True
 
 
 def add_to_conversion_queue(input_file, priority=1):
 def add_to_conversion_queue(input_file, priority=1):
     """Add a video file to the conversion queue with priority."""
     """Add a video file to the conversion queue with priority."""
@@ -200,16 +278,28 @@ def process_conversion_queue():
 
 
 def convert_to_apple_tv_compatible(input_file):
 def convert_to_apple_tv_compatible(input_file):
     """Convert a video to Apple TV 4K compatible format, optimized by resolution."""
     """Convert a video to Apple TV 4K compatible format, optimized by resolution."""
+    global conversion_stats
+    
     base_name = os.path.splitext(input_file)[0]
     base_name = os.path.splitext(input_file)[0]
     mp4_file = base_name + ".mp4"
     mp4_file = base_name + ".mp4"
     
     
+    # Update conversion stats
+    conversion_stats['active_conversions'] += 1
+    conversion_stats['current_conversion'] = os.path.basename(input_file)
+    
     print(f"Converting {input_file} to Apple TV compatible format...")
     print(f"Converting {input_file} to Apple TV compatible format...")
     
     
+    # Update Home Assistant
+    update_homeassistant_stats(
+        conversion_queue=conversion_queue.qsize(),
+        active_conversions=conversion_stats['active_conversions']
+    )
+    
     # Detect video properties to optimize conversion
     # Detect video properties to optimize conversion
     try:
     try:
         import json
         import json
         probe_cmd = [
         probe_cmd = [
-            "ffprobe", "-v", "quiet", "-print_format", "json", 
+            FFPROBE_PATH, "-v", "quiet", "-print_format", "json", 
             "-show_format", "-show_streams", input_file
             "-show_format", "-show_streams", input_file
         ]
         ]
         probe_result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
         probe_result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
@@ -260,7 +350,7 @@ def convert_to_apple_tv_compatible(input_file):
         print("Using H.264 encoding for lower resolution content")
         print("Using H.264 encoding for lower resolution content")
     
     
     command = [
     command = [
-        "ffmpeg", "-i", input_file,
+        FFMPEG_PATH, "-i", input_file,
         *codec_args,
         *codec_args,
         "-c:a", "aac",              # AAC audio codec
         "-c:a", "aac",              # AAC audio codec
         "-b:a", "192k",             # Higher audio bitrate for better quality
         "-b:a", "192k",             # Higher audio bitrate for better quality
@@ -273,12 +363,31 @@ def convert_to_apple_tv_compatible(input_file):
         print("Starting conversion... This may take a while for 4K content.")
         print("Starting conversion... This may take a while for 4K content.")
         subprocess.run(command, check=True)
         subprocess.run(command, check=True)
         print(f"Conversion completed: {mp4_file}")
         print(f"Conversion completed: {mp4_file}")
+        
+        # Update completion stats
+        conversion_stats['active_conversions'] -= 1
+        conversion_stats['completed_conversions'] += 1
+        
+        # Update Home Assistant
+        update_homeassistant_stats(
+            conversion_queue=conversion_queue.qsize(),
+            active_conversions=conversion_stats['active_conversions']
+        )
+        
         if os.path.exists(mp4_file):
         if os.path.exists(mp4_file):
             os.remove(input_file)
             os.remove(input_file)
             print(f"Original file deleted: {input_file}")
             print(f"Original file deleted: {input_file}")
         return True
         return True
     except subprocess.CalledProcessError as e:
     except subprocess.CalledProcessError as e:
+        conversion_stats['active_conversions'] -= 1
         print(f"Conversion failed for {input_file}: {e}")
         print(f"Conversion failed for {input_file}: {e}")
+        
+        # Update Home Assistant
+        update_homeassistant_stats(
+            conversion_queue=conversion_queue.qsize(),
+            active_conversions=conversion_stats['active_conversions']
+        )
+        
         return False
         return False
 
 
 # Temporarily commented out video conversion functionality
 # Temporarily commented out video conversion functionality
@@ -334,12 +443,23 @@ def video_exists(output_path, video_id):
 
 
 def check_exit_time():
 def check_exit_time():
     """Check if the current time is past the exit time."""
     """Check if the current time is past the exit time."""
-    now = datetime.datetime.now().time()
+    now = datetime.now().time()
     if now >= EXIT_TIME:
     if now >= EXIT_TIME:
         print("Current time exceeds exit time. Terminating script.")
         print("Current time exceeds exit time. Terminating script.")
         sys.exit(0)
         sys.exit(0)
 
 
 def main():
 def main():
+    global download_stats
+    
+    # Initialize Home Assistant integration
+    if HOMEASSISTANT_ENABLED:
+        print("🏠 Initializing Home Assistant integration...")
+        ha_integration = init_homeassistant_integration()
+        if ha_integration:
+            print("✅ Home Assistant integration started")
+        else:
+            print("⚠️ Home Assistant integration failed to start")
+    
     # Start the conversion queue worker
     # Start the conversion queue worker
     print("🎬 Starting video conversion queue system...")
     print("🎬 Starting video conversion queue system...")
     print(f"📊 Max concurrent conversions: {MAX_CONCURRENT_CONVERSIONS}")
     print(f"📊 Max concurrent conversions: {MAX_CONCURRENT_CONVERSIONS}")
@@ -366,75 +486,191 @@ def main():
     print("Fetching subscribed channels...")
     print("Fetching subscribed channels...")
     channels = get_subscribed_channels(youtube)
     channels = get_subscribed_channels(youtube)
     
     
-    # Fetch and process recent videos from subscribed channels
+    # Count total videos for progress tracking
+    print("📊 Counting total videos to download...")
+    total_videos = 0
+    all_videos = []
+    
+    # Collect all videos first for counting
     for channel_id in channels:
     for channel_id in channels:
-        print(f"Fetching recent videos for channel: {channel_id}")
         videos = get_recent_videos(youtube, channel_id)
         videos = get_recent_videos(youtube, channel_id)
-        
         for video in videos:
         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"])
             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
-            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
-            
-            # Check if conversion is needed (VP9/AV1 codecs or non-MP4 files)
-            needs_conversion = False
-            conversion_file = None
-            
-            for file in os.listdir(video_dir):
-                if file.endswith(('.mp4', '.mkv', '.webm', '.m4v')):
-                    file_path = os.path.join(video_dir, file)
-                    try:
-                        # Quick check for problematic codecs
-                        probe_cmd = ["ffprobe", "-v", "quiet", "-select_streams", "v:0", 
-                                   "-show_entries", "stream=codec_name", "-of", "csv=p=0", file_path]
-                        result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
-                        codec = result.stdout.strip().lower()
-                        
-                        if codec in ['vp9', 'av01', 'av1'] or not file.endswith('.mp4'):
-                            needs_conversion = True
-                            conversion_file = file_path
-                            print(f"Found {codec} codec - will convert for Apple TV compatibility")
-                            break
-                    except subprocess.CalledProcessError:
-                        # If we can't probe, assume it might need conversion if not MP4
-                        if not file.endswith('.mp4'):
-                            needs_conversion = True
-                            conversion_file = file_path
-                            break
-            
-            if needs_conversion and conversion_file:
-                # Determine priority based on video resolution
+            if not os.path.exists(video_dir):
+                all_videos.append(('subscription', video))
+                total_videos += 1
+    
+    # Add popular videos
+    for region_code in REGION_CODES:
+        popular_videos = get_popular_videos(youtube, region_code)
+        for video in popular_videos:
+            video_dir = os.path.join(OUTPUT_DIR, video["video_id"])
+            if not os.path.exists(video_dir):
+                all_videos.append(('popular', video))
+                total_videos += 1
+    
+    # Initialize download stats
+    download_stats['total_videos'] = total_videos
+    download_stats['completed_videos'] = 0
+    
+    print(f"📈 Total videos to download: {total_videos}")
+    
+    # Update initial Home Assistant stats
+    update_homeassistant_stats(
+        download_queue=total_videos,
+        conversion_queue=0,
+        download_progress=0,
+        active_downloads=0,
+        active_conversions=0
+    )
+    
+    # Process all videos
+    for video_type, video in all_videos:
+        # Check the exit time before processing each video
+        check_exit_time()
+        
+        print(f"Processing {video_type} video: {video['title']}")
+        video_dir = os.path.join(OUTPUT_DIR, video["video_id"])
+        
+        # Create directory
+        os.makedirs(video_dir, exist_ok=True)
+        
+        # Download the video
+        if not download_video(video["video_id"], video_dir, video["title"]):
+            print(f"Skipping video {video['video_id']} due to download error.")
+            continue  # Skip this video if download failed
+        
+        # Check if conversion is needed (VP9/AV1 codecs or non-MP4 files)
+        needs_conversion = False
+        conversion_file = None
+        
+        for file in os.listdir(video_dir):
+            if file.endswith(('.mp4', '.mkv', '.webm', '.m4v')):
+                file_path = os.path.join(video_dir, file)
                 try:
                 try:
-                    probe_cmd = ["ffprobe", "-v", "quiet", "-select_streams", "v:0", 
-                               "-show_entries", "stream=height", "-of", "csv=p=0", conversion_file]
+                    # Quick check for problematic codecs
+                    probe_cmd = [FFPROBE_PATH, "-v", "quiet", "-select_streams", "v:0", 
+                               "-show_entries", "stream=codec_name", "-of", "csv=p=0", file_path]
                     result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
                     result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
-                    height = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 1080
-                    priority = 2 if height >= 2160 else 1  # 4K gets higher priority
-                except:
-                    priority = 1  # Default priority
+                    codec = result.stdout.strip().lower()
+                    
+                    if codec in ['vp9', 'av01', 'av1'] or not file.endswith('.mp4'):
+                        needs_conversion = True
+                        conversion_file = file_path
+                        print(f"Found {codec} codec - will convert for Apple TV compatibility")
+                        break
+                except subprocess.CalledProcessError:
+                    # If we can't probe, assume it might need conversion if not MP4
+                    if not file.endswith('.mp4'):
+                        needs_conversion = True
+                        conversion_file = file_path
+                        break
+        
+        if needs_conversion and conversion_file:
+            # Determine priority based on video resolution
+            try:
+                probe_cmd = [FFPROBE_PATH, "-v", "quiet", "-select_streams", "v:0", 
+                           "-show_entries", "stream=height", "-of", "csv=p=0", conversion_file]
+                result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
+                height = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 1080
+                priority = 2 if height >= 2160 else 1  # 4K gets higher priority
+            except:
+                priority = 1  # Default priority
+            
+            add_to_conversion_queue(conversion_file, priority)
+            print_queue_status()
+        
+        # Create the NFO file
+        nfo_file_path = os.path.join(video_dir, "movie.nfo")
+        create_nfo_file(video, nfo_file_path)
+        
+        # Update completed videos count
+        download_stats['completed_videos'] += 1
+        progress = (download_stats['completed_videos'] / download_stats['total_videos']) * 100
+        
+        # Update Home Assistant stats
+        update_homeassistant_stats(
+            download_queue=max(0, download_stats['total_videos'] - download_stats['completed_videos']),
+            download_progress=round(progress, 1)
+        )
+
+    print("✅ All videos processed!")
+    print(f"📊 Final stats: {download_stats['completed_videos']}/{download_stats['total_videos']} videos completed")
+    
+    # Wait for all conversions to complete
+    print("⏳ Waiting for all conversions to complete...")
+    conversion_executor.shutdown(wait=True)
+    print("✅ All conversions completed!")
+    
+    # Final Home Assistant update
+    update_homeassistant_stats(
+        download_queue=0,
+        conversion_queue=0,
+        download_progress=100,
+        active_downloads=0,
+        active_conversions=0
+    )
+
+
+def schedule_downloads():
+    """Schedule downloads to run at specified times"""
+    # Configuration for scheduling
+    START_TIME = dt_time(0, 0)   # 00:00
+    END_TIME = dt_time(7, 0)     # 07:00
+    
+    while True:
+        current_time = datetime.now().time()
+        
+        # Check if we're in the allowed time window
+        if START_TIME <= current_time <= END_TIME:
+            try:
+                set_service_running()
+                print(f"🚀 Starting download session at {datetime.now().strftime('%H:%M:%S')}")
                 
                 
-                add_to_conversion_queue(conversion_file, priority)
-                print_queue_status()
+                # Run the main download process
+                main()
+                
+                set_service_completed()
+                print(f"✅ Download session completed at {datetime.now().strftime('%H:%M:%S')}")
+                
+                # Calculate next run time (next day at START_TIME)
+                next_run = datetime.now().replace(hour=START_TIME.hour, minute=START_TIME.minute, second=0, microsecond=0)
+                if current_time > START_TIME:
+                    next_run = next_run.replace(day=next_run.day + 1)
+                
+                set_service_waiting(next_run.isoformat())
+                
+                # Sleep until next day
+                sleep_seconds = (next_run - datetime.now()).total_seconds()
+                print(f"😴 Sleeping until next run at {next_run.strftime('%Y-%m-%d %H:%M:%S')}")
+                time.sleep(sleep_seconds)
+                
+            except Exception as e:
+                print(f"❌ Error during download session: {e}")
+                set_service_error()
+                # Sleep for 1 hour before retrying
+                time.sleep(3600)
+        else:
+            # We're outside the allowed time window
+            if current_time < START_TIME:
+                # Before start time today
+                next_run = datetime.now().replace(hour=START_TIME.hour, minute=START_TIME.minute, second=0, microsecond=0)
+            else:
+                # After end time today, schedule for tomorrow
+                next_run = datetime.now().replace(hour=START_TIME.hour, minute=START_TIME.minute, second=0, microsecond=0)
+                next_run = next_run.replace(day=next_run.day + 1)
             
             
-            # Create the NFO file
-            nfo_file_path = os.path.join(video_dir, "movie.nfo")
-            create_nfo_file(video, nfo_file_path)
+            set_service_waiting(next_run.isoformat())
+            
+            # Sleep until start time
+            sleep_seconds = (next_run - datetime.now()).total_seconds()
+            print(f"⏰ Waiting until {next_run.strftime('%Y-%m-%d %H:%M:%S')} to start downloads")
+            time.sleep(min(sleep_seconds, 3600))  # Check every hour maximum
 
 
-    # Fetch and process most popular videos worldwide (from multiple regions)
+
+# Fetch and process most popular videos worldwide (from multiple regions)
+def fetch_popular_videos_old():
+    """Old function kept for reference - this logic is now integrated into main()"""
     for region_code in REGION_CODES:
     for region_code in REGION_CODES:
         print(f"Fetching the most popular videos from {region_code}...")
         print(f"Fetching the most popular videos from {region_code}...")
         popular_videos = get_popular_videos(youtube, region_code)
         popular_videos = get_popular_videos(youtube, region_code)
@@ -467,7 +703,7 @@ def main():
                     file_path = os.path.join(video_dir, file)
                     file_path = os.path.join(video_dir, file)
                     try:
                     try:
                         # Quick check for problematic codecs
                         # Quick check for problematic codecs
-                        probe_cmd = ["ffprobe", "-v", "quiet", "-select_streams", "v:0", 
+                        probe_cmd = [FFPROBE_PATH, "-v", "quiet", "-select_streams", "v:0", 
                                    "-show_entries", "stream=codec_name", "-of", "csv=p=0", file_path]
                                    "-show_entries", "stream=codec_name", "-of", "csv=p=0", file_path]
                         result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
                         result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
                         codec = result.stdout.strip().lower()
                         codec = result.stdout.strip().lower()
@@ -487,7 +723,7 @@ def main():
             if needs_conversion and conversion_file:
             if needs_conversion and conversion_file:
                 # Determine priority based on video resolution
                 # Determine priority based on video resolution
                 try:
                 try:
-                    probe_cmd = ["ffprobe", "-v", "quiet", "-select_streams", "v:0", 
+                    probe_cmd = [FFPROBE_PATH, "-v", "quiet", "-select_streams", "v:0", 
                                "-show_entries", "stream=height", "-of", "csv=p=0", conversion_file]
                                "-show_entries", "stream=height", "-of", "csv=p=0", conversion_file]
                     result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
                     result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
                     height = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 1080
                     height = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 1080
@@ -508,13 +744,33 @@ def main():
     print("\n🎬 Final Conversion Queue Status:")
     print("\n🎬 Final Conversion Queue Status:")
     print_queue_status()
     print_queue_status()
     
     
+    # Final Home Assistant update
+    update_homeassistant_stats(
+        download_queue=0,
+        conversion_queue=conversion_queue.qsize(),
+        download_progress=100,
+        active_downloads=0,
+        active_conversions=conversion_stats['active_conversions']
+    )
+    
     queued_items = conversion_queue.qsize()
     queued_items = conversion_queue.qsize()
     if queued_items > 0:
     if queued_items > 0:
         print(f"⏳ {queued_items} videos still in conversion queue")
         print(f"⏳ {queued_items} videos still in conversion queue")
         print("💡 Conversions will continue in the background")
         print("💡 Conversions will continue in the background")
-        print("💡 You can monitor progress by checking the output folder")
+        print("💡 You can monitor progress in Home Assistant")
     else:
     else:
         print("✅ All conversions completed!")
         print("✅ All conversions completed!")
+    
+    print("🏠 Home Assistant integration will continue running in background")
+
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
-    main()
+    import sys
+    
+    # Check if we should run as a service with scheduling
+    if len(sys.argv) > 1 and sys.argv[1] == "--service":
+        print("🔄 Starting YouTube Predownloader Service with scheduling")
+        schedule_downloads()
+    else:
+        print("▶️ Running YouTube Predownloader once")
+        main()