| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- from google_auth_oauthlib.flow import InstalledAppFlow
- from google.auth.transport.requests import Request
- 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"
-
- if not os.path.exists(service_account_file):
- print(f"Service account file {service_account_file} not found.")
- print("To use service account authentication:")
- print("1. Go to Google Cloud Console")
- print("2. Navigate to IAM & Admin > Service Accounts")
- print("3. Create a new service account")
- print("4. Download the JSON key file as 'service_account.json'")
- return None
-
- try:
- creds = service_account.Credentials.from_service_account_file(
- service_account_file, scopes=SCOPES)
- print("Service account authentication successful!")
- return creds
- except Exception as e:
- print(f"Service account authentication failed: {e}")
- return None
- def get_token_interactive():
- """Perform OAuth authentication with user interaction."""
- creds = None
- token_file = "youtube_token.pickle"
- # Check if token file exists
- if os.path.exists(token_file):
- with open(token_file, "rb") as token:
- creds = pickle.load(token)
- # If no valid credentials, authenticate user
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- try:
- creds.refresh(Request())
- print("Token refreshed successfully!")
- except Exception as e:
- print(f"Token refresh failed: {e}")
- creds = None
-
- if not creds:
- print("Starting interactive authentication...")
- flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", SCOPES)
- creds = flow.run_local_server(port=8080)
-
- # Save the credentials to a file
- with open(token_file, "wb") as token:
- pickle.dump(creds, token)
- print(f"Token saved to {token_file}")
- else:
- print("Token already exists and is valid.")
-
- return creds
- def get_token_non_interactive():
- """Try non-interactive authentication methods first."""
- # Try service account first
- creds = get_service_account_token()
- if creds:
- return creds
-
- # Try existing saved token
- token_file = "youtube_token.pickle"
- if os.path.exists(token_file):
- try:
- with open(token_file, "rb") as token:
- creds = pickle.load(token)
-
- if creds and creds.valid:
- print("Using existing valid token.")
- return creds
- elif creds and creds.expired and creds.refresh_token:
- try:
- creds.refresh(Request())
- print("Token refreshed successfully!")
- # Save refreshed token
- with open(token_file, "wb") as token:
- pickle.dump(creds, token)
- return creds
- except Exception as e:
- print(f"Token refresh failed: {e}")
- except Exception as e:
- print(f"Error loading saved token: {e}")
-
- print("No valid non-interactive authentication method available.")
- print("Run with --interactive flag or set up service account authentication.")
- return None
- def get_token():
- """Main authentication function - tries non-interactive first."""
- return get_token_non_interactive()
- if __name__ == "__main__":
- import sys
-
- 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)
|