From be8689eee6f9ecaaf6b52c74c4d4a024c1c4549e Mon Sep 17 00:00:00 2001 From: SHAREit Date: Wed, 9 Sep 2026 15:25:53 +0800 Subject: [PATCH] Update Sep 2026 data; auto-fetch from Google Sheet; daily refresh --- data.json | 227 +++++++++++++++++++++++++++++++++++++++++++++++--- schedule.conf | 2 +- update.sh | 124 +++++++++++++++++++++++++-- 3 files changed, 337 insertions(+), 16 deletions(-) diff --git a/data.json b/data.json index 17a49ed..301cd0d 100644 --- a/data.json +++ b/data.json @@ -2,16 +2,223 @@ "meta": { "geo": "EG", "product": "Nagwa", - "price": 0.30, - "sep_budget": 7500.00, - "spend": 814.80, - "left": 6685.20, - "spend_pct": "10.86%", - "rec_daily_install": 825.33 + "sep_budget": 7500, + "spend": 2279.6, + "left": 5220.4, + "spend_pct": "30.39%", + "rec_daily_install": 593.23, + "price": 0.4 }, "daily": [ - {"date": "2026-09-01", "install": 932, "payable_spend": 279.60, "enroll_session": 698, "enroll_session_pct": 74.89}, - {"date": "2026-09-02", "install": 917, "payable_spend": 275.10, "enroll_session": 0, "enroll_session_pct": 0.00}, - {"date": "2026-09-03", "install": 867, "payable_spend": 260.10, "enroll_session": 0, "enroll_session_pct": 0.00} + { + "date": "2026-09-01", + "install": 932, + "payable_spend": 279.6, + "enroll_session": 698, + "enroll_session_pct": 74.89 + }, + { + "date": "2026-09-02", + "install": 917, + "payable_spend": 275.1, + "enroll_session": 586, + "enroll_session_pct": 63.9 + }, + { + "date": "2026-09-03", + "install": 867, + "payable_spend": 260.1, + "enroll_session": 502, + "enroll_session_pct": 57.9 + }, + { + "date": "2026-09-04", + "install": 822, + "payable_spend": 246.6, + "enroll_session": 676, + "enroll_session_pct": 82.24 + }, + { + "date": "2026-09-05", + "install": 894, + "payable_spend": 268.2, + "enroll_session": 760, + "enroll_session_pct": 85.01 + }, + { + "date": "2026-09-06", + "install": 1048, + "payable_spend": 314.4, + "enroll_session": 782, + "enroll_session_pct": 74.62 + }, + { + "date": "2026-09-07", + "install": 858, + "payable_spend": 343.2, + "enroll_session": 866, + "enroll_session_pct": 100.93 + }, + { + "date": "2026-09-08", + "install": 731, + "payable_spend": 292.4, + "enroll_session": 651, + "enroll_session_pct": 89.06 + }, + { + "date": "2026-09-09", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-10", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-11", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-12", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-13", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-14", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-15", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-16", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-17", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-18", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-19", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-20", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-21", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-22", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-23", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-24", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-25", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-26", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-27", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-28", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-29", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + }, + { + "date": "2026-09-30", + "install": 0, + "payable_spend": 0.0, + "enroll_session": 0, + "enroll_session_pct": 0.0 + } ] -} +} \ No newline at end of file diff --git a/schedule.conf b/schedule.conf index 75016ea..a45fd52 100644 --- a/schedule.conf +++ b/schedule.conf @@ -1 +1 @@ -03 +24 diff --git a/update.sh b/update.sh index 7718513..eb10176 100755 --- a/update.sh +++ b/update.sh @@ -1,6 +1,120 @@ #!/bin/bash -# update.sh - 数据来自手动更新的 data.json -# 由于数据源是 Excel 表格(无公开 API),此脚本仅做占位 -# 每次有新数据时,直接更新 data.json 并 push 即可 -echo "data.json is manually maintained from Excel export." -echo "Last check: $(date)" +# update.sh - 自动从 Google Sheet 拉取 EG Nagwa 当月数据并生成 data.json +# 数据源:公开导出的 Google Sheet CSV +# 每天由服务器自动执行一次(见 schedule.conf) +set -euo pipefail + +SHEET_ID="11Npr4IpXT8jtgUnrkrjITJ8s1fHNYTwRRwSGIvcfeIs" +GID="699511110" +CSV_URL="https://docs.google.com/spreadsheets/d/${SHEET_ID}/export?format=csv&gid=${GID}" + +OUT="data.json" +TMP_CSV="$(mktemp)" +trap 'rm -f "$TMP_CSV"' EXIT + +# 当月,格式如 September-2026 +MONTH_TAG="$(date +%B-%Y)" + +echo "Fetching CSV for month: $MONTH_TAG" +curl -fsSL "$CSV_URL" -o "$TMP_CSV" + +# 用 python 解析 CSV 生成 data.json(python3 处理带引号/逗号的字段更稳妥) +python3 - "$TMP_CSV" "$OUT" "$MONTH_TAG" <<'PY' +import csv, json, sys, re +from datetime import datetime + +csv_path, out_path, month_tag = sys.argv[1], sys.argv[2], sys.argv[3] + +def num(s): + if s is None: return None + s = s.strip().replace(',', '').replace('$', '').replace('%', '') + if s == '': return None + try: + f = float(s) + return int(f) if f.is_integer() else f + except ValueError: + return None + +rows = list(csv.reader(open(csv_path, newline='', encoding='utf-8'))) + +# 列索引(0-based),依据表头布局: +# Month=7, DT=8, Geo=9, Install=10, Price=11, MidasSpend=12, +# PayableSpend=13, Enroll_Session=14, Enroll_Session%=15, Remark=16, +# meta-key=17, meta-value=18 +COL_MONTH, COL_DT, COL_INSTALL = 7, 8, 10 +COL_PAYABLE, COL_ENROLL, COL_ENROLLPCT = 13, 14, 15 +COL_METAK, COL_METAV = 16, 17 + +daily = [] +meta = {"geo": "EG", "product": "Nagwa"} + +# 从 month_tag 解析目标年月,用于把 DT(如 2026/9/1 或 20260901)标准化成 YYYY-MM-DD +target_month = datetime.strptime(month_tag, "%B-%Y") +ty, tm = target_month.year, target_month.month + +def parse_dt(dt): + dt = dt.strip() + if not dt: return None + # 形如 2026/9/1 + m = re.match(r'^(\d{4})/(\d{1,2})/(\d{1,2})$', dt) + if m: + y, mo, d = map(int, m.groups()) + return f"{y:04d}-{mo:02d}-{d:02d}" + # 形如 20260901 + m = re.match(r'^(\d{4})(\d{2})(\d{2})$', dt) + if m: + y, mo, d = map(int, m.groups()) + return f"{y:04d}-{mo:02d}-{d:02d}" + return None + +price_seen = None +for r in rows: + if len(r) <= COL_ENROLLPCT: + continue + if r[COL_MONTH].strip() != month_tag: + continue + date = parse_dt(r[COL_DT]) + if not date: + continue + install = num(r[COL_INSTALL]) or 0 + spend = num(r[COL_PAYABLE]) or 0.0 + enroll = num(r[COL_ENROLL]) or 0 + pct = num(r[COL_ENROLLPCT]) or 0.0 + daily.append({ + "date": date, + "install": int(install), + "payable_spend": round(float(spend), 2), + "enroll_session": int(enroll), + "enroll_session_pct": round(float(pct), 2), + }) + # 记录价格(取当月出现的最新价) + p = num(r[11]) + if p is not None: + price_seen = p + # 抓取 meta(Remark 区块的 key/value) + k = r[COL_METAK].strip() if len(r) > COL_METAK else "" + v = r[COL_METAV].strip() if len(r) > COL_METAV else "" + if k and v: + kl = k.lower() + if "budget" in kl: + meta["sep_budget"] = num(v) + elif kl == "spend": + meta["spend"] = num(v) + elif kl == "left": + meta["left"] = num(v) + elif kl == "%": + meta["spend_pct"] = v if v.endswith('%') else (v + '%') + elif "daily install" in kl: + meta["rec_daily_install"] = num(v) + +if price_seen is not None: + meta["price"] = price_seen + +data = {"meta": meta, "daily": daily} +with open(out_path, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + +print(f"Wrote {len(daily)} days to {out_path}") +PY + +echo "Done. Last run: $(date)"