iStoreOS GitHub 提交监控青龙面板脚本

一个简单的青龙面板脚本,使用青龙面板可以每天定时收获iStoreOS的最新更新进展:

#!/usr/bin/env python3
# coding:utf-8

"""
2025.7.18
iStoreOS GitHub 提交监控脚本 - 按提交顺序排序
环境变量:GITHUB_TOKEN
github令牌需要repo权限
"""

import os
import sys
import requests
import time
from datetime import datetime, timedelta
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(script_dir)

# 指定目标分支
TARGET_BRANCH = "istoreos-24.10"
REPO_URL = f"https://api.github.com/repos/istoreos/istoreos/commits?sha={TARGET_BRANCH}"
STATE_FILE = os.path.join(script_dir, f"istoreos_commit_state_{TARGET_BRANCH}.txt")
MAX_COMMITS = 50

notification_list = []

def safe_send(title, content):
    """安全发送通知 - 优化换行处理"""
    try:
        from notify import send as ql_send
        print("✅ 使用青龙通知模块")
        ql_send(title, content)
        return True
    except ImportError:
        print("⚠️ 使用内置简单通知功能")
        print(f"📢 {title}\n{content}")
        return True
    except Exception as e:
        print(f"❌ 通知发送失败: {e}")
        print(f"📢 {title}\n{content}")
        return False

def get_env(name):
    """获取环境变量值"""
    return os.environ.get(name) or os.environ.get(f"QL_{name}")

def add_notification(title, content):
    """添加到通知列表 - 使用简洁文本格式"""
    notification_list.append(f"【{title}】\n{content}")
    print(f"📢 添加通知: {title}")

def send_notifications():
    """发送所有通知 - 优化换行处理"""
    if not notification_list:
        print("🟢 无通知内容,跳过发送")
        return
    
    title = "📢 iStoreOS 项目每日更新"
    content = "\n\n".join(notification_list)
    content += f"\n\n⏰ 更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}"
    safe_send(title, content)

def get_last_commit():
    """获取上次处理的提交ID"""
    try:
        if os.path.exists(STATE_FILE):
            with open(STATE_FILE, "r") as f:
                return f.read().strip()
        return None
    except Exception as e:
        print(f"❌ 读取状态文件失败: {e}")
        return None

def save_last_commit(commit_id):
    """保存最新提交ID"""
    try:
        with open(STATE_FILE, "w") as f:
            f.write(commit_id)
        print(f"✅ 已保存最新提交ID: {commit_id[:7]}")
    except Exception as e:
        print(f"❌ 保存状态失败: {e}")

def format_relative_time(dt):
    """格式化时间差为中文描述"""
    now = datetime.utcnow()
    diff = now - dt
    
    if diff < timedelta(minutes=1):
        return "刚刚"
    elif diff < timedelta(hours=1):
        return f"{int(diff.seconds / 60)} 分钟前"
    elif diff < timedelta(days=1):
        return f"{int(diff.seconds / 3600)} 小时前"
    elif diff < timedelta(days=2):
        return "昨天"
    else:
        return f"{diff.days} 天前"

def format_date_header(dt):
    """优化日期标题格式"""
    return f"{dt.year}-{dt.month}-{dt.day}"

def create_session():
    """创建带重试机制的HTTP会话"""
    session = requests.Session()
    retry_strategy = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504],
        allowed_methods=["GET"]
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.verify = '/etc/ssl/certs/ca-certificates.crt'
    return session

def process_commits():
    """处理GitHub提交更新 - 保持原始提交顺序"""
    GITHUB_TOKEN = get_env("GITHUB_TOKEN")
    if not GITHUB_TOKEN:
        error_msg = (
            "❌ 未配置GITHUB_TOKEN环境变量\n"
            "请在青龙面板中添加您的GitHub访问令牌\n"
            "创建地址: https://github.com/settings/tokens"
        )
        add_notification("配置错误", error_msg)
        return False
    
    last_commit = get_last_commit()
    session = create_session()
    headers = {
        "Authorization": f"token {GITHUB_TOKEN}",
        "User-Agent": "QingLong iStoreOS Monitor",
        "Accept": "application/vnd.github.v3+json"
    }
    
    try:
        print(f"🔍 正在获取 {TARGET_BRANCH} 分支的提交记录...")
        response = session.get(
            REPO_URL,
            headers=headers,
            params={"per_page": MAX_COMMITS},
            timeout=15
        )
        
        if response.status_code != 200:
            error_msg = f"❌ GitHub API错误: {response.status_code}\n响应内容: {response.text[:200]}"
            add_notification("API错误", error_msg)
            return False
            
        commits = response.json()
        if not commits:
            add_notification("无数据", "GitHub API未返回提交记录")
            return False
            
        current_latest = commits[0]['sha']
        if last_commit and last_commit != current_latest:
            save_last_commit(current_latest)
        elif not last_commit:
            save_last_commit(current_latest)
        
        three_days_ago = datetime.utcnow() - timedelta(days=3)
        recent_commits = []
        
        # 新的提交在前
        for commit in commits:
            commit_data = commit['commit']
            commit_time = datetime.strptime(commit_data['author']['date'], "%Y-%m-%dT%H:%M:%SZ")
            if commit_time < three_days_ago:
                continue
                
            author = commit_data['author']['name']
            message = commit_data['message'].split('\n')[0].strip()
            commit_id = commit['sha'][:7]
            
            recent_commits.append({
                "id": commit_id,
                "time": commit_time,
                "author": author,
                "message": message,
                "url": f"https://github.com/istoreos/istoreos/commit/{commit['sha']}"
            })
        
        if not recent_commits:
            content = "✅ 最近三天无新提交"
            add_notification("提交更新", content)
            return True
            
        # 顺序
        content = f"📂 仓库分支: https://github.com/istoreos/istoreos/commits/{TARGET_BRANCH}\n"
        content += f"📆 最新时段: {three_days_ago.strftime('%Y-%m-%d')} 至 {datetime.utcnow().strftime('%Y-%m-%d')}\n"
        content += f"📊 时段内提交数: {len(recent_commits)}\n"
        content += "=" * 20 + "\n"
        
        # 输出
        for commit in recent_commits:
            date_header = format_date_header(commit['time'])
            content += f"\n【{date_header}】\n"
            content += f"⏰ 时间: {format_relative_time(commit['time'])}\n"
            content += f"📝 信息: {commit['message']}\n"
            content += f"👤 作者: {commit['author']}\n"
            content += f"🔖 ID: {commit['id']}\n"
            content += f"🔗 链接: {commit['url']}\n"
        
        add_notification("提交更新", content)
        return True
        
    except Exception as e:
        import traceback
        error_msg = f"❌ 处理失败: {str(e)}\n{traceback.format_exc()}"
        add_notification("处理错误", error_msg)
        return False

if __name__ == "__main__":
    print("=" * 40)
    print(f"🕒 iStoreOS 提交监控任务启动 (分支: {TARGET_BRANCH})")
    print(f"📅 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    print("=" * 40)
    
    start_time = time.time()
    success = process_commits()
    elapsed = time.time() - start_time
    
    print("=" * 40)
    print(f"{'✅ 成功' if success else '❌ 失败'} | 耗时: {elapsed:.2f}秒")
    print(f"⏰ 结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    print("=" * 40)
    
    send_notifications()
    sys.exit(0 if success else 1)

我使用的是WxPusher接收的。


当然上个脚本太简化了,今天又鼓捣了一下,分分类,区分一下提交Issues和PR,所以下一个脚本就不太精简了,喜欢的的也可以用这个,重点是,不止可以监控一个项目,自己喜欢的项目都可以监控更新状况:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
青龙面板 GitHub 项目监控脚本
功能类似于 GitHubSentinel,但适配青龙面板环境
"""

import os
import sys
import json
import requests
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any

# ==================== 配置区域 ====================
# 在此处设置要监控的 GitHub 仓库列表
MONITORED_REPOS = [
    "istoreos/istoreos",
    # 添加更多仓库...
]

# 监控时间范围(天)
MONITOR_DAYS = 7

# 报告格式选择: "markdown" 或 "wechat" 或 "wxpusher"
REPORT_FORMAT = "wxpusher"

# ==================== 配置结束 ====================

# 配置常量
STATE_FILE = "github_monitor_state.json"
MAX_RETRIES = 3
RETRY_DELAY = 5
DEFAULT_HEADERS = {
    "User-Agent": "GitHub-Monitor-Qinglong/1.0.0",
    "Accept": "application/vnd.github.v3+json"
}

# 全局变量
notification_list = []


def get_env(name: str) -> Optional[str]:
    """获取环境变量"""
    return os.environ.get(name) or os.environ.get(f"QL_{name}")


def safe_send(title: str, content: str) -> bool:
    """安全发送通知 - 适配青龙面板"""
    try:
        # 青龙面板的通知模块
        from notify import send as ql_send
        print("✅ 使用青龙通知模块")
        ql_send(title, content)
        return True
    except ImportError:
        print("⚠️ 使用内置简单通知功能")
        print(f"📢 {title}\n{content}")
        return True
    except Exception as e:
        print(f"❌ 通知发送失败: {e}")
        print(f"📢 {title}\n{content}")
        return False


def add_notification(title: str, content: str) -> None:
    """添加到通知列表"""
    notification_list.append(f"【{title}】\n{content}")
    print(f"📢 添加通知: {title}")


def send_notifications() -> None:
    """发送所有通知"""
    if not notification_list:
        print("🟢 无通知内容,跳过发送")
        return

    title = "📢 GitHub 项目监控报告"
    content = "\n\n".join(notification_list)
    content += f"\n\n⏰ 更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}"
    safe_send(title, content)


def load_state() -> Dict[str, Any]:
    """加载状态文件"""
    try:
        if os.path.exists(STATE_FILE):
            with open(STATE_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        return {}
    except Exception as e:
        print(f"❌ 读取状态文件失败: {e}")
        return {}


def save_state(state: Dict[str, Any]) -> None:
    """保存状态文件"""
    try:
        with open(STATE_FILE, 'w', encoding='utf-8') as f:
            json.dump(state, f, ensure_ascii=False, indent=2)
        print("✅ 状态文件保存成功")
    except Exception as e:
        print(f"❌ 保存状态文件失败: {e}")


def format_relative_time(dt: datetime) -> str:
    """格式化相对时间"""
    now = datetime.utcnow()
    diff = now - dt

    if diff < timedelta(minutes=1):
        return "刚刚"
    elif diff < timedelta(hours=1):
        return f"{int(diff.seconds / 60)} 分钟前"
    elif diff < timedelta(days=1):
        return f"{int(diff.seconds / 3600)} 小时前"
    elif diff < timedelta(days=2):
        return "昨天"
    else:
        return f"{diff.days} 天前"


def create_session() -> requests.Session:
    """创建HTTP会话"""
    session = requests.Session()
    session.headers.update(DEFAULT_HEADERS)
    return session


class GitHubMonitor:
    """GitHub监控器"""

    def __init__(self):
        self.session = create_session()
        self.github_token = get_env("GITHUB_TOKEN")
        if self.github_token:
            self.session.headers.update({
                "Authorization": f"token {self.github_token}"
            })

    def get_repo_info(self, owner: str, repo: str) -> Optional[Dict[str, Any]]:
        """获取仓库基本信息"""
        url = f"https://api.github.com/repos/{owner}/{repo}"
        try:
            response = self.session.get(url, timeout=30)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"❌ 获取仓库信息失败 {owner}/{repo}: {e}")
            return None

    def get_recent_commits(self, owner: str, repo: str, since: Optional[datetime] = None) -> List[Dict[str, Any]]:
        """获取最近提交"""
        url = f"https://api.github.com/repos/{owner}/{repo}/commits"
        params = {"per_page": 10}
        
        if since:
            params["since"] = since.isoformat() + "Z"

        try:
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"❌ 获取提交记录失败 {owner}/{repo}: {e}")
            return []

    def get_recent_issues(self, owner: str, repo: str, days: int = MONITOR_DAYS) -> List[Dict[str, Any]]:
        """获取最近的 Issues"""
        url = f"https://api.github.com/repos/{owner}/{repo}/issues"
        cutoff_date = (datetime.utcnow() - timedelta(days=days)).isoformat() + "Z"
        params = {
            "state": "all",
            "sort": "updated",
            "direction": "desc",
            "per_page": 10,
            "since": cutoff_date
        }

        try:
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"❌ 获取 Issues 失败 {owner}/{repo}: {e}")
            return []

    def get_recent_pull_requests(self, owner: str, repo: str, days: int = MONITOR_DAYS) -> List[Dict[str, Any]]:
        """获取最近的 Pull Requests"""
        url = f"https://api.github.com/repos/{owner}/{repo}/pulls"
        cutoff_date = (datetime.utcnow() - timedelta(days=days)).isoformat() + "Z"
        params = {
            "state": "all",
            "sort": "updated",
            "direction": "desc",
            "per_page": 10,
            "since": cutoff_date
        }

        try:
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"❌ 获取 Pull Requests 失败 {owner}/{repo}: {e}")
            return []

    def format_repo_report(self, owner: str, repo: str, data: Dict[str, Any]) -> str:
        """格式化仓库报告"""
        if REPORT_FORMAT == "markdown":
            return self._format_repo_report_markdown(owner, repo, data)
        elif REPORT_FORMAT == "wechat":
            return self._format_repo_report_wechat(owner, repo, data)
        elif REPORT_FORMAT == "wxpusher":
            return self._format_repo_report_wxpusher(owner, repo, data)
        else:
            # 默认使用 wxpusher 格式
            return self._format_repo_report_wxpusher(owner, repo, data)

    def _format_repo_report_markdown(self, owner: str, repo: str, data: Dict[str, Any]) -> str:
        """格式化 Markdown 仓库报告"""
        repo_info = data.get("repo_info", {})
        commits = data.get("commits", [])
        issues = data.get("issues", [])
        pull_requests = data.get("pull_requests", [])

        report_lines = [
            f"📦 {owner}/{repo} 项目更新报告",
            "=" * 40,
            f"📊 仓库概览",
            f"  描述: {repo_info.get('description', 'N/A')}",
            f"  语言: {repo_info.get('language', 'N/A')} | ⭐ Stars: {repo_info.get('stargazers_count', 0):,}",
            f"  🍴 Forks: {repo_info.get('forks_count', 0):,} | ❗ Issues: {repo_info.get('open_issues_count', 0):,}",
            ""
        ]

        # 提交部分
        report_lines.extend([
            "📝 最新提交",
            "-" * 20
        ])

        if commits:
            for i, commit in enumerate(commits[:5]):  # 只显示前5个提交
                commit_info = commit.get("commit", {})
                author = commit_info.get("author", {})
                commit_time = datetime.strptime(author.get("date", ""), "%Y-%m-%dT%H:%M:%SZ")
                message = commit_info.get("message", "").split("\n")[0][:60]  # 限制消息长度
                sha = commit.get("sha", "")[:7]
                
                report_lines.append(f"{i+1}. {sha} {message}")
                report_lines.append(f"   @{author.get('name', 'N/A')} | {format_relative_time(commit_time)}")
        else:
            report_lines.append("暂无新提交")

        # Issues部分
        report_lines.extend([
            "",
            "❗ 最新 Issues",
            "-" * 20
        ])

        if issues:
            for i, issue in enumerate(issues[:5]):  # 只显示前5个issues
                created_at = datetime.strptime(issue.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state_icon = "✅" if issue.get("state") == "closed" else "❗"
                title = issue.get('title', 'N/A')[:50]  # 限制标题长度
                
                report_lines.append(f"{i+1}. {state_icon} #{issue.get('number', '')} {title}")
                report_lines.append(f"   更新: {format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Issues")

        # Pull Requests部分
        report_lines.extend([
            "",
            "📦 最新 Pull Requests",
            "-" * 20
        ])

        if pull_requests:
            for i, pr in enumerate(pull_requests[:5]):  # 只显示前5个PR
                created_at = datetime.strptime(pr.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state = pr.get("state", "N/A")
                state_icon = "✅" if state == "closed" else "🔄" if state == "open" else "🔁"
                title = pr.get('title', 'N/A')[:50]  # 限制标题长度
                
                report_lines.append(f"{i+1}. {state_icon} #{pr.get('number', '')} {title}")
                report_lines.append(f"   状态: {state} | 创建: {format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Pull Requests")

        return "\n".join(report_lines)

    def _format_repo_report_wechat(self, owner: str, repo: str, data: Dict[str, Any]) -> str:
        """格式化微信公众号风格的仓库报告"""
        repo_info = data.get("repo_info", {})
        commits = data.get("commits", [])
        issues = data.get("issues", [])
        pull_requests = data.get("pull_requests", [])

        report_lines = [
            f"【{owner}/{repo} 项目更新】",
            "",
            f"📈 仓库概览",
            f"描述:{repo_info.get('description', 'N/A')}",
            f"语言:{repo_info.get('language', 'N/A')}",
            f"⭐ Stars:{repo_info.get('stargazers_count', 0):,}",
            f"🍴 Forks:{repo_info.get('forks_count', 0):,}",
            f"❗ Issues:{repo_info.get('open_issues_count', 0):,}",
            ""
        ]

        # 提交部分
        report_lines.extend([
            "📝 最近提交"
        ])

        if commits:
            for i, commit in enumerate(commits[:5]):  # 只显示前5个提交
                commit_info = commit.get("commit", {})
                author = commit_info.get("author", {})
                commit_time = datetime.strptime(author.get("date", ""), "%Y-%m-%dT%H:%M:%SZ")
                message = commit_info.get("message", "").split("\n")[0][:50]  # 限制消息长度
                sha = commit.get("sha", "")[:7]
                
                report_lines.append(f"{i+1}. {sha} {message}")
                report_lines.append(f"   作者:{author.get('name', 'N/A')}  {format_relative_time(commit_time)}")
        else:
            report_lines.append("暂无新提交")

        # Issues部分
        report_lines.extend([
            "",
            "❗ 最近 Issues"
        ])

        if issues:
            for i, issue in enumerate(issues[:5]):  # 只显示前5个issues
                created_at = datetime.strptime(issue.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state_text = "已关闭" if issue.get("state") == "closed" else "开启中"
                title = issue.get('title', 'N/A')[:40]  # 限制标题长度
                
                report_lines.append(f"{i+1}. #{issue.get('number', '')} {title}")
                report_lines.append(f"   状态:{state_text}  更新:{format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Issues")

        # Pull Requests部分
        report_lines.extend([
            "",
            "📦 最近 Pull Requests"
        ])

        if pull_requests:
            for i, pr in enumerate(pull_requests[:5]):  # 只显示前5个PR
                created_at = datetime.strptime(pr.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state = pr.get("state", "N/A")
                state_text = "已合并" if state == "closed" else "待处理" if state == "open" else state
                title = pr.get('title', 'N/A')[:40]  # 限制标题长度
                
                report_lines.append(f"{i+1}. #{pr.get('number', '')} {title}")
                report_lines.append(f"   状态:{state_text}  创建:{format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Pull Requests")

        return "\n".join(report_lines)

    def _format_repo_report_wxpusher(self, owner: str, repo: str, data: Dict[str, Any]) -> str:
        """格式化 wxpusher 风格的仓库报告"""
        repo_info = data.get("repo_info", {})
        commits = data.get("commits", [])
        issues = data.get("issues", [])
        pull_requests = data.get("pull_requests", [])

        report_lines = [
            f"【{owner}/{repo} 项目更新】",
            "",
            f"📈 仓库概览",
            f"描述:{repo_info.get('description', 'N/A')}",
            f"语言:{repo_info.get('language', 'N/A')}",
            f"⭐ Stars:{repo_info.get('stargazers_count', 0):,}",
            f"🍴 Forks:{repo_info.get('forks_count', 0):,}",
            f"❗ Issues:{repo_info.get('open_issues_count', 0):,}",
            ""
        ]

        # 提交部分
        report_lines.extend([
            "📝 最近提交"
        ])

        if commits:
            for i, commit in enumerate(commits[:5]):  # 只显示前5个提交
                commit_info = commit.get("commit", {})
                author = commit_info.get("author", {})
                commit_time = datetime.strptime(author.get("date", ""), "%Y-%m-%dT%H:%M:%SZ")
                message = commit_info.get("message", "").split("\n")[0][:50]  # 限制消息长度
                sha = commit.get("sha", "")[:7]
                
                report_lines.append(f"{i+1}. {sha} {message}")
                report_lines.append(f"   作者:{author.get('name', 'N/A')}  {format_relative_time(commit_time)}")
        else:
            report_lines.append("暂无新提交")

        # Issues部分
        report_lines.extend([
            "",
            "❗ 最近 Issues"
        ])

        if issues:
            for i, issue in enumerate(issues[:5]):  # 只显示前5个issues
                created_at = datetime.strptime(issue.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state_text = "已关闭" if issue.get("state") == "closed" else "开启中"
                title = issue.get('title', 'N/A')[:40]  # 限制标题长度
                
                report_lines.append(f"{i+1}. #{issue.get('number', '')} {title}")
                report_lines.append(f"   状态:{state_text}  更新:{format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Issues")

        # Pull Requests部分
        report_lines.extend([
            "",
            "📦 最近 Pull Requests"
        ])

        if pull_requests:
            for i, pr in enumerate(pull_requests[:5]):  # 只显示前5个PR
                created_at = datetime.strptime(pr.get("created_at", ""), "%Y-%m-%dT%H:%M:%SZ")
                state = pr.get("state", "N/A")
                state_text = "已合并" if state == "closed" else "待处理" if state == "open" else state
                title = pr.get('title', 'N/A')[:40]  # 限制标题长度
                
                report_lines.append(f"{i+1}. #{pr.get('number', '')} {title}")
                report_lines.append(f"   状态:{state_text}  创建:{format_relative_time(created_at)}")
        else:
            report_lines.append("暂无新 Pull Requests")

        return "\n".join(report_lines)

    def monitor_repository(self, owner: str, repo: str) -> bool:
        """监控单个仓库"""
        print(f"🔍 开始监控仓库: {owner}/{repo}")
        
        # 获取仓库信息
        repo_info = self.get_repo_info(owner, repo)
        if not repo_info:
            add_notification("监控失败", f"无法获取仓库信息: {owner}/{repo}")
            return False

        # 加载状态
        state = load_state()
        last_check_key = f"{owner}/{repo}_last_check"
        last_check_time = state.get(last_check_key)
        
        # 计算上次检查时间
        since_time = None
        if last_check_time:
            try:
                since_time = datetime.fromisoformat(last_check_time)
            except ValueError:
                pass

        # 获取最新数据
        commits = self.get_recent_commits(owner, repo, since_time)
        issues = self.get_recent_issues(owner, repo)
        pull_requests = self.get_recent_pull_requests(owner, repo)

        # 准备数据
        data = {
            "repo_info": repo_info,
            "commits": commits,
            "issues": issues,
            "pull_requests": pull_requests
        }

        # 生成报告
        report = self.format_repo_report(owner, repo, data)
        
        # 只有当有更新时才发送通知
        if commits or issues or pull_requests:
            add_notification(f"{owner}/{repo} 更新报告", report)
            print(f"✅ 仓库监控完成并生成报告: {owner}/{repo}")
        else:
            print(f"✅ 仓库无更新: {owner}/{repo}")
        
        # 更新状态
        state[last_check_key] = datetime.utcnow().isoformat()
        save_state(state)
        
        return True


def main():
    """主函数"""
    print("=" * 50)
    print("🚀 GitHub 项目监控脚本启动")
    print(f"📅 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    print("=" * 50)

    # 检查监控的仓库列表
    if not MONITORED_REPOS:
        add_notification("配置错误", "未设置要监控的仓库,请在脚本中配置 MONITORED_REPOS")
        send_notifications()
        return False

    # 创建监控器
    monitor = GitHubMonitor()
    
    # 检查 GitHub Token
    if not monitor.github_token:
        warning_msg = (
            "⚠️ 未配置 GITHUB_TOKEN 环境变量\n"
            "建议配置 GitHub Token 以避免 API 限制\n"
            "创建地址: https://github.com/settings/tokens"
        )
        add_notification("警告", warning_msg)

    # 监控所有仓库
    success_count = 0
    error_count = 0
    
    for repo_full_name in MONITORED_REPOS:
        try:
            if "/" not in repo_full_name:
                print(f"❌ 仓库格式错误: {repo_full_name}")
                continue
                
            owner, repo = repo_full_name.split("/", 1)
            if monitor.monitor_repository(owner, repo):
                success_count += 1
            else:
                error_count += 1
        except Exception as e:
            error_count += 1
            print(f"❌ 监控仓库失败 {repo_full_name}: {e}")

    print("=" * 50)
    print(f"📊 监控完成 - 成功: {success_count}, 失败: {error_count}")
    print(f"⏰ 结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    print("=" * 50)

    send_notifications()
    return error_count == 0


if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)
1 个赞