feat: replace yt-dlp cookies with YouTube Data API v3 OAuth

- Add auth.py: OAuth credential manager with auto-refresh
- Rewrite fetcher.py: use googleapiclient subscriptions/search
- Add google-auth, google-api-python-client dependencies
- Update docker-compose for config volume mount
- Add .gitignore for secrets (client_secret.json, token.pickle)
- Live test: 198 videos ingested from 229 channels
This commit is contained in:
Gan, Jimmy
2026-06-24 00:14:16 +08:00
parent dba070531e
commit a0ffa41c9e
7 changed files with 658 additions and 67 deletions
+43
View File
@@ -0,0 +1,43 @@
import os
import pickle
import logging
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
log = logging.getLogger(__name__)
SCOPES = ["https://www.googleapis.com/auth/youtube.readonly"]
CONFIG_DIR = os.environ.get("CONFIG_DIR", "/app/config")
_local_dir = os.path.dirname(os.path.abspath(__file__))
_local_config = os.path.join(os.path.dirname(_local_dir), "config")
if os.path.exists(os.path.join(_local_config, "client_secret.json")):
CONFIG_DIR = _local_config
CLIENT_SECRET = os.path.join(CONFIG_DIR, "client_secret.json")
TOKEN_FILE = os.path.join(CONFIG_DIR, "token.pickle")
def get_credentials():
"""Load or refresh OAuth credentials, triggering browser flow if needed."""
creds = None
if os.path.exists(TOKEN_FILE):
with open(TOKEN_FILE, "rb") as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
if not os.path.exists(CLIENT_SECRET):
raise FileNotFoundError(
f"client_secret.json not found at {CLIENT_SECRET}. "
"Download from Google Cloud Console."
)
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET, SCOPES)
creds = flow.run_local_server(port=0)
os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)
with open(TOKEN_FILE, "wb") as token:
pickle.dump(creds, token)
return creds