使用 API 订阅 GitHub 的新消息通知 Notifications

本帖算是 尝试用浏览器查看论坛 RSS 订阅 的延续。在那个帖子中我介绍了 RSSHub,里面也提供了订阅 GitHub Notifications 的 feed。但是,由于获取数据需要使用 GitHub Access Token,可能是出于安全考虑,因而只有本地部署 RSSHub 的选项。这样一来呢,每次开机都必须要自启动 Docker。像我这样 GitHub 没什么新通知也根本不用 Docker 的人,也不太可能为了接 RSS 安个软件。此外,GitHub 也有邮件通知的设置,但有时也不是每个通知都想要邮件。这时,就可以用到类似本帖的订阅方式。

虽然我觉得有这个需求的人都能自己写,不过写都写了就发一下吧。这里用 DataviewJS 实现。

241209: 更新了通知距离当前时间的计算方式。顺带一提之前修复了获取不到首发帖子的问题。
240125: PR 的 comments api url 路径不是 +/comments 的格式,还是得分情况讨论。已修。

DataviewJS 代码
const token = '你的 Token'
const conf = {
  method: 'GET',
  headers: {
    'Accept': 'application/vnd.github+json',
    'Authorization': `Bearer ${token}`,
  },
}
const fetchUrl = async (url, conf)=> {
  try {
    const res = await fetch(url, conf)
    if (!res.ok) throw new Error(res.status)
    return await res.json()
  } catch (err) {
    console.error(err.message)
    throw err // 重新抛出错误以便处理
  }
}
const dateDiff = (t1, t2)=> {
  if (t1 > t2) return;
  else {
    const minutes = (t2 - t1) / 6e4
    const hours = minutes / 60
    const days = hours / 24
    const weeks = days / 7
    const half_trunc = (num)=> Math.trunc(num * 2) / 2
    if (weeks > 4) return '很久';
    else if (weeks >= 1) return `${half_trunc(weeks)} 周前`;
    else if (days >= 1) return `${half_trunc(days)} 天前`;
    else if (hours >= 1) return `${half_trunc(hours)} 时前`;
    else return `${Math.trunc(minutes)} 分前`
  }
}
const icon = '<font color="#1f6feb">☼</font>'
const getDial = (time1, time2, curr)=> {
  const t1 = new Date(time1)
  const t2 = new Date(time2)
  const diff = dateDiff(t2, curr)
  return (t1 > t2) ? icon : diff
}
const pickLatest = new class {
  main = async ({type, url}, conf)=> {
    const getOPost = async ()=> await fetchUrl(url, conf)
    let cmtUrl, oPost
    if (type == 'PullRequest') {
      oPost = await getOPost()
      cmtUrl = oPost.comments_url
    }
    else cmtUrl = `${url}/comments`
    const cmts = await fetchUrl(cmtUrl, conf)
    // Original Post is not considered as a comment.
    const post = cmts[0] ? cmts.pop() : (oPost || await getOPost())
    return this.formPost(post)
  }
  limit = 420
  formPost = ({body, html_url, user})=> {
    const lines = this.trimTrailing(body.split('\r\n'))
    const parag = lines.join('\n')
    const _body = (parag.length > this.limit)
      ? parag.slice(0, this.limit) + '\n-<more>'
      : parag
    return {
      body: '````markdown\n' + _body + '\n````', html_url,
      user: `![|20](<${user.avatar_url}>) ${user.login}`,
    }
  }
  trimTrailing = (arr)=> {
    let index = arr.length - 1
    while (index > 0 && arr[index] === '') index--
    return arr.slice(0, index + 1)
  }
}
const curr = new Date()
const liveUrl = `https://api.github.com/notifications?${curr.getTime()}`
const threads = await fetchUrl(liveUrl, conf), data = []
for (const thread of threads) {
  const { last_read_at, updated_at, subject } = thread
  const { title } = subject
  const dial = getDial(last_read_at, updated_at, curr)
  if (!subject.url) {
    const link = `[${dial}](https://github.com/notifications)`
    data.push(`${thread.reason.toUpperCase()} ${link} ${title}`)
  }
  else {
    const latest = await pickLatest.main(subject, conf)
    const link = `[${dial}](<${latest.html_url}>)`
    data.push(`${latest.user} ${link} ${title}\n\n${latest.body}`)
  }
}
dv.paragraph(data.join('\n\n')||'🎉 No further', {cls: 'gitbox'})
申请 Token 大致步骤

地址:https://github.com/settings/tokens,或点击头像 - Settings - 左侧滑到底部 Developer settings - Personal access tokens - Tokens (classic)。

Generate new token 继续设置:

Select scopes 向下滑,无其他需求只勾选 notifications 即可。

image

效果,无新消息时:image

GitHub 的 API 只会获取到未读状态的信息。这里我手动将状态设置为未读来进行测试:

原始通知

image

如何设置为未读

imageimage

类型依次为 ci_activity、PullRequest、Issue 和 Discussion。

1 个赞