我宣布了自己死亡–github生命检测

共计 4286 个字符,预计需要花费 11 分钟才能阅读完成。

前一段时间死了么 app 火了一阵,没想到这么快我就要用上了。作者也得了绝症,也将不久人世,再见了~(无需过问)
自己简单搓了一个非 app 的,使用 github action 每天更新状态,action workflowk 可手动签到或死亡,死亡后自动更新 README.md 在自己的主页上。
我宣布了自己死亡 --github 生命检测
存活判定方式:

  • workflowk 手动签到;
  • 任务每天执行,7 天内没签到默认存活;


我宣布了自己死亡 --github 生命检测
死亡判定方式:
1. 超过 7 天未手动签到即宣布死亡。
2. 手动执行 workflowk 立即死亡。
我宣布了自己死亡 --github 生命检测

死亡后:
更新首页 README,宣布死亡消息(没了)。
因每个人的信息不同, 需要修改成自己的,项目名用自己的用户名(这样可以显示在自己主页上)
https://github.com/Zhu-junwei/Zhu-junwei/
自动任务 life-monitor.yml

name: Life Monitor

on:
  schedule:
    - cron: '00 19 * * *'
  workflow_dispatch:
    inputs:
      mode:
        description: '选择运行模式'
        required: true
        type: choice
        options:
          - 签到
          - 死亡

jobs:
  monitor:
    runs-on: ubuntu-24.04
    permissions:
      contents: write

    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Python
        uses: actions/setup-python@v7.1.0
        with:
          python-version: '3.13'

      - name: Run life monitor
        run: |
          MODE="${{github.event.inputs.mode}}"
          if ["$MODE" = "签到"]; then
            python life_monitor.py
          elif ["$MODE" = "死亡"]; then
            python life_monitor.py --force-death
          else
            # 定时触发:只检查不签到,超过 7 天自动宣告死亡
            python life_monitor.py --auto
          fi

      - name: Commit and push
        run: |
          MODE="${{github.event.inputs.mode}}"
          MSG="${MODE:- 自动签到}"
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add README.md .last_run
          git diff --cached --quiet || git commit -m "life monitor: $MSG"
          git push
 死亡逻辑 life_monitor.py
#!/usr/bin/env python3
"""生命监测系统"""

import os
import datetime

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATE_FILE = os.path.join(BASE_DIR, ".last_run")
README_PATH = os.path.join(BASE_DIR, "README.md")

MAX_DAYS = 7
BIRTH_DATE = datetime.date(1995, 4, 23)
BJ = datetime.timezone(datetime.timedelta(hours=8))

def read_last_run():
    if not os.path.exists(STATE_FILE):
        return None
    try:
        with open(STATE_FILE, "r", encoding="utf-8") as f:
            raw = f.read().strip()
        dt = datetime.datetime.fromisoformat(raw)
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=BJ)
        return dt
    except Exception:
        return None

def write_last_run(dt):
    with open(STATE_FILE, "w", encoding="utf-8") as f:
        f.write(dt.isoformat())

def now():
    return datetime.datetime.now(BJ)

def generate_alive_content(last_run, days, scan_time):
    lines = [f"🟢 上次存活时间: {last_run.strftime('%Y-%m-%d %H:%M:%S')} (UTC+8)",
        "",
        f"更新时间: {scan_time.strftime('%Y-%m-%d %H:%M:%S')} (UTC+8)",
    ]
    return "\n".join(lines)

def generate_obituary_content(last_run, days, scan_time, force_death=False):
    birth = BIRTH_DATE
    if force_death:
        # 手动确认死亡:死亡日期为当前扫描日期,保留真实最后存活时间
        death_date = scan_time.date()
        death_detail = ""death_reason =" 手动确认死亡。"days_line = f"> ** 距上次执行 **: {days} 天 "
    else:
        # 自动判定死亡:超过阈值,估算死亡日期
        death_date = (last_run + datetime.timedelta(days=MAX_DAYS)).date()
        death_detail = f"(最后手动执行后第 {MAX_DAYS} 天(估算))"
        death_reason = f"超过 {MAX_DAYS} 天未检测到生命体征,按协议发布讣告。"
        days_line = f"> ** 距上次执行 **: {days} 天"
    age = death_date.year - birth.year - ((death_date.month, death_date.day) < (birth.month, birth.day)) with open(os.path.join(BASE_DIR, "obituary.md"), "r", encoding="utf-8") as f: content = f.read() replacements = { "{{BIRTH_DATE}}": birth.strftime('%Y-%m-%d'), "{{BIRTH_LUNAR}}": "农历一九九五年三月廿四", "{{NAME}}": "朱俊伟", "{{DEATH_DATE}}": death_date.strftime('%Y-%m-%d'), "{{AGE}}": str(age), "{{MAX_DAYS}}": str(MAX_DAYS), "{{LAST_RUN}}": last_run.strftime('%Y-%m-%d %H:%M:%S'), "{{SCAN_TIME}}": scan_time.strftime('%Y-%m-%d %H:%M:%S'), "{{DEATH_DETAIL}}": death_detail, "{{DEATH_REASON}}": death_reason, "{{DAYS_LINE}}": days_line, } for key, value in replacements.items(): content = content.replace(key, value) return content def run(): import sys auto_mode = "--auto" in sys.argv force_death = "--force-death" in sys.argv scan_time = now() last_run = read_last_run() if force_death: # 死亡模式:不修改 .last_run,保留真实的上次存活时间 # 如果没有历史记录,用当前时间兜底 if last_run is None: last_run = scan_time elif not auto_mode: # 手动签到:更新 .last_run 为当前时间 write_last_run(scan_time) last_run = scan_time if last_run is None: days = 0 if force_death: # 没有历史记录但手动确认死亡 content = generate_obituary_content(scan_time, days, scan_time, force_death) else: content = generate_alive_content(scan_time, days, scan_time) else: days = (scan_time - last_run).days if force_death: # 手动确认死亡:直接生成讣告,不经过阈值判断 print(f"💀 手动确认死亡。最后存活时间: {last_run.strftime('%Y-%m-%d %H:%M:%S')}") content = generate_obituary_content(last_run, days, scan_time, force_death) elif days > MAX_DAYS:
            print(f"⚠️  距上次手动执行已过去 {days} 天,超过 {MAX_DAYS} 天阈值!")
            content = generate_obituary_content(last_run, days, scan_time, force_death)
        else:
            print(f"✅ 距上次手动执行 {days} 天,在 {MAX_DAYS} 天阈值内。")
            content = generate_alive_content(last_run, days, scan_time)

    with open(README_PATH, "w", encoding="utf-8") as f:
        f.write(content)

    print(f"📝 README.md 已更新")
    print(f"间隔: {days} 天 | 模式: {' 自动检查 'if auto_mode else (' 强制死亡 'if force_death else' 手动打卡 ')}")
    print(f"状态: {' 讣告 'if last_run and days > MAX_DAYS else' 正常 '}")

if __name__ == "__main__":
    run()

正文完
 0
suyan
版权声明:本站原创文章,由 suyan 于2026-11-04发表,共计4286字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件QQ邮箱:suyanw520@163.com 与我们联系处理。敬请谅解!
评论(没有评论)
验证码