一个简单的青龙面板脚本,使用青龙面板可以每天定时收获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)
当然上个脚本太简化了,今天又鼓捣了一下,分分类,区分一下提交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)

