소스 검색

updated to service account auth

Murad Jabir 1 년 전
부모
커밋
cbf50e68cb
2개의 변경된 파일과 113개의 추가작업 그리고 27개의 파일을 삭제
  1. 91 7
      auth.py
  2. 22 20
      main.py

+ 91 - 7
auth.py

@@ -1,15 +1,38 @@
 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
 
 # OAuth 2.0 scopes
 SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"]
 
-def get_token():
-    """Perform OAuth authentication and save the token."""
+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
-    # The token file to save credentials
     token_file = "youtube_token.pickle"
 
     # Check if token file exists
@@ -20,17 +43,78 @@ def get_token():
     # If no valid credentials, authenticate user
     if not creds or not creds.valid:
         if creds and creds.expired and creds.refresh_token:
-            creds.refresh(Request())
-        else:
+            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=0)
+            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__":
-    get_token()
+    import sys
+    
+    if "--interactive" in sys.argv:
+        creds = get_token_interactive()
+    else:
+        creds = get_token_non_interactive()
+        if not creds:
+            print("\nTo authenticate interactively, run: python3 auth.py --interactive")
+    
+    if creds:
+        print("Authentication successful!")
+    else:
+        print("Authentication failed!")
+        sys.exit(1)
 

+ 22 - 20
main.py

@@ -7,6 +7,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
 
 # Constants
 OUTPUT_DIR = "/media/media/YouTube"  # Change this to your Emby folder
@@ -23,28 +24,29 @@ def update_yt_dlp():
     subprocess.run(["pip", "install", "--upgrade", "yt-dlp"], check=True)
     print("yt-dlp updated successfully!")
 
-def authenticate_with_token():
-    """Authenticate using the saved token, with automatic refresh."""
-    if not os.path.exists(TOKEN_FILE):
-        raise FileNotFoundError(f"Token file '{TOKEN_FILE}' not found. Please run the token retrieval script first.")
-
-    # Load credentials from the token file
-    with open(TOKEN_FILE, "rb") as token:
-        creds = pickle.load(token)
-
-    # Refresh the token if it has expired
-    if creds and creds.expired and creds.refresh_token:
-        print("Access token expired. Refreshing...")
-        creds.refresh(Request())
-        # Save the refreshed credentials back to the file
-        with open(TOKEN_FILE, "wb") as token:
-            pickle.dump(creds, token)
-        print("Token refreshed successfully!")
-
+def authenticate_youtube_api():
+    """Authenticate using our enhanced auth system (tries non-interactive first)."""
+    print("Attempting non-interactive authentication...")
+    
+    # Try non-interactive authentication first
+    creds = get_token_non_interactive()
+    
+    if not creds:
+        print("Non-interactive authentication failed.")
+        print("You need to run: python3 auth.py --interactive")
+        print("Or set up service account authentication.")
+        raise Exception("Authentication failed. No valid credentials available.")
+    
+    print("Authentication successful!")
+    
     # Build the YouTube API client
     youtube = build("youtube", "v3", credentials=creds)
     return youtube
 
+def authenticate_with_token():
+    """Legacy function - kept for compatibility but redirects to new auth system."""
+    return authenticate_youtube_api()
+
 def get_subscribed_channels(youtube):
     """Fetch the list of subscribed channels."""
     channels = []
@@ -186,8 +188,8 @@ def main():
     update_yt_dlp()
 
     # Authenticate YouTube API
-    print("Authenticating with token...")
-    youtube = authenticate_with_token()
+    print("Authenticating with YouTube API...")
+    youtube = authenticate_youtube_api()
 
     if not os.path.exists(OUTPUT_DIR):
         os.makedirs(OUTPUT_DIR)