auth.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from google_auth_oauthlib.flow import InstalledAppFlow
  2. from google.auth.transport.requests import Request
  3. from google.oauth2 import service_account
  4. import os
  5. import pickle
  6. import json
  7. import sqlite3
  8. import subprocess
  9. import shutil
  10. import tempfile
  11. from pathlib import Path
  12. from datetime import datetime
  13. import logging
  14. # OAuth 2.0 scopes
  15. SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"]
  16. # Configure logging
  17. logger = logging.getLogger(__name__)
  18. def extract_chrome_cookies(output_file="youtube_cookies.txt"):
  19. """Extract YouTube cookies from Chrome browser."""
  20. try:
  21. # Common Chrome cookie database locations
  22. chrome_paths = [
  23. Path.home() / ".config/google-chrome/Default/Cookies",
  24. Path.home() / ".config/google-chrome/Profile 1/Cookies",
  25. Path.home() / ".config/chromium/Default/Cookies",
  26. Path.home() / "snap/chromium/common/chromium/Default/Cookies",
  27. Path.home() / ".var/app/com.google.Chrome/config/google-chrome/Default/Cookies",
  28. ]
  29. # Find existing Chrome cookies database
  30. chrome_cookies_db = None
  31. for path in chrome_paths:
  32. if path.exists():
  33. chrome_cookies_db = path
  34. logger.info(f"Found Chrome cookies database: {chrome_cookies_db}")
  35. break
  36. if not chrome_cookies_db:
  37. logger.warning("Chrome cookies database not found")
  38. return False
  39. # Use yt-dlp to extract cookies directly from browser
  40. try:
  41. cmd = ['yt-dlp', '--cookies-from-browser', 'chrome', '--print-to-file', 'cookies', output_file, '--no-download', 'https://www.youtube.com']
  42. result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
  43. if result.returncode == 0:
  44. logger.info(f"Successfully extracted Chrome cookies to {output_file}")
  45. return True
  46. else:
  47. logger.error(f"yt-dlp cookie extraction failed: {result.stderr}")
  48. return False
  49. except subprocess.TimeoutExpired:
  50. logger.error("Cookie extraction timed out")
  51. return False
  52. except Exception as e:
  53. logger.error(f"Error running yt-dlp cookie extraction: {e}")
  54. return False
  55. except Exception as e:
  56. logger.error(f"Error extracting Chrome cookies: {e}")
  57. return False
  58. def check_browser_cookies():
  59. """Check which browsers have accessible cookies for YouTube."""
  60. browsers = ['chrome', 'chromium', 'firefox', 'brave', 'edge']
  61. available_browsers = []
  62. for browser in browsers:
  63. try:
  64. # Test if browser cookies are accessible
  65. cmd = ['yt-dlp', '--cookies-from-browser', browser, '--simulate', '--quiet', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ']
  66. result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
  67. if result.returncode == 0:
  68. available_browsers.append(browser)
  69. logger.info(f"Browser {browser} has accessible cookies")
  70. else:
  71. logger.debug(f"Browser {browser} cookies not accessible: {result.stderr}")
  72. except (subprocess.TimeoutExpired, subprocess.SubprocessError) as e:
  73. logger.debug(f"Error checking {browser} cookies: {e}")
  74. continue
  75. return available_browsers
  76. def update_cookies_from_browser(browser='chrome', output_file="youtube_cookies.txt"):
  77. """Update cookies file from specified browser."""
  78. try:
  79. logger.info(f"Updating cookies from {browser} browser...")
  80. # Use yt-dlp to extract cookies from browser
  81. cmd = ['yt-dlp', '--cookies-from-browser', browser, '--print-to-file', 'cookies', output_file, '--no-download', 'https://www.youtube.com']
  82. result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
  83. if result.returncode == 0:
  84. logger.info(f"Successfully updated cookies from {browser} to {output_file}")
  85. # Verify the cookies file was created and has content
  86. cookies_path = Path(output_file)
  87. if cookies_path.exists() and cookies_path.stat().st_size > 0:
  88. logger.info(f"Cookies file created: {cookies_path} ({cookies_path.stat().st_size} bytes)")
  89. return True
  90. else:
  91. logger.warning("Cookies file was not created or is empty")
  92. return False
  93. else:
  94. logger.error(f"Failed to extract cookies from {browser}: {result.stderr}")
  95. return False
  96. except subprocess.TimeoutExpired:
  97. logger.error("Cookie extraction timed out")
  98. return False
  99. except Exception as e:
  100. logger.error(f"Error updating cookies from browser: {e}")
  101. return False
  102. def get_service_account_token():
  103. """Authenticate using service account (no user interaction needed)."""
  104. service_account_file = "service_account.json"
  105. if not os.path.exists(service_account_file):
  106. print(f"Service account file {service_account_file} not found.")
  107. print("To use service account authentication:")
  108. print("1. Go to Google Cloud Console")
  109. print("2. Navigate to IAM & Admin > Service Accounts")
  110. print("3. Create a new service account")
  111. print("4. Download the JSON key file as 'service_account.json'")
  112. return None
  113. try:
  114. creds = service_account.Credentials.from_service_account_file(
  115. service_account_file, scopes=SCOPES)
  116. print("Service account authentication successful!")
  117. return creds
  118. except Exception as e:
  119. print(f"Service account authentication failed: {e}")
  120. return None
  121. def get_token_interactive():
  122. """Perform OAuth authentication with user interaction."""
  123. creds = None
  124. token_file = "youtube_token.pickle"
  125. # Check if token file exists
  126. if os.path.exists(token_file):
  127. with open(token_file, "rb") as token:
  128. creds = pickle.load(token)
  129. # If no valid credentials, authenticate user
  130. if not creds or not creds.valid:
  131. if creds and creds.expired and creds.refresh_token:
  132. try:
  133. creds.refresh(Request())
  134. print("Token refreshed successfully!")
  135. except Exception as e:
  136. print(f"Token refresh failed: {e}")
  137. creds = None
  138. if not creds:
  139. print("Starting interactive authentication...")
  140. flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", SCOPES)
  141. creds = flow.run_local_server(port=8080)
  142. # Save the credentials to a file
  143. with open(token_file, "wb") as token:
  144. pickle.dump(creds, token)
  145. print(f"Token saved to {token_file}")
  146. else:
  147. print("Token already exists and is valid.")
  148. return creds
  149. def get_token_non_interactive():
  150. """Try non-interactive authentication methods first."""
  151. # Try service account first
  152. creds = get_service_account_token()
  153. if creds:
  154. return creds
  155. # Try existing saved token
  156. token_file = "youtube_token.pickle"
  157. if os.path.exists(token_file):
  158. try:
  159. with open(token_file, "rb") as token:
  160. creds = pickle.load(token)
  161. if creds and creds.valid:
  162. print("Using existing valid token.")
  163. return creds
  164. elif creds and creds.expired and creds.refresh_token:
  165. try:
  166. creds.refresh(Request())
  167. print("Token refreshed successfully!")
  168. # Save refreshed token
  169. with open(token_file, "wb") as token:
  170. pickle.dump(creds, token)
  171. return creds
  172. except Exception as e:
  173. print(f"Token refresh failed: {e}")
  174. except Exception as e:
  175. print(f"Error loading saved token: {e}")
  176. print("No valid non-interactive authentication method available.")
  177. print("Run with --interactive flag or set up service account authentication.")
  178. return None
  179. def get_token():
  180. """Main authentication function - tries non-interactive first."""
  181. return get_token_non_interactive()
  182. if __name__ == "__main__":
  183. import sys
  184. # Set up logging
  185. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
  186. if "--extract-cookies" in sys.argv:
  187. # Extract cookies from Chrome
  188. browser = 'chrome'
  189. if "--browser" in sys.argv:
  190. browser_idx = sys.argv.index("--browser") + 1
  191. if browser_idx < len(sys.argv):
  192. browser = sys.argv[browser_idx]
  193. output_file = "youtube_cookies.txt"
  194. if "--output" in sys.argv:
  195. output_idx = sys.argv.index("--output") + 1
  196. if output_idx < len(sys.argv):
  197. output_file = sys.argv[output_idx]
  198. print(f"Extracting cookies from {browser} browser...")
  199. success = update_cookies_from_browser(browser, output_file)
  200. if success:
  201. print(f"Cookies successfully extracted to {output_file}")
  202. else:
  203. print("Cookie extraction failed")
  204. sys.exit(1)
  205. elif "--check-browsers" in sys.argv:
  206. # Check available browsers
  207. print("Checking available browsers with YouTube cookies...")
  208. browsers = check_browser_cookies()
  209. if browsers:
  210. print(f"Available browsers: {', '.join(browsers)}")
  211. else:
  212. print("No browsers with accessible YouTube cookies found")
  213. elif "--interactive" in sys.argv:
  214. creds = get_token_interactive()
  215. else:
  216. creds = get_token_non_interactive()
  217. if not creds:
  218. print("\nTo authenticate interactively, run: python3 auth.py --interactive")
  219. print("To extract cookies from browser, run: python3 auth.py --extract-cookies")
  220. print("To check available browsers, run: python3 auth.py --check-browsers")
  221. if "--extract-cookies" not in sys.argv and "--check-browsers" not in sys.argv:
  222. if creds:
  223. print("Authentication successful!")
  224. else:
  225. print("Authentication failed!")
  226. sys.exit(1)