Murad Jabir 1 年之前
父節點
當前提交
2ac131bc58
共有 3 個文件被更改,包括 471 次插入 和 55 次删除
  1. 171 0
      auth.py
  2. 78 16
      install.sh
  3. 222 39
      main.py

+ 171 - 0
auth.py

@@ -4,10 +4,160 @@ from google.oauth2 import service_account
 import os
 import pickle
 import json
+import subprocess
+import tempfile
+import time
+from pathlib import Path
 
 # OAuth 2.0 scopes
 SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"]
 
+def extract_cookies_from_browser():
+    """Extract cookies from browsers to bypass YouTube bot detection."""
+    print("🍪 Attempting to extract cookies from browsers...")
+    
+    # Try different browsers in order of preference
+    browsers = ['chrome', 'firefox', 'edge', 'safari', 'opera', 'brave']
+    cookies_file = "youtube_cookies.txt"
+    
+    for browser in browsers:
+        try:
+            print(f"  Trying {browser}...")
+            
+            # Use yt-dlp's built-in cookie extraction
+            cmd = [
+                'yt-dlp', 
+                '--cookies-from-browser', browser,
+                '--cookies', cookies_file,
+                '--simulate',
+                '--no-warnings',
+                'https://www.youtube.com/watch?v=dQw4w9WgXcQ'  # Test video
+            ]
+            
+            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
+            
+            if result.returncode == 0 and os.path.exists(cookies_file):
+                print(f"  ✅ Successfully extracted cookies from {browser}")
+                return cookies_file
+            else:
+                print(f"  ❌ Failed to extract from {browser}")
+                # Clean up any partial cookie file
+                if os.path.exists(cookies_file):
+                    os.remove(cookies_file)
+                    
+        except subprocess.TimeoutExpired:
+            print(f"  ⏰ Timeout extracting from {browser}")
+        except Exception as e:
+            print(f"  ❌ Error with {browser}: {e}")
+    
+    print("  ⚠️ Could not extract cookies from any browser")
+    return None
+
+def generate_youtube_cookies():
+    """Generate or update YouTube cookies for yt-dlp."""
+    cookies_file = "youtube_cookies.txt"
+    
+    # Check if cookies file already exists and is recent
+    if os.path.exists(cookies_file):
+        file_age = time.time() - os.path.getmtime(cookies_file)
+        if file_age < 3600:  # Less than 1 hour old
+            print(f"✅ Using existing cookies file (age: {file_age/60:.1f} minutes)")
+            return cookies_file
+        else:
+            print(f"🔄 Cookies file is {file_age/3600:.1f} hours old, refreshing...")
+    
+    # Try to extract fresh cookies
+    result = extract_cookies_from_browser()
+    if result:
+        return result
+    
+    # If extraction failed, try manual cookie creation
+    print("🔧 Attempting manual cookie setup...")
+    return create_manual_cookies()
+
+def create_manual_cookies():
+    """Create a basic cookie file for YouTube."""
+    cookies_file = "youtube_cookies.txt"
+    
+    # Create a basic Netscape-format cookie file
+    # This won't have real session cookies but may help with some requests
+    cookie_content = """# Netscape HTTP Cookie File
+# This is a generated file! Do not edit.
+
+.youtube.com	TRUE	/	FALSE	0	PREF	f1=50000000
+.youtube.com	TRUE	/	FALSE	0	VISITOR_INFO1_LIVE	
+.youtube.com	TRUE	/	TRUE	0	YSC	
+.google.com	TRUE	/	FALSE	0	NID	
+"""
+    
+    try:
+        with open(cookies_file, 'w') as f:
+            f.write(cookie_content)
+        print(f"📝 Created basic cookie file: {cookies_file}")
+        return cookies_file
+    except Exception as e:
+        print(f"❌ Failed to create cookie file: {e}")
+        return None
+
+def test_youtube_access():
+    """Test if YouTube access works with current authentication."""
+    print("🧪 Testing YouTube access...")
+    
+    cookies_file = "youtube_cookies.txt"
+    test_commands = [
+        # Test with cookies
+        {
+            'name': 'With Cookies',
+            'cmd': ['yt-dlp', '--cookies', cookies_file, '--simulate', '--print', 'title', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ']
+        },
+        # Test with browser extraction
+        {
+            'name': 'Browser Extraction', 
+            'cmd': ['yt-dlp', '--cookies-from-browser', 'chrome', '--simulate', '--print', 'title', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ']
+        },
+        # Test with user agent
+        {
+            'name': 'Custom User Agent',
+            'cmd': ['yt-dlp', '--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', '--simulate', '--print', 'title', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ']
+        }
+    ]
+    
+    for test in test_commands:
+        try:
+            print(f"  Testing: {test['name']}")
+            result = subprocess.run(test['cmd'], capture_output=True, text=True, timeout=20)
+            
+            if result.returncode == 0:
+                print(f"    ✅ Success: {result.stdout.strip()}")
+                return test['name']
+            else:
+                print(f"    ❌ Failed: {result.stderr[:100]}...")
+                
+        except subprocess.TimeoutExpired:
+            print(f"    ⏰ Timeout")
+        except Exception as e:
+            print(f"    ❌ Error: {e}")
+    
+    print("  ⚠️ All YouTube access tests failed")
+    return None
+
+def setup_youtube_access():
+    """Setup YouTube access with cookie authentication."""
+    print("🔧 Setting up YouTube access with cookie authentication...")
+    
+    # Generate cookies
+    cookies_file = generate_youtube_cookies()
+    
+    if cookies_file:
+        # Test the access
+        working_method = test_youtube_access()
+        if working_method:
+            print(f"✅ YouTube access working with: {working_method}")
+            return cookies_file
+    
+    print("⚠️ YouTube access setup incomplete - may encounter bot detection")
+    return None
+
 def get_service_account_token():
     """Authenticate using service account (no user interaction needed)."""
     service_account_file = "service_account.json"
@@ -107,13 +257,34 @@ if __name__ == "__main__":
     
     if "--interactive" in sys.argv:
         creds = get_token_interactive()
+    elif "--cookies" in sys.argv:
+        print("🍪 Setting up YouTube cookies...")
+        cookies_file = setup_youtube_access()
+        if cookies_file:
+            print(f"✅ Cookie setup complete: {cookies_file}")
+        else:
+            print("❌ Cookie setup failed")
+        sys.exit(0)
+    elif "--test" in sys.argv:
+        print("🧪 Testing YouTube access...")
+        working_method = test_youtube_access()
+        if working_method:
+            print(f"✅ YouTube access working with: {working_method}")
+        else:
+            print("❌ YouTube access not working")
+        sys.exit(0)
     else:
         creds = get_token_non_interactive()
         if not creds:
             print("\nTo authenticate interactively, run: python3 auth.py --interactive")
+            print("To setup YouTube cookies, run: python3 auth.py --cookies")
+            print("To test YouTube access, run: python3 auth.py --test")
     
     if creds:
         print("Authentication successful!")
+        # Also setup cookies when authenticating
+        print("\n🍪 Setting up YouTube cookies for bot detection bypass...")
+        setup_youtube_access()
     else:
         print("Authentication failed!")
         sys.exit(1)

+ 78 - 16
install.sh

@@ -48,6 +48,17 @@ echo -e "${BLUE}📦 Installing system dependencies...${NC}"
 apt update
 apt install -y python3 python3-venv python3-pip ffmpeg git curl
 
+# Install Intel GPU acceleration dependencies
+echo -e "${BLUE}🚀 Installing Intel GPU acceleration dependencies...${NC}"
+apt install -y intel-media-va-driver vainfo mesa-va-drivers
+echo -e "${GREEN}✅ GPU acceleration dependencies installed${NC}"
+
+# Configure GPU permissions
+echo -e "${BLUE}🔧 Configuring GPU permissions...${NC}"
+usermod -a -G video $SERVICE_USER
+usermod -a -G render $SERVICE_USER
+echo -e "${GREEN}✅ GPU permissions configured${NC}"
+
 # Create service user
 echo -e "${BLUE}👤 Creating service user...${NC}"
 if ! id "$SERVICE_USER" &>/dev/null; then
@@ -127,6 +138,10 @@ REGION_CODES = ["US", "GB", "LU", "LK"]
 MAX_CONCURRENT_CONVERSIONS = 2
 CONVERSION_QUEUE_SIZE = 50
 
+# GPU acceleration settings
+GPU_ACCELERATION_ENABLED = True
+INTEL_VAAPI_DEVICE = "/dev/dri/renderD128"
+
 # Home Assistant MQTT settings (optional)
 HOMEASSISTANT_ENABLED = True
 MQTT_BROKER = "192.168.1.100"  # Your Home Assistant IP
@@ -164,6 +179,8 @@ PrivateTmp=true
 ProtectSystem=strict
 ProtectHome=true
 ReadWritePaths=$INSTALL_DIR $LOG_DIR /media
+DeviceAllow=/dev/dri/renderD128 rw
+DeviceAllow=/dev/dri/card1 rw
 ProtectKernelTunables=true
 ProtectKernelModules=true
 ProtectControlGroups=true
@@ -248,18 +265,59 @@ case "$1" in
         echo "Restarting service..."
         systemctl restart $SERVICE_NAME
         ;;
+    gpu-test)
+        echo "Testing GPU acceleration capabilities..."
+        sudo -u youtube-dl $INSTALL_DIR/venv/bin/python -c "
+import subprocess
+try:
+    result = subprocess.run(['vainfo', '--display', 'drm', '--device', '/dev/dri/renderD128'], 
+                          capture_output=True, text=True, timeout=10)
+    if result.returncode == 0:
+        print('✅ Intel VAAPI GPU acceleration available')
+        if 'VAProfileH264High' in result.stdout:
+            print('✅ H.264 hardware decode/encode supported')
+        if 'VAProfileVP9Profile0' in result.stdout:
+            print('✅ VP9 hardware decode supported')
+        if 'VAProfileHEVCMain' in result.stdout:
+            print('✅ HEVC hardware decode supported')
+    else:
+        print('❌ GPU acceleration not available')
+except Exception as e:
+    print(f'❌ Error testing GPU: {e}')
+"
+        ;;
+    performance)
+        echo "Showing performance statistics..."
+        sudo -u youtube-dl $INSTALL_DIR/venv/bin/python -c "
+import psutil
+import subprocess
+print(f'CPU Usage: {psutil.cpu_percent()}%')
+print(f'Memory Usage: {psutil.virtual_memory().percent}%')
+print(f'Disk Usage: {psutil.disk_usage(\"/media\").percent}%')
+try:
+    result = subprocess.run(['nvidia-smi'], capture_output=True, text=True)
+    if result.returncode == 0:
+        print('NVIDIA GPU detected')
+    else:
+        print('Using Intel integrated graphics')
+except:
+    print('Using Intel integrated graphics')
+"
+        ;;
     *)
-        echo "Usage: $0 {start|stop|restart|status|logs|logs-file|config|update}"
+        echo "Usage: $0 {start|stop|restart|status|logs|logs-file|config|update|gpu-test|performance}"
         echo ""
         echo "Commands:"
-        echo "  start      - Start the service"
-        echo "  stop       - Stop the service"
-        echo "  restart    - Restart the service"
-        echo "  status     - Show service status"
-        echo "  logs       - Show live system logs"
-        echo "  logs-file  - Show live application logs"
-        echo "  config     - Edit configuration"
-        echo "  update     - Update yt-dlp"
+        echo "  start        - Start the service"
+        echo "  stop         - Stop the service"
+        echo "  restart      - Restart the service"
+        echo "  status       - Show service status"
+        echo "  logs         - Show live system logs"
+        echo "  logs-file    - Show live application logs"
+        echo "  config       - Edit configuration"
+        echo "  update       - Update yt-dlp"
+        echo "  gpu-test     - Test GPU acceleration"
+        echo "  performance  - Show system performance"
         exit 1
         ;;
 esac
@@ -279,17 +337,21 @@ echo "4. Check status: youtube-predownloader status"
 echo "5. View logs: youtube-predownloader logs"
 echo
 echo -e "${BLUE}🛠️ Management Commands:${NC}"
-echo "  youtube-predownloader start    - Start service"
-echo "  youtube-predownloader stop     - Stop service"
-echo "  youtube-predownloader restart  - Restart service"
-echo "  youtube-predownloader status   - Check status"
-echo "  youtube-predownloader logs     - View logs"
-echo "  youtube-predownloader config   - Edit settings"
-echo "  youtube-predownloader update   - Update yt-dlp"
+echo "  youtube-predownloader start       - Start service"
+echo "  youtube-predownloader stop        - Stop service"
+echo "  youtube-predownloader restart     - Restart service"
+echo "  youtube-predownloader status      - Check status"
+echo "  youtube-predownloader logs        - View logs"
+echo "  youtube-predownloader config      - Edit settings"
+echo "  youtube-predownloader update      - Update yt-dlp"
+echo "  youtube-predownloader gpu-test    - Test GPU acceleration"
+echo "  youtube-predownloader performance - Show performance stats"
 echo
 echo -e "${YELLOW}⚠️ Important:${NC}"
 echo "- Edit $INSTALL_DIR/config.py to customize settings"
 echo "- Place your YouTube API credentials in $INSTALL_DIR/"
 echo "- Service will run continuously and handle scheduling internally"
 echo "- Logs are available at $LOG_DIR/youtube-predownloader.log"
+echo "- GPU acceleration is enabled for Intel integrated graphics"
+echo "- Run 'youtube-predownloader gpu-test' to verify GPU support"
 echo

+ 222 - 39
main.py

@@ -14,7 +14,7 @@ from googleapiclient.discovery import build
 import subprocess
 from google.auth.transport.requests import Request
 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, setup_youtube_access
 
 # Home Assistant Integration
 try:
@@ -235,6 +235,63 @@ def update_yt_dlp():
         logger.debug(f"yt-dlp update error: {e.stderr}")
         raise
 
+def get_youtube_cookie_args():
+    """Get YouTube cookie arguments for yt-dlp to bypass bot detection."""
+    logger = logging.getLogger(__name__)
+    
+    cookies_file = "youtube_cookies.txt"
+    cookie_args = []
+    
+    # Check if cookies file exists and is recent (less than 24 hours)
+    if os.path.exists(cookies_file):
+        file_age = time.time() - os.path.getmtime(cookies_file)
+        if file_age < 86400:  # 24 hours
+            logger.debug(f"Using existing cookies file (age: {file_age/3600:.1f} hours)")
+            cookie_args = ["--cookies", cookies_file]
+        else:
+            logger.debug("Cookies file is old, will try to refresh")
+    
+    # If no cookie file or it's old, try to setup fresh cookies
+    if not cookie_args:
+        try:
+            logger.debug("Setting up YouTube cookie authentication...")
+            fresh_cookies = setup_youtube_access()
+            if fresh_cookies and os.path.exists(fresh_cookies):
+                cookie_args = ["--cookies", fresh_cookies]
+                logger.debug("✅ Fresh cookies obtained")
+            else:
+                logger.debug("⚠️ Could not obtain fresh cookies")
+        except Exception as e:
+            logger.debug(f"Cookie setup failed: {e}")
+    
+    # Fallback: try browser extraction as last resort
+    if not cookie_args:
+        logger.debug("Trying browser cookie extraction as fallback...")
+        browser_options = ['chrome', 'firefox', 'edge']
+        for browser in browser_options:
+            try:
+                # Test if browser cookies work
+                test_cmd = ['yt-dlp', '--cookies-from-browser', browser, '--simulate', '--no-warnings', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ']
+                result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=15)
+                if result.returncode == 0:
+                    cookie_args = ["--cookies-from-browser", browser]
+                    logger.debug(f"✅ Using {browser} browser cookies")
+                    break
+            except:
+                continue
+    
+    # Add additional anti-bot arguments
+    anti_bot_args = [
+        "--user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
+        "--sleep-interval", "1",
+        "--max-sleep-interval", "3", 
+        "--retry-sleep", "linear=2:5",
+        "--fragment-retries", "3",
+        "--socket-timeout", "30"
+    ]
+    
+    return cookie_args + anti_bot_args
+
 def authenticate_youtube_api():
     """Authenticate using our enhanced auth system (tries non-interactive first)."""
     logger = logging.getLogger(__name__)
@@ -364,9 +421,13 @@ def list_available_formats(video_id):
     logger = logging.getLogger(__name__)
     
     try:
+        # Get cookie arguments for bot detection bypass
+        cookie_args = get_youtube_cookie_args()
+        
         command = [
             "yt-dlp",
             "--list-formats",
+        ] + cookie_args + [
             f"https://www.youtube.com/watch?v={video_id}"
         ]
         
@@ -397,9 +458,13 @@ def download_video(video_id, output_path, video_title="Unknown"):
         # First, check what format would be downloaded to determine compatibility
         logger.debug(f"Checking video format compatibility for: {video_title}")
         
+        # Get cookie arguments for bot detection bypass
+        cookie_args = get_youtube_cookie_args()
+        
         simulate_command = [
             "yt-dlp", "--simulate", "--print", "%(format_id)s|%(vcodec)s|%(height)s|%(ext)s",
             "-f", "(bestvideo[height>=2160][vcodec~='^(avc|h264|hevc|h265)']+bestaudio)/(bestvideo[height>=2160]+bestaudio)/(bestvideo[height>=1440]+bestaudio)/(bestvideo[height>=1080]+bestaudio)/best",
+        ] + cookie_args + [
             f"https://www.youtube.com/watch?v={video_id}"
         ]
         
@@ -452,7 +517,7 @@ def download_video(video_id, output_path, video_title="Unknown"):
         )
         
         # 4K-prioritized approach: Try Apple TV compatible 4K first, then any 4K, then lower resolutions
-        command = [
+        base_command = [
             "yt-dlp",
             "-f", "(bestvideo[height>=2160][vcodec~='^(avc|h264|hevc|h265)']+bestaudio)/(bestvideo[height>=2160]+bestaudio)/(bestvideo[height>=1440]+bestaudio)/(bestvideo[height>=1080]+bestaudio)/best",
             "--merge-output-format", "mp4",
@@ -460,6 +525,11 @@ def download_video(video_id, output_path, video_title="Unknown"):
             "--newline",  # Better for parsing progress
             "--verbose" if logger.isEnabledFor(logging.DEBUG) else "--no-warnings",
             "--write-info-json",  # Write metadata for analysis
+        ]
+        
+        # Add cookie authentication to bypass bot detection
+        cookie_args = get_youtube_cookie_args()
+        command = base_command + cookie_args + [
             f"https://www.youtube.com/watch?v={video_id}",
             "-o", output_template
         ]
@@ -782,7 +852,7 @@ def sanitize_filename(filename):
     return sanitized
 
 def test_vaapi_support():
-    """Test if Intel VAAPI hardware acceleration is available."""
+    """Test if Intel VAAPI/QSV hardware acceleration is available for both encoding and decoding."""
     logger = logging.getLogger(__name__)
     
     try:
@@ -800,19 +870,76 @@ def test_vaapi_support():
         result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=10)
         hevc_vaapi_available = result.returncode == 0
         
-        if h264_vaapi_available and hevc_vaapi_available:
-            logger.info("🚀 Intel VAAPI hardware acceleration available (H.264 + HEVC)")
-            return True, True
-        elif h264_vaapi_available:
-            logger.info("🚀 Intel VAAPI hardware acceleration available (H.264 only)")
-            return True, False
+        # Test H.264 VAAPI decoding - create a small test file and try to decode it
+        h264_decode_available = False
+        try:
+            # Create a small test H.264 file
+            create_test_cmd = [FFMPEG_PATH, "-hide_banner", "-f", "lavfi", "-i", "testsrc=duration=1:size=320x240:rate=1", 
+                              "-c:v", "libx264", "-frames:v", "5", "-f", "mp4", "/tmp/vaapi_test.mp4"]
+            subprocess.run(create_test_cmd, capture_output=True, text=True, timeout=10, check=True)
+            
+            # Test hardware decoding
+            decode_test_cmd = [FFMPEG_PATH, "-hide_banner", "-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128",
+                              "-i", "/tmp/vaapi_test.mp4", "-f", "null", "-"]
+            result = subprocess.run(decode_test_cmd, capture_output=True, text=True, timeout=10)
+            h264_decode_available = result.returncode == 0
+            
+            # Clean up test file
+            try:
+                os.remove("/tmp/vaapi_test.mp4")
+            except:
+                pass
+        except:
+            pass
+        
+        # Test VP9 VAAPI decoding capability (Intel HD Graphics 630 supports VP9 via VAAPI)
+        vp9_vaapi_decode_available = False
+        try:
+            # Create a small VP9 test file
+            create_vp9_cmd = [FFMPEG_PATH, "-hide_banner", "-f", "lavfi", "-i", "testsrc=duration=1:size=320x240:rate=1", 
+                             "-c:v", "libvpx-vp9", "-frames:v", "5", "-f", "webm", "/tmp/vp9_test.webm"]
+            result = subprocess.run(create_vp9_cmd, capture_output=True, text=True, timeout=15)
+            
+            if result.returncode == 0:
+                # Test VP9 hardware decoding with VAAPI
+                decode_vp9_cmd = [FFMPEG_PATH, "-hide_banner", "-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128",
+                                 "-i", "/tmp/vp9_test.webm", "-f", "null", "-"]
+                result = subprocess.run(decode_vp9_cmd, capture_output=True, text=True, timeout=10)
+                vp9_vaapi_decode_available = result.returncode == 0
+                
+                # Clean up test file
+                try:
+                    os.remove("/tmp/vp9_test.webm")
+                except:
+                    pass
+        except:
+            pass
+        
+        # AV1 is not supported on Intel HD Graphics 630, so we'll skip it
+        av1_decode_available = False
+        
+        # Log results with comprehensive hardware support info
+        hw_support = []
+        if h264_vaapi_available:
+            hw_support.append("H.264 encode")
+        if hevc_vaapi_available:
+            hw_support.append("HEVC encode")
+        if h264_decode_available:
+            hw_support.append("H.264 decode")
+        if vp9_vaapi_decode_available:
+            hw_support.append("VP9 decode")
+            
+        if hw_support:
+            logger.info(f"🚀 Intel hardware acceleration available: {', '.join(hw_support)}")
         else:
-            logger.info("⚠️ Intel VAAPI hardware acceleration not available, falling back to software encoding")
-            return False, False
+            logger.info("⚠️ Intel hardware acceleration not available, falling back to software encoding")
+            
+        return (h264_vaapi_available, hevc_vaapi_available, h264_decode_available, 
+                av1_decode_available, vp9_vaapi_decode_available)
             
     except Exception as e:
-        logger.warning(f"Could not test VAAPI support: {e}")
-        return False, False
+        logger.warning(f"Could not test hardware acceleration support: {e}")
+        return False, False, False, False, False
 
 def convert_to_apple_tv_compatible(input_file):
     """Convert a video to Apple TV 4K compatible format with Intel VAAPI hardware acceleration."""
@@ -840,7 +967,7 @@ def convert_to_apple_tv_compatible(input_file):
     logger.debug(f"Output file: {mp4_file}")
     
     # Test VAAPI support
-    vaapi_h264_available, vaapi_hevc_available = test_vaapi_support()
+    vaapi_h264_available, vaapi_hevc_available, vaapi_decode_available, av1_decode_available, vp9_vaapi_decode_available = test_vaapi_support()
     
     # Update Home Assistant
     update_homeassistant_stats(
@@ -863,6 +990,7 @@ def convert_to_apple_tv_compatible(input_file):
         video_stream = next((s for s in video_info['streams'] if s['codec_type'] == 'video'), None)
         is_4k = video_stream and int(video_stream.get('height', 0)) >= 2160
         is_high_res = video_stream and int(video_stream.get('height', 0)) >= 1080
+        input_codec = video_stream.get('codec_name', 'unknown').lower() if video_stream else 'unknown'
         
         if video_stream:
             height = video_stream.get('height', 'unknown')
@@ -874,13 +1002,36 @@ def convert_to_apple_tv_compatible(input_file):
         logger.warning(f"Could not probe video properties: {e}, using default settings")
         is_4k = False
         is_high_res = True
+        input_codec = 'unknown'
+    
+    # Intel VAAPI optimized encoding with hardware decoding based on source quality and hardware support:
+    hwaccel_args = []
+    filter_args = []
+    
+    # Determine optimal hardware decoding strategy based on input codec
+    if input_codec == 'av1' and av1_decode_available:
+        # AV1 is not supported on Intel HD Graphics 630, fallback to software
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"Using software decoding with GPU upload for AV1 input (no hardware AV1 support)")
+    elif input_codec in ['vp9', 'vp09'] and vp9_vaapi_decode_available:
+        # Use Intel VAAPI for VP9 hardware decoding 
+        hwaccel_args = ["-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128"]
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"🚀 Using Intel VAAPI hardware decoding for VP9 input")
+    elif input_codec in ['h264', 'avc'] and vaapi_decode_available:
+        # Use Intel VAAPI for H.264 hardware decoding (decode + encode on same device)
+        hwaccel_args = ["-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128"]
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"🚀 Using Intel VAAPI hardware decoding for H.264 input")
+    else:
+        # Fallback: CPU decode with GPU upload for compatibility
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"Using software decoding with GPU upload for {input_codec} input")
     
-    # Intel VAAPI optimized encoding based on source quality and hardware support:
     if is_4k and vaapi_hevc_available:
         # 4K content with VAAPI HEVC: Use hardware-accelerated H.265
         codec_args = [
-            "-vaapi_device", "/dev/dri/renderD128",  # VAAPI device
-            "-vf", "format=nv12,hwupload",          # Upload to GPU memory
+            *filter_args,
             "-c:v", "hevc_vaapi",                   # Intel VAAPI HEVC encoder
             "-qp", "20",                            # Quality parameter (lower = better)
             "-rc_mode", "CQP",                      # Constant Quality mode
@@ -890,8 +1041,7 @@ def convert_to_apple_tv_compatible(input_file):
         # 4K/1080p content with VAAPI H.264: Use hardware-accelerated H.264
         quality = "20" if is_4k else "22"  # Slightly lower quality for 1080p
         codec_args = [
-            "-vaapi_device", "/dev/dri/renderD128",  # VAAPI device
-            "-vf", "format=nv12,hwupload",          # Upload to GPU memory
+            *filter_args,
             "-c:v", "h264_vaapi",                   # Intel VAAPI H.264 encoder
             "-qp", quality,                         # Quality parameter
             "-rc_mode", "CQP",                      # Constant Quality mode
@@ -908,6 +1058,7 @@ def convert_to_apple_tv_compatible(input_file):
             "-level", "5.1",                # Level 5.1 supports 4K
             "-pix_fmt", "yuv420p",          # Standard compatibility
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("⚠️ Using software H.265 encoding for 4K content (VAAPI not available)")
     elif is_high_res:
         # 1080p content without VAAPI: Use software H.264
@@ -918,6 +1069,7 @@ def convert_to_apple_tv_compatible(input_file):
             "-crf", "21",                   # Good quality for 1080p
             "-level", "4.1",                # Level 4.1 supports 1080p
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("⚠️ Using software H.264 encoding for 1080p content (VAAPI not available)")
     else:
         # Lower resolution: Use software H.264 with faster settings
@@ -928,17 +1080,20 @@ def convert_to_apple_tv_compatible(input_file):
             "-crf", "23",                   # Standard quality
             "-level", "3.1",                # Level 3.1 for lower res
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("Using software H.264 encoding for lower resolution content")
     
     # Add progress reporting to FFmpeg command
     command = [
-        FFMPEG_PATH, "-i", input_file,
-        *codec_args,
-        "-c:a", "aac",              # AAC audio codec
-        "-b:a", "192k",             # Higher audio bitrate for better quality
-        "-movflags", "+faststart",  # Optimize for streaming/quick playback
-        "-progress", "pipe:1",      # Output progress to stdout
-        "-y",                       # Overwrite output file if exists
+        FFMPEG_PATH,
+        *hwaccel_args,                  # Hardware acceleration args (decode)
+        "-i", input_file,
+        *codec_args,                    # Video codec args (encode + filters)
+        "-c:a", "aac",                  # AAC audio codec
+        "-b:a", "192k",                 # Higher audio bitrate for better quality
+        "-movflags", "+faststart",      # Optimize for streaming/quick playback
+        "-progress", "pipe:1",          # Output progress to stdout
+        "-y",                           # Overwrite output file if exists
         mp4_file
     ]
     
@@ -1095,7 +1250,7 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
     temp_output = f"{base_name}.converting{ext}"
     
     # Test VAAPI support
-    vaapi_h264_available, vaapi_hevc_available = test_vaapi_support()
+    vaapi_h264_available, vaapi_hevc_available, vaapi_decode_available, av1_decode_available, vp9_vaapi_decode_available = test_vaapi_support()
     
     # Update Home Assistant
     update_homeassistant_stats(
@@ -1118,6 +1273,7 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
         video_stream = next((s for s in video_info['streams'] if s['codec_type'] == 'video'), None)
         is_4k = video_stream and int(video_stream.get('height', 0)) >= 2160
         is_high_res = video_stream and int(video_stream.get('height', 0)) >= 1080
+        input_codec = video_stream.get('codec_name', 'unknown').lower() if video_stream else 'unknown'
         
         if video_stream:
             height = video_stream.get('height', 'unknown')
@@ -1129,13 +1285,36 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
         logger.warning(f"Could not probe video properties: {e}, using default settings")
         is_4k = False
         is_high_res = True
+        input_codec = 'unknown'
+    
+    # Intel VAAPI optimized encoding with hardware decoding based on source quality and hardware support
+    hwaccel_args = []
+    filter_args = []
+    
+    # Determine optimal hardware decoding strategy based on input codec
+    if input_codec == 'av1' and av1_decode_available:
+        # AV1 is not supported on Intel HD Graphics 630, fallback to software
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"Using software decoding with GPU upload for AV1 input (no hardware AV1 support)")
+    elif input_codec in ['vp9', 'vp09'] and vp9_vaapi_decode_available:
+        # Use Intel VAAPI for VP9 hardware decoding 
+        hwaccel_args = ["-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128"]
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"🚀 Using Intel VAAPI hardware decoding for VP9 input")
+    elif input_codec in ['h264', 'avc'] and vaapi_decode_available:
+        # Use Intel VAAPI for H.264 hardware decoding (decode + encode on same device)
+        hwaccel_args = ["-hwaccel", "vaapi", "-hwaccel_device", "/dev/dri/renderD128"]
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"🚀 Using Intel VAAPI hardware decoding for H.264 input")
+    else:
+        # Fallback: CPU decode with GPU upload for compatibility
+        filter_args = ["-vaapi_device", "/dev/dri/renderD128", "-vf", "format=nv12,hwupload"]
+        logger.info(f"Using software decoding with GPU upload for {input_codec} input")
     
-    # Intel VAAPI optimized encoding based on source quality and hardware support
     if is_4k and vaapi_hevc_available:
         # 4K content with VAAPI HEVC: Use hardware-accelerated H.265
         codec_args = [
-            "-vaapi_device", "/dev/dri/renderD128",  # VAAPI device
-            "-vf", "format=nv12,hwupload",          # Upload to GPU memory
+            *filter_args,
             "-c:v", "hevc_vaapi",                   # Intel VAAPI HEVC encoder
             "-qp", "20",                            # Quality parameter (lower = better)
             "-rc_mode", "CQP",                      # Constant Quality mode
@@ -1145,8 +1324,7 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
         # 4K/1080p content with VAAPI H.264: Use hardware-accelerated H.264
         quality = "20" if is_4k else "22"  # Slightly lower quality for 1080p
         codec_args = [
-            "-vaapi_device", "/dev/dri/renderD128",  # VAAPI device
-            "-vf", "format=nv12,hwupload",          # Upload to GPU memory
+            *filter_args,
             "-c:v", "h264_vaapi",                   # Intel VAAPI H.264 encoder
             "-qp", quality,                         # Quality parameter
             "-rc_mode", "CQP",                      # Constant Quality mode
@@ -1163,6 +1341,7 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
             "-level", "5.1",                # Level 5.1 supports 4K
             "-pix_fmt", "yuv420p",          # Standard compatibility
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("⚠️ Using software H.265 encoding for 4K content (VAAPI not available)")
     elif is_high_res:
         # 1080p content without VAAPI: Use software H.264
@@ -1173,6 +1352,7 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
             "-crf", "21",                   # Good quality for 1080p
             "-level", "4.1",                # Level 4.1 supports 1080p
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("⚠️ Using software H.264 encoding for 1080p content (VAAPI not available)")
     else:
         # Lower resolution: Use software H.264 with faster settings
@@ -1183,17 +1363,20 @@ def convert_to_apple_tv_compatible_with_target(input_file, target_file):
             "-crf", "23",                   # Standard quality
             "-level", "3.1",                # Level 3.1 for lower res
         ]
+        hwaccel_args = []  # No hardware acceleration
         logger.info("Using software H.264 encoding for lower resolution content")
     
     # Add progress reporting to FFmpeg command
     command = [
-        FFMPEG_PATH, "-i", input_file,
-        *codec_args,
-        "-c:a", "aac",              # AAC audio codec
-        "-b:a", "192k",             # Higher audio bitrate for better quality
-        "-movflags", "+faststart",  # Optimize for streaming/quick playback
-        "-progress", "pipe:1",      # Output progress to stdout
-        "-y",                       # Overwrite output file if exists
+        FFMPEG_PATH,
+        *hwaccel_args,                  # Hardware acceleration args (decode)
+        "-i", input_file,
+        *codec_args,                    # Video codec args (encode + filters)
+        "-c:a", "aac",                  # AAC audio codec
+        "-b:a", "192k",                 # Higher audio bitrate for better quality
+        "-movflags", "+faststart",      # Optimize for streaming/quick playback
+        "-progress", "pipe:1",          # Output progress to stdout
+        "-y",                           # Overwrite output file if exists
         temp_output
     ]