|
12 | 12 | import argparse |
13 | 13 | import json |
14 | 14 | import os |
| 15 | +import subprocess |
15 | 16 | import sys |
16 | 17 | import time |
17 | 18 | from datetime import datetime |
|
21 | 22 |
|
22 | 23 | try: |
23 | 24 | from dotenv import load_dotenv |
24 | | - load_dotenv("/.env.local") |
25 | | -except ImportError: |
26 | | - # python-dotenv is optional; continue if not installed and rely on existing env vars. |
27 | | - print("ℹ️ python-dotenv not installed; skipping /.env.local loading.", file=sys.stderr) |
| 25 | + repo_root = subprocess.check_output( |
| 26 | + ["git", "rev-parse", "--show-toplevel"], stderr=subprocess.DEVNULL |
| 27 | + ).decode().strip() |
| 28 | + load_dotenv(os.path.join(repo_root, ".env.local")) |
| 29 | +except (ImportError, subprocess.CalledProcessError): |
| 30 | + pass |
28 | 31 |
|
29 | 32 | # ========================================== |
30 | 33 | # EDIT THESE TWO LINES BEFORE EACH RUN |
|
36 | 39 |
|
37 | 40 | API_KEY = os.environ.get("BUFFER_API_KEY") |
38 | 41 | if not API_KEY: |
39 | | - print("❌ BUFFER_API_KEY not set. Add it to website/.env.local or export it.") |
| 42 | + print("ERROR: BUFFER_API_KEY not set. Add it to website/.env.local or export it.") |
40 | 43 | sys.exit(1) |
41 | 44 |
|
42 | 45 | BUFFER_URL = "https://api.buffer.com/" |
|
54 | 57 | all_keynoters = json.load(f) |
55 | 58 |
|
56 | 59 | if KEYNOTER not in all_keynoters: |
57 | | - print(f"❌ '{KEYNOTER}' not found in keynoters.json") |
| 60 | + print(f"ERROR: '{KEYNOTER}' not found in keynoters.json") |
58 | 61 | print(f" Available: {', '.join(all_keynoters.keys())}") |
59 | 62 | sys.exit(1) |
60 | 63 |
|
61 | 64 | data = all_keynoters[KEYNOTER] |
62 | | -image_path = os.path.join(os.path.dirname(__file__), data["image"]) |
| 65 | +image_url = data.get("image") |
63 | 66 | channels = {k: v for k, v in data.items() if k != "image"} |
64 | 67 | sched_unix = int(SCHEDULED_AT.timestamp()) |
65 | 68 |
|
66 | | -print(f"👤 {KEYNOTER}") |
67 | | -print(f" 📅 Scheduled: {SCHEDULED_AT.strftime('%Y-%m-%d %H:%M %Z')}") |
| 69 | +print(f"Keynoter: {KEYNOTER}") |
| 70 | +print(f"Scheduled: {SCHEDULED_AT.strftime('%Y-%m-%d %H:%M %Z')}") |
| 71 | +print(f"Image: {image_url or 'none'}") |
68 | 72 | if args.dry_run: |
69 | | - print(" 🔍 DRY RUN — nothing will be sent\n") |
| 73 | + print("DRY RUN — nothing will be sent\n") |
70 | 74 | for network, text in channels.items(): |
71 | 75 | print(f"[{network.upper()}]") |
72 | | - print(text[:200] + ("…" if len(text) > 200 else "")) |
| 76 | + print(text[:200] + ("..." if len(text) > 200 else "")) |
73 | 77 | print() |
74 | 78 | sys.exit(0) |
75 | 79 |
|
|
81 | 85 | """ |
82 | 86 | resp = requests.post(BUFFER_URL, json={"query": get_channels_query}, headers=HEADERS) |
83 | 87 | if resp.status_code != 200 or "errors" in resp.json(): |
84 | | - print(f"❌ Could not fetch Buffer channels: {resp.text}") |
| 88 | + print(f"ERROR: Could not fetch Buffer channels: {resp.text}") |
85 | 89 | sys.exit(1) |
86 | 90 |
|
87 | 91 | SERVICE_MAP = {"twitter": "x", "mastodon": "fosstodon", "bluesky": "bsky"} |
|
91 | 95 | key = SERVICE_MAP.get(ch["service"].lower(), ch["service"].lower()) |
92 | 96 | profile_map[key] = ch["id"] |
93 | 97 |
|
94 | | -print("✅ Connected channels:", list(profile_map.keys())) |
| 98 | +print("Connected channels:", list(profile_map.keys())) |
95 | 99 | print("-" * 50) |
96 | 100 |
|
97 | | -# ========================================== |
98 | | -# UPLOAD IMAGE |
99 | | -# ========================================== |
100 | | -upload_mutation = """ |
101 | | -mutation UploadMedia($input: UploadMediaInput!) { |
102 | | - uploadMedia(input: $input) { |
103 | | - ... on UploadMediaSuccess { mediaId url } |
104 | | - ... on MutationError { message } |
105 | | - } |
106 | | -} |
107 | | -""" |
108 | | - |
109 | | -image_url = None |
110 | | -if os.path.isfile(image_path): |
111 | | - import base64 |
112 | | - with open(image_path, "rb") as f: |
113 | | - encoded = base64.b64encode(f.read()).decode() |
114 | | - ext = os.path.splitext(image_path)[1].lstrip(".").lower() |
115 | | - mime = "image/jpeg" if ext in ("jpg", "jpeg") else f"image/{ext}" |
116 | | - resp = requests.post( |
117 | | - BUFFER_URL, |
118 | | - json={"query": upload_mutation, "variables": {"input": {"data": f"data:{mime};base64,{encoded}"}}}, |
119 | | - headers=HEADERS, |
120 | | - ) |
121 | | - result = resp.json().get("data", {}).get("uploadMedia", {}) |
122 | | - image_url = result.get("url") |
123 | | - if image_url: |
124 | | - print(f"📤 Image uploaded: {image_url}") |
125 | | - else: |
126 | | - print(f"⚠️ Image upload failed: {result.get('message', 'unknown')}") |
127 | | -else: |
128 | | - print(f"⚠️ Image not found: {image_path}") |
129 | | - |
130 | 101 | # ========================================== |
131 | 102 | # POST TO EACH CHANNEL |
132 | 103 | # ========================================== |
|
142 | 113 | for network, text in channels.items(): |
143 | 114 | profile_id = profile_map.get(network) |
144 | 115 | if not profile_id: |
145 | | - print(f"⚠️ [{network}] not connected in Buffer — skipped") |
| 116 | + print(f" [{network}] not connected in Buffer — skipped") |
146 | 117 | continue |
147 | 118 |
|
148 | 119 | post_input = { |
|
164 | 135 | json={"query": create_mutation, "variables": {"input": post_input}}, |
165 | 136 | headers=HEADERS, |
166 | 137 | ) |
167 | | - res = resp.json().get("data", {}).get("createPost", {}) |
168 | | - post = res.get("post", {}) |
169 | | - if post.get("id"): |
170 | | - print(f"✅ [{network}] scheduled at {post.get('scheduledAt')} (id: {post['id']})") |
| 138 | + if resp.status_code == 200: |
| 139 | + res_json = resp.json() |
| 140 | + if "errors" in res_json: |
| 141 | + print(f" [{network}] GraphQL error: {res_json['errors'][0]['message']}") |
| 142 | + else: |
| 143 | + res = res_json.get("data", {}).get("createPost", {}) |
| 144 | + post = res.get("post", {}) |
| 145 | + if post.get("id"): |
| 146 | + print(f" [{network}] scheduled at {post.get('scheduledAt')} (id: {post['id']})") |
| 147 | + else: |
| 148 | + print(f" [{network}] failed: {res.get('message', 'unknown error')}") |
171 | 149 | else: |
172 | | - print(f"❌ [{network}] failed: {res.get('message') or resp.json().get('errors', '?')}") |
| 150 | + print(f" [{network}] HTTP {resp.status_code}: {resp.text}") |
173 | 151 |
|
174 | 152 | time.sleep(0.5) |
175 | 153 |
|
176 | | -print("\n🎉 Done!") |
| 154 | +print("\nDone.") |
0 commit comments