-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
177 lines (142 loc) · 5.14 KB
/
server.py
File metadata and controls
177 lines (142 loc) · 5.14 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python3
"""
Flask server for GMPuzzles Tracker.
Serves the dashboard and provides API endpoints for marking puzzles solved.
"""
import os
import json
import subprocess
from pathlib import Path
from flask import Flask, send_from_directory, jsonify, request
from dotenv import load_dotenv
import requests
load_dotenv()
app = Flask(__name__)
REMEMBERME_COOKIE = os.getenv("GMPUZZLES_REMEMBERME")
PUZZLES_FILE = Path(__file__).parent / "puzzles.json"
BASE_DIR = Path(__file__).parent
API_BASE = "https://www.gmpuzzles.com/checker/api"
def get_cookies():
return {"rememberme": REMEMBERME_COOKIE} if REMEMBERME_COOKIE else {}
# Static file serving
@app.route("/")
def index():
return send_from_directory(BASE_DIR, "index.html")
@app.route("/puzzles.json")
def puzzles_json():
return send_from_directory(BASE_DIR, "puzzles.json")
# API endpoints
@app.route("/api/puzzle_status/<post_id>")
def puzzle_status(post_id):
"""Get current status of a puzzle including whether it requires answer verification."""
resp = requests.post(
f"{API_BASE}/generate_buttons.php",
data={"post_ids[]": [post_id]},
cookies=get_cookies(),
timeout=30
)
if resp.status_code == 200:
results = resp.json()
if results:
return jsonify(results[0])
return jsonify({"error": "Failed to fetch status"}), 500
@app.route("/api/mark_solved", methods=["POST"])
def mark_solved():
"""Mark a puzzle as solved."""
data = request.json
post_id = data.get("post_id")
answer = data.get("answer", "")
resp = requests.post(
f"{API_BASE}/add_solved.php",
data={"post_id": post_id, "user_code": answer, "mode": "add"},
cookies=get_cookies(),
timeout=30
)
if resp.status_code == 200:
result = resp.json()
if result.get("success") == 1:
update_local_json(post_id, solved=True)
return jsonify({"success": True})
else:
return jsonify({"success": False, "error": result.get("emsg", "Unknown error")})
return jsonify({"success": False, "error": "Request failed"}), 500
@app.route("/api/mark_unsolved", methods=["POST"])
def mark_unsolved():
"""Mark a puzzle as unsolved."""
data = request.json
post_id = data.get("post_id")
resp = requests.post(
f"{API_BASE}/add_solved.php",
data={"post_id": post_id, "user_code": "", "mode": "remove"},
cookies=get_cookies(),
timeout=30
)
if resp.status_code == 200:
result = resp.json()
if result.get("success") == 1:
update_local_json(post_id, solved=False)
return jsonify({"success": True})
else:
return jsonify({"success": False, "error": result.get("emsg", "Unknown error")})
return jsonify({"success": False, "error": "Request failed"}), 500
@app.route("/api/toggle_fave", methods=["POST"])
def toggle_fave():
"""Toggle favorite status."""
data = request.json
post_id = data.get("post_id")
add = data.get("add", True)
resp = requests.post(
f"{API_BASE}/add_fave.php",
data={"post_id": post_id, "mode": "add" if add else "remove"},
cookies=get_cookies(),
timeout=30
)
if resp.status_code == 200:
result = resp.json()
if result.get("success") == 1:
update_local_json(post_id, faved=add)
return jsonify({"success": True})
else:
return jsonify({"success": False, "error": result.get("emsg", "Unknown error")})
return jsonify({"success": False, "error": "Request failed"}), 500
@app.route("/api/refresh", methods=["POST"])
def refresh():
"""Run refresh.py to update puzzle data."""
try:
result = subprocess.run(
["python3", str(BASE_DIR / "refresh.py"), "--solves"],
capture_output=True,
text=True,
timeout=120,
cwd=BASE_DIR
)
return jsonify({
"success": result.returncode == 0,
"output": result.stdout,
"error": result.stderr
})
except subprocess.TimeoutExpired:
return jsonify({"success": False, "error": "Refresh timed out"}), 500
except Exception as e:
return jsonify({"success": False, "error": str(e)}), 500
def update_local_json(post_id, solved=None, faved=None):
"""Update local puzzles.json to reflect the change."""
if not PUZZLES_FILE.exists():
return
with open(PUZZLES_FILE) as f:
data = json.load(f)
for puzzle in data["puzzles"]:
if puzzle.get("post_id") == post_id:
if solved is not None:
puzzle["solved"] = solved
if faved is not None:
puzzle["faved"] = faved
break
# Recalculate metadata
data["metadata"]["solved_count"] = sum(1 for p in data["puzzles"] if p.get("solved"))
data["metadata"]["faved_count"] = sum(1 for p in data["puzzles"] if p.get("faved"))
with open(PUZZLES_FILE, "w") as f:
json.dump(data, f, indent=2)
if __name__ == "__main__":
print("Starting GMPuzzles Tracker server at http://localhost:8080")
app.run(host="0.0.0.0", port=8080, debug=True)