| """ |
| Google Drive Auto-Uploader using OAuth2 refresh token. |
| Works with personal Google accounts (not just Workspace). |
| """ |
| import os |
| import json |
| from google.oauth2.credentials import Credentials |
| from google.auth.transport.requests import Request |
| from googleapiclient.discovery import build |
| from googleapiclient.http import MediaFileUpload |
|
|
| |
| SCOPES = ['https://www.googleapis.com/auth/drive'] |
|
|
| def get_drive_service(): |
| """ |
| Creates a Google Drive API service using OAuth2 refresh token. |
| Requires 3 env vars: GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET, GOOGLE_DRIVE_REFRESH_TOKEN |
| """ |
| client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID", "").strip() |
| client_secret = os.getenv("GOOGLE_OAUTH_CLIENT_SECRET", "").strip() |
| refresh_token = os.getenv("GOOGLE_DRIVE_REFRESH_TOKEN", "").strip() |
| |
| if not all([client_id, client_secret, refresh_token]): |
| missing = [] |
| if not client_id: missing.append("GOOGLE_OAUTH_CLIENT_ID") |
| if not client_secret: missing.append("GOOGLE_OAUTH_CLIENT_SECRET") |
| if not refresh_token: missing.append("GOOGLE_DRIVE_REFRESH_TOKEN") |
| print(f"ERROR: Missing env vars: {', '.join(missing)}", flush=True) |
| return None |
| |
| |
| print(f"DEBUG: Client ID: {client_id[:5]}... (len={len(client_id)})", flush=True) |
| print(f"DEBUG: Client Secret: {client_secret[:3]}... (len={len(client_secret)})", flush=True) |
| print(f"DEBUG: Refresh Token: {refresh_token[:5]}... (len={len(refresh_token)})", flush=True) |
| |
| try: |
| creds = Credentials( |
| token=None, |
| refresh_token=refresh_token, |
| client_id=client_id, |
| client_secret=client_secret, |
| token_uri="https://oauth2.googleapis.com/token", |
| scopes=SCOPES |
| ) |
| |
| creds.refresh(Request()) |
| |
| service = build('drive', 'v3', credentials=creds) |
| print("β
Google Drive connected (OAuth2)!", flush=True) |
| return service |
| except Exception as e: |
| print(f"β Failed to connect to Google Drive: {e}", flush=True) |
| return None |
|
|
| def upload_to_drive(file_path, folder_id=None): |
| """ |
| Uploads a file to Google Drive using the user's own account. |
| |
| Args: |
| file_path: Path to the file to upload |
| folder_id: Google Drive folder ID |
| |
| Returns: |
| The file URL on Google Drive, or None if upload failed |
| """ |
| if not folder_id: |
| folder_id = os.getenv("GOOGLE_DRIVE_FOLDER_ID") |
| |
| if not folder_id: |
| print("ERROR: GOOGLE_DRIVE_FOLDER_ID not set!", flush=True) |
| return None |
| |
| service = get_drive_service() |
| if not service: |
| return None |
| |
| filename = os.path.basename(file_path) |
| file_size_mb = os.path.getsize(file_path) / (1024 * 1024) |
| |
| print(f"π€ Uploading {filename} ({file_size_mb:.1f} MB) to Google Drive...", flush=True) |
| |
| file_metadata = { |
| 'name': filename, |
| 'parents': [folder_id] |
| } |
| |
| media = MediaFileUpload( |
| file_path, |
| mimetype='video/mp4', |
| resumable=True, |
| chunksize=10 * 1024 * 1024 |
| ) |
| |
| try: |
| file = service.files().create( |
| body=file_metadata, |
| media_body=media, |
| fields='id, webViewLink' |
| ).execute() |
| |
| file_id = file.get('id') |
| file_link = file.get('webViewLink', f"https://drive.google.com/file/d/{file_id}/view") |
| |
| print(f"β
Upload SUCCESS: {filename}", flush=True) |
| print(f"π Link: {file_link}", flush=True) |
| |
| return file_link |
| |
| except Exception as e: |
| print(f"β Upload FAILED: {e}", flush=True) |
| return None |
|
|