-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
120 lines (98 loc) · 3.61 KB
/
Copy pathmain.py
File metadata and controls
120 lines (98 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from __future__ import annotations
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from dotenv import load_dotenv
from quiz_generator import generate_quiz
from seo_metadata import metadata_for_quiz
from video_builder import build_video
from youtube_upload import upload_video
load_dotenv()
ROOT = Path(__file__).resolve().parent
DATA = ROOT / "data"
OUTPUT = ROOT / "output"
STATE_FILE = DATA / "state.json"
MUSIC_FILE = ROOT / "assets" / "music.mp3"
TOPICS = [
"Python lists, tuples, and indexing",
"Python dictionaries and sets",
"Python functions and scope",
"Python loops and comprehensions",
"Python exceptions and debugging",
"Python classes and objects",
"Python modules and packages",
"Python strings and formatting",
]
def load_state() -> dict:
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text(encoding="utf-8"))
return {"day": "", "cycles_today": 0, "topic_index": 0, "history": [], "runs": []}
def save_state(state: dict) -> None:
DATA.mkdir(parents=True, exist_ok=True)
STATE_FILE.write_text(json.dumps(state, indent=2), encoding="utf-8")
def daily_cycle_limit_reached(state: dict) -> bool:
today = datetime.now(timezone.utc).date().isoformat()
if state.get("day") != today:
state["day"] = today
state["cycles_today"] = 0
return state["cycles_today"] >= int(os.getenv("MAX_DAILY_CYCLES", "4"))
def run_once() -> list[str]:
state = load_state()
if daily_cycle_limit_reached(state):
save_state(state)
print("Daily cycle limit reached; no new videos created.")
return []
topic = TOPICS[state.get("topic_index", 0) % len(TOPICS)]
state["topic_index"] = state.get("topic_index", 0) + 1
quiz = generate_quiz(topic)
slug = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
music = str(MUSIC_FILE) if MUSIC_FILE.exists() else None
privacy = os.getenv("YOUTUBE_PRIVACY_STATUS", "private")
video_ids: list[str] = []
formats = []
if os.getenv("PUBLISH_LONGFORM", "true").lower() == "true":
formats.append((False, OUTPUT / f"python_quiz_long_{slug}.mp4"))
if os.getenv("PUBLISH_SHORTS", "true").lower() == "true":
formats.append((True, OUTPUT / f"python_quiz_short_{slug}.mp4"))
for shorts, path in formats:
build_video(quiz, str(path), music, shorts=shorts)
metadata = metadata_for_quiz(quiz, shorts=shorts)
video_id = upload_video(
video_path=str(path),
title=metadata["title"],
description=metadata["description"],
tags=metadata["tags"],
privacy_status=privacy,
)
video_ids.append(video_id)
state["history"].append({
"topic": quiz["topic"],
"format": "short" if shorts else "longform",
"video_id": video_id,
"path": str(path),
"privacy": privacy,
})
state["cycles_today"] += 1
state["runs"].append({
"created_at": datetime.now(timezone.utc).isoformat(),
"status": "uploaded",
"video_ids": video_ids,
})
state["history"] = state["history"][-100:]
state["runs"] = state["runs"][-100:]
save_state(state)
for video_id in video_ids:
print(f"Uploaded https://youtu.be/{video_id}")
return video_ids
def main() -> None:
interval_seconds = int(os.getenv("INTERVAL_MINUTES", "45")) * 60
while True:
try:
run_once()
except Exception as error:
print(f"Pipeline failed: {error}")
time.sleep(interval_seconds)
if __name__ == "__main__":
main()