Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/gh.cpython-312.pyc
Binary file not shown.
Binary file added __pycache__/tg.cpython-312.pyc
Binary file not shown.
20 changes: 14 additions & 6 deletions gh.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
from typing import Tuple, Optional, Callable
from env_config import get_env

GITHUB_COMMIT_RETRY_DELAY_FACTOR = 0.6
VIDEOS_JSON_RETRY_DELAY_FACTOR = 0.4
ENTRY_VERIFICATION_DELAY_FACTOR = 2.0

# Google Drive API imports
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
Expand All @@ -18,6 +22,10 @@

# GitHub API imports
from github import Github, InputGitTreeElement

# Heuristic minimum length check to catch obviously invalid/placeholder tokens.
# This is not a strict format validator for all possible GitHub token types.
MIN_GITHUB_TOKEN_LENGTH = 30
from github.GithubException import GithubException

# --- Logging Setup ---
Expand Down Expand Up @@ -289,7 +297,7 @@ def delete_from_google_drive(service, file_id: str) -> bool:

def authenticate_github():
"""Authenticates with GitHub API using a Personal Access Token."""
if not GITHUB_ACCESS_TOKEN or len(GITHUB_ACCESS_TOKEN) < 30: # Basic check for placeholder/empty token
if not GITHUB_ACCESS_TOKEN or len(GITHUB_ACCESS_TOKEN) < MIN_GITHUB_TOKEN_LENGTH: # Basic check for placeholder/empty token
logger.error("GITHUB_ACCESS_TOKEN is not set or is invalid. Cannot authenticate with GitHub.")
return None
try:
Expand Down Expand Up @@ -348,7 +356,7 @@ def update_and_commit_github_file(repo, file_path, new_content, commit_message,
status = getattr(e, "status", None)
is_conflict = status == 409 or "does not match" in str(e).lower()
if is_conflict and attempt < max_retries:
delay = 0.6 * attempt
delay = GITHUB_COMMIT_RETRY_DELAY_FACTOR * attempt
logger.warning(
f"GitHub conflict while committing '{file_path}' (attempt {attempt}/{max_retries}). "
f"Retrying in {delay:.1f}s..."
Expand All @@ -365,7 +373,7 @@ def update_and_commit_github_file(repo, file_path, new_content, commit_message,
return None


def _load_videos_json_and_sha(repo, branch: str) -> tuple[list, Optional[str]]:
def _load_videos_json_and_sha(repo, branch: str) -> Tuple[list, Optional[str]]:
"""Loads videos.json list and current blob SHA (if file exists)."""
try:
contents = repo.get_contents(GITHUB_VIDEOS_JSON_PATH, ref=branch)
Expand Down Expand Up @@ -467,7 +475,7 @@ def upsert_video_entry_merge_safe(
status = getattr(e, "status", None)
is_conflict = status == 409 or "does not match" in str(e).lower()
if is_conflict and attempt < max_retries:
delay = 0.4 * attempt
delay = VIDEOS_JSON_RETRY_DELAY_FACTOR * attempt
logger.warning(
f"Conflict while upserting videos.json (attempt {attempt}/{max_retries}). "
f"Retrying in {delay:.1f}s..."
Expand Down Expand Up @@ -506,7 +514,7 @@ def _verify_entry_exists_with_retry(repo, branch: str, entry: dict, max_retries:
return True

if attempt < max_retries:
delay = 2.0 * attempt # 2s, 4s, 6s, 8s
delay = ENTRY_VERIFICATION_DELAY_FACTOR * attempt # 2s, 4s, 6s, 8s
logger.warning(
f"Entry verification pending (attempt {attempt}/{max_retries}). "
f"Retrying in {delay:.1f}s..."
Expand Down Expand Up @@ -690,7 +698,7 @@ def _run_update_flow() -> Tuple[bool, Optional[str], Optional[str]]:
logger.info(f"commitSha verification passed on attempt {attempt}/4")
break
if attempt < 4:
delay = 2.0 * attempt
delay = ENTRY_VERIFICATION_DELAY_FACTOR * attempt
logger.warning(
f"commitSha verification pending (attempt {attempt}/4). "
f"Retrying in {delay:.1f}s..."
Expand Down
8 changes: 5 additions & 3 deletions tg.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from collections import defaultdict
import os

YT_DLP_H264_PREFERRED_FORMAT = "bestvideo[ext=mp4][vcodec^=avc]+bestaudio[ext=m4a]/bestvideo[ext=mp4][vcodec!=av01]+bestaudio[ext=m4a]/bestvideo[vcodec^=avc]+bestaudio/best"

# --- Conditional Telegram Import ---
# Telegram is optional due to regional bans (e.g., India)
# Set ENABLE_TELEGRAM=true to enable the Telegram bot
Expand Down Expand Up @@ -2483,7 +2485,7 @@ async def download_video_async(url: str, output_dir: str, progress_message_obj=N
"--simulate",
"--get-filename",
"-o", "%(title)s.%(ext)s", # No dir prefix; we join manually below
"-f", "bestvideo[ext=mp4][vcodec^=avc]+bestaudio[ext=m4a]/bestvideo[ext=mp4][vcodec!*=av01]+bestaudio[ext=m4a]/bestvideo[vcodec^=avc]+bestaudio/best",
"-f", YT_DLP_H264_PREFERRED_FORMAT,
"--merge-output-format", "mp4", # Ensure output format is mp4
"--no-playlist", # Only get filename for the target video, not the entire playlist
"--js-runtimes", "node", # Use Node.js as JS runtime for YouTube extraction
Expand Down Expand Up @@ -2537,7 +2539,7 @@ async def download_video_async(url: str, output_dir: str, progress_message_obj=N
"-o", actual_output_path,
# Prefer H.264 (avc) to ensure OpenCV compatibility. Explicitly avoid AV1 (av01) and VP9.
# Fallback chain: H.264 mp4 → non-AV1 mp4 → H.264 any container → absolute best
"-f", "bestvideo[ext=mp4][vcodec^=avc]+bestaudio[ext=m4a]/bestvideo[ext=mp4][vcodec!*=av01]+bestaudio[ext=m4a]/bestvideo[vcodec^=avc]+bestaudio/best",
"-f", YT_DLP_H264_PREFERRED_FORMAT,
"--merge-output-format", "mp4", # Ensure output is mp4
"--progress",
"--no-playlist",
Expand Down Expand Up @@ -6235,7 +6237,7 @@ async def edit_text(self, message):
download_cmd = [
"yt-dlp",
"--no-playlist",
"-f", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best",
"-f", YT_DLP_H264_PREFERRED_FORMAT,
"--merge-output-format", "mp4", # Ensure output is mp4
"-o", f"{local_video_path}.%(ext)s",
"--no-warnings",
Expand Down