解决github幽灵通知问题

起因

今天打开 github 发现右上角有通知,打开列表发现该通知被归到一个名为ycombiiinator/-co的项目,点开却没有通知内容,这就有点诡异了。
在社区反馈中找到这样一个 issue : Bug:ghost notifications
看来有很多人有同样的问题,令人意外的是,这个帖子已经存在好几年,官方仍未修复。

解决

通过请求 github 的 API /notifications/threads/{thread_id} 将该通知设为 done 即可。

API说明 (请求必须使用 tokens (classic),不支持 Fine-grained tokens)
获取Token (需要勾选 notifications 权限)

自动化脚本

import urllib.request
import json

# ⚠️ Replace this with your GitHub personal access token (must include notifications scope)
GITHUB_TOKEN = "your_personal_access_token_here"

BASE_URL = "https://api.github.com"
HEADERS = {
    "Authorization": f"Bearer {GITHUB_TOKEN}",
    "Accept": "application/vnd.github+json",
    "User-Agent": "Python-urllib"  # GitHub requires a User-Agent header
}

def api_request(url, method="GET"):
    """Make an HTTP request to the GitHub API and return (status, body)."""
    req = urllib.request.Request(url, method=method, headers=HEADERS)
    try:
        with urllib.request.urlopen(req) as resp:
            status = resp.getcode()
            body = resp.read().decode("utf-8")
            return status, body
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode("utf-8")
    except urllib.error.URLError as e:
        return None, str(e)

def list_notifications():
    """Fetch notifications from GitHub."""
    url = f"{BASE_URL}/notifications"
    status, body = api_request(url)
    if status != 200:
        print(f"Error fetching notifications: {status}")
        print(body)
        return []
    return json.loads(body)

def mark_thread_done(thread_id):
    """Mark a notification thread as Done (archive it)."""
    url = f"{BASE_URL}/notifications/threads/{thread_id}"
    status, body = api_request(url, method="DELETE")
    if status == 204:
        print(f"✅ Thread {thread_id} marked as Done")
    else:
        print(f"❌ Failed to mark thread {thread_id} as Done: {status}")
        print(body)

def main():
    notifications = list_notifications()
    if not notifications:
        print("No notifications found or failed to fetch notifications.")
        return

    print("\n📬 Current notifications:")
    for idx, n in enumerate(notifications, start=1):
        repo = n["repository"]["full_name"]
        title = n["subject"]["title"]
        notif_type = n["subject"]["type"]
        thread_id = n["id"]
        unread = n.get("unread", False)
        print(f"{idx}. [{repo}] ({notif_type}) {title} → thread_id={thread_id} unread={unread}")

    while True:
        inp = input("\nEnter notification numbers to mark as Done (q to quit): ").strip()
        if inp.lower() == 'q':
            break

        # Support both spaces and commas as separators
        parts = [p for p in inp.replace(',', ' ').split() if p.isdigit()]
        if not parts:
            print("⚠️ Invalid input. Please enter one or more numbers separated by space or comma.")
            continue

        indices = [int(p) for p in parts if 1 <= int(p) <= len(notifications)]
        if not indices:
            print("⚠️ No valid numbers found in input.")
            continue

        for idx in indices:
            selected = notifications[idx - 1]
            mark_thread_done(selected["id"])

if __name__ == "__main__":
    main()
posted @ 2025-09-26 10:00  一克猫  阅读(54)  评论(0)    收藏  举报