用 Gitee Go 搭建WorkBuddy云端定时任务

前言

一套不依赖本地电脑、不用自己买服务器、每天准时跑的自动化方案。包含完整代码、配置步骤和 6 个真实踩坑记录。


一、整体架构

scss 复制代码
┌─────────────────┐
│  Gitee Go 定时器  │  (每天触发)
└────────┬────────┘
         ↓
┌─────────────────┐
│   拉取私有仓库     │  (checkin.py + config.json)
└────────┬────────┘
         ↓
┌─────────────────┐
│     执行脚本      │ 
└────────┬────────┘
         ↓
┌─────────────────┐
│  Server酱 推微信   │  (通知到个人微信)
└─────────────────┘

核心优势

  • 不依赖本地电脑,云端跑
  • 微信实时通知,签到结果一目了然
  • 维护成本极低(token 过期前更新一次即可)

二、准备工作

2.1 获取 accessToken

WorkBuddy 客户端登录后,会在本地保存登录态:

  • macOS~/Library/Application Support/CodeBuddyExtension/Data/Public/auth/workbuddy-desktop.info

打开这个文件,你会看到类似:

json 复制代码
{
  "account": { "nickname": "你的昵称", ... },
  "auth": { "accessToken": "eyJhbGc...", "expiresIn": ... }
}

auth.accessToken 就是我们需要的 token(这是你自己账号的合法凭证,不涉及任何破解)。

⚠️ 安全提示 :accessToken 就是你的登录态,绝对不要 提交到公开仓库。下面的方案会用私有仓库 + 配置文件保存。

2.2 注册 Server酱(微信通知)

打开 sct.ftqq.com → 微信扫码登录 → 在页面里看到 SendKey(一串字母数字)。

效果:调用 Server酱 接口就能把消息推送到你的微信(关注"方糖"公众号即可接收)。


三、签到脚本

完整脚本 checkin.py(纯 Python 标准库,零依赖):

python 复制代码
#!/usr/bin/env python3
"""
WorkBuddy 每日签到脚本
支持本地运行和云端运行
"""
import json
import os
import sys
import urllib.request
import urllib.error
from pathlib import Path
from datetime import datetime

# ─── 配置 ───────────────────────────────────────────────
API_BASE = "https://copilot.tencent.com"
CHECKIN_STATUS_URL = f"{API_BASE}/billing/meter/checkin-status"
DAILY_CHECKIN_URL = f"{API_BASE}/billing/meter/daily-checkin"
SERVERCHAN_URL = "https://sctapi.ftqq.com/{sendkey}.send"
REQUEST_TIMEOUT = 15

# 本地 auth 文件 (macOS)
_LOCAL_AUTH_FILE = (
    Path.home()
    / "Library/Application Support/CodeBuddyExtension"
    / "Data/Public/auth/workbuddy-desktop.info"
)
# 云端配置文件
_CLOUD_CONFIG_FILE = Path(__file__).parent / "config.json"


def log(msg: str):
    print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}", flush=True)


# ─── Token 读取 ─────────────────────────────────────────
def load_access_token() -> tuple[str | None, str]:
    """读取 token,优先级:config.json > 本地 auth > 环境变量"""
    # 1. 云端 config.json
    if _CLOUD_CONFIG_FILE.exists():
        try:
            data = json.loads(_CLOUD_CONFIG_FILE.read_text(encoding="utf-8"))
            token = data.get("access_token", "").strip()
            name = data.get("account_name", "云端账号")
            if token:
                log(f"   使用云端 config.json token (账号: {name})")
                return token, name
        except Exception as e:
            log(f"⚠️  读取 config.json 失败: {e}")

    # 2. 环境变量
    token = os.environ.get("WORKBUDDY_ACCESS_TOKEN", "").strip()
    if token:
        name = os.environ.get("WORKBUDDY_ACCOUNT_NAME", "环境变量账号")
        log(f"   使用环境变量 token (账号: {name})")
        return token, name

    # 3. 本地 auth 文件
    if not _LOCAL_AUTH_FILE.exists():
        log("❌ 未找到任何 token 来源,请配置 config.json 或环境变量")
        return None, ""
    try:
        data = json.loads(_LOCAL_AUTH_FILE.read_text(encoding="utf-8"))
        token = data.get("auth", {}).get("accessToken", "").strip()
        name = data.get("account", {}).get("nickname", "本地账号")
        if not token:
            log("❌ auth 文件中未找到 accessToken")
            return None, ""
        log(f"   使用本地 auth 文件 token (账号: {name})")
        return token, name
    except Exception as e:
        log(f"❌ 读取 auth 文件失败: {e}")
        return None, ""


# ─── API 调用 ───────────────────────────────────────────
def _request(url: str, token: str) -> dict | None:
    req = urllib.request.Request(
        url,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
            "User-Agent": "WorkBuddy-Checkin/1.0",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        log(f"   HTTP {e.code}: {e.reason}")
        return None
    except Exception as e:
        log(f"   请求失败: {e}")
        return None


def get_checkin_status(token: str) -> dict | None:
    return _request(CHECKIN_STATUS_URL, token)


def claim_daily_checkin(token: str) -> dict | None:
    return _request(DAILY_CHECKIN_URL, token)


# ─── Server酱 通知 ─────────────────────────────────────
def send_wechat_notification(title: str, content: str, sendkey: str) -> bool:
    """推送消息到微信"""
    if not sendkey:
        return False
    url = SERVERCHAN_URL.format(sendkey=sendkey)
    payload = urllib.parse.urlencode({"title": title, "desp": content}).encode()
    req = urllib.request.Request(url, data=payload, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
            result = json.loads(resp.read().decode("utf-8"))
            if result.get("code") == 0:
                log(f"   ✅ 微信通知已发送")
                return True
            log(f"   ⚠️  微信通知失败: {result.get('message')}")
            return False
    except Exception as e:
        log(f"   ⚠️  微信通知异常: {e}")
        return False


# ─── 签到主流程 ─────────────────────────────────────────
def checkin() -> bool:
    log("=" * 56)
    log(f"  WorkBuddy 每日签到 --- {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    log("=" * 56)

    sendkey = os.environ.get("SERVERCHAN_SENDKEY", "")
    if _CLOUD_CONFIG_FILE.exists():
        try:
            sendkey = sendkey or json.loads(
                _CLOUD_CONFIG_FILE.read_text(encoding="utf-8")
            ).get("serverchan_sendkey", "")
        except Exception:
            pass

    log("步骤 1/3: 获取 accessToken...")
    token, account_name = load_access_token()
    if not token:
        log("❌ 无法获取 accessToken,签到终止。")
        send_wechat_notification(
            "❌ WorkBuddy 签到失败", f"账号: {account_name}\n未找到 accessToken", sendkey
        )
        return False

    log("\n步骤 2/3: 查询签到状态...")
    status_data = get_checkin_status(token)

    if status_data and status_data.get("today_checked_in", False):
        log("\nℹ️  今日已签到,无需重复领取。")
        send_wechat_notification(
            "✅ WorkBuddy 今日已签到", f"账号: {account_name}\n时间: {datetime.now()}", sendkey
        )
        return True

    log("\n步骤 3/3: 领取签到积分...")
    result = claim_daily_checkin(token)
    if result:
        points = result.get("points", result.get("reward_points", ""))
        log(f"\n✅ 签到成功! 获得积分: {points}")
        send_wechat_notification(
            "✅ WorkBuddy 签到成功",
            f"账号: {account_name}\n获得积分: +{points}\n时间: {datetime.now()}",
            sendkey,
        )
        return True

    log("\n❌ 签到失败")
    send_wechat_notification(
        "❌ WorkBuddy 签到失败", f"账号: {account_name}\n请检查 token 是否过期", sendkey
    )
    return False


if __name__ == "__main__":
    sys.exit(0 if checkin() else 1)

配置文件 config.json

json 复制代码
{
  "access_token": "你的_accessToken",
  "account_name": "你的昵称",
  "serverchan_sendkey": "你的_SendKey"
}

四、本地测试

bash 复制代码
# 方式 1:用环境变量
export WORKBUDDY_ACCESS_TOKEN="你的token"
export WORKBUDDY_ACCOUNT_NAME="你的昵称"
export SERVERCHAN_SENDKEY="你的SendKey"
python3 checkin.py

# 方式 2:用 config.json (推荐)
# 把 config.json 放到同目录,直接 python3 checkin.py

预期输出

yaml 复制代码
[2026-08-03 14:00:00] ========================================================
[2026-08-03 14:00:00]   WorkBuddy 每日签到 --- 2026-08-03 14:00:00
[2026-08-03 14:00:00] ========================================================
[2026-08-03 14:00:00] 步骤 1/3: 获取 accessToken...
[2026-08-03 14:00:00]    使用云端 config.json token (账号: X 先生)
...
[2026-08-03 14:00:00] ✅ 签到成功! 获得积分: 100
[2026-08-03 14:00:00]    ✅ 微信通知已发送

打开微信,"方糖"公众号会立刻收到推送


五、云端部署(Gitee Go)

5.1 创建私有仓库

登录 gitee.com新建仓库 → 选私有 (重要!token 不能公开)→ 起名 workbuddy-checkin

5.2 推送代码

bash 复制代码
cd workbuddy-checkin
git init
git remote add origin https://gitee.com/你的用户名/workbuddy-checkin.git
git add .
git commit -m "init: WorkBuddy 每日签到"
git push -u origin main

5.3 配置流水线

进入仓库 → 流水线 (Gitee Go) → 新建流水线:

  1. 基本信息 :名字设为 WorkBuddy 每日签到
  2. 流程编排
    • 删除默认的"主机部署"步骤
    • Python 构建 步骤里,构建命令填:python3 checkin.py
    • Python 版本选 3.11
  3. 高级设置定时触发
字段
0
5
小时 9
*
*
?
*

这个表达式 = 每天北京时间 09:05 触发

5.4 测试

回到流水线列表 → 点 "立即执行" → 看日志输出 + 微信是否收到通知。

云端跑通后,整套就完全自动了

  • 每天 09:05 Gitee Go 自动跑
  • 跑完签到脚本自动调 Server酱
  • 你微信收到通知
  • 不依赖本地电脑开不开机

六、方案对比

方案 优点 缺点
WorkBuddy 自动化 配置最简单 依赖本地电脑,断签风险高
macOS launchd 本地稳定,能利用 PowerNap 还是依赖电脑唤醒
Gitee Go + Server酱 不依赖电脑、微信通知 需要私有仓库
腾讯云函数 定时最准 配置复杂,有少量费用
GitHub Actions 国际化、文档全 国内访问慢

我的最终选择:Gitee Go + Server酱,国内访问快、维护简单、通知及时。


七、写在最后

核心思路其实就是把"本地自动化"升级成"云端自动化":

  • 任何需要定期执行的小任务,都可以按这个套路来
  • Token / API Key 用私有仓库 + 配置文件管理
  • 通知用 Server酱 这种"零成本"通道

希望对你有帮助,有问题欢迎评论区交流 👇

相关推荐
天天鸭2 小时前
5 万处中文的老项目实现国际化,如何用架构思维完成改造?
前端·javascript·架构
程序员黑豆2 小时前
鸿蒙应用开发之持久化存储解析:PersistentStorage / PersistenceV2 / preferences 选型与实战
前端·harmonyos
明月_清风2 小时前
🚀 OpenAI 数据代理架构全解析:从 600 PB 到自然语言的六层上下文工程
前端·后端·架构
明月_清风2 小时前
🚀 从 Foundry 到 AIP:Palantir 发生了什么变化?一篇文章全搞懂
前端·后端
西门啐血2 小时前
Vue 缓存之坑,变量赋值方式和响应式数据
前端·vue.js·缓存
京东云开发者2 小时前
实测 9 款 AI 架构图工具:从 Mermaid 美化到 GPT-Image2,一份选型清单
gpt·ai编程·笔记测评
涛涛ing2 小时前
2026 上半年,前端圈已经炸了五次
前端
小星星_20262 小时前
AI Coding Platform 六层架构设计:对标 Claude Code 的企业落地之路
ai编程
hunterandroid2 小时前
Android 后台任务可靠性排查:从 WorkManager 观测到失败重试闭环
android·前端