yihong0618 / 2021

关于我的 2021 的一些记录。
MIT License
274 stars 17 forks source link

如何用一个仓库记录自己的一年 #19

Closed yihong0618 closed 3 years ago

yihong0618 commented 3 years ago

写在前面

从最开始的用 GitHub 的 Issues 写博客,到尝试用 GitHub 记录的年度数据已经一年有余了,从最开始有想法 2020, 到 2021 加了很多功能,把大部分的记录自动化,一点一点记录也算是有些心得了,这篇文章就介绍一下我是怎么做了,能帮助到同样感兴趣的大家就更好了。也算是践行这 2 年对我影响最大的文章之一

People Die, but Long Live GitHub

GitHub 的一个 repo 能做什么?

  1. 能记录 Issues
  2. Issues 可以评论
  3. 能给 issue 打标签
  4. 能有一张展示的 README
  5. README 能引入 svg
  6. 有 Actions 可以辅助自动化
  7. Actions 可以放 secrets
  8. 可以用 cron 和各种事件触发 Actions
  9. API 公开,可以自己 DIY
  10. 有手机应用,不用开电脑能随时随地记录
  11. 有评论区
  12. 私有仓库这些以上的都有

好,我们把这些结合起来,记录自己的一年~

数字区

image 上图这些数字区是怎么实现方式 分为两部分

Issues 的代码思路为获取 label -> 通过 label 找 issues -> issues 的评论特定格式 -> 通过函数解析 -> 整合 -> 通过正则替换 README 中的原有数据 (README 可以写注释,而注释是不显示的,利用这个完成显示和替换)

def main(
    login_dict,
    github_token,
    repo_name,
):
    my_num_stat_str = MY_NUMBER_STAT_HEAD
    # API STAT STR
    for name, value_dict in MY_STATUS_DICT_FROM_API.items():
        try:
            url = value_dict.get("url")
            md_name = f"[{name}]({url})"
            # maybe a better way?
            total_data, streak, today_check = value_dict.get("daily_func")(
                *login_dict.get(name, tuple())
            )
            total_data_str = str(total_data) + value_dict.get("unit_str", "")
            my_num_stat_str += make_stat_str(
                md_name, total_data_str, streak, today_check
            )
        # just a tricky code for others for use
        except Exception as e:
            print(e)
            continue

    u = Github(github_token)
    # COMMENTS STAT STR
    for name, value_dict in MY_STATUS_DICT_FROM_COMMENTS.items():
        try:
            labels, map_func, reduce_func = LABEL_DAILY_DICT.get(name)
        except:
            # tricky for mine
            continue
        func = value_dict.get("daily_func")
        if not func:
            break

        issues = u.get_repo(repo_name).get_issues(labels=labels)
        total_data, streak, today_check, url, month_summary_dict = func(
            issues, map_func, reduce_func
        )
        # change the issue body for month summary
        unit = value_dict.get("unit_str", "")
        for i in issues:
            body = ""
            for b in i.body.splitlines():
                # from the summary table
                if b.startswith("|"):
                    break
                body += b + "\r\n"
            body = body + "\r\n" + make_month_summary_str(month_summary_dict, unit)
            # edit this issue body
            i.edit(body=body)
        name = f"[{name}]({url})"
        total_data_str = str(total_data) + unit
        my_num_stat_str += make_stat_str(name, total_data_str, streak, today_check)

    replace_readme_comments("README.md", my_num_stat_str, "my_number")

多说几句早起

关于早起这个数据和 issue 因为自己喜欢诗歌,我找了一个获取一句诗的 API, 然后自动评论,评论是带时间戳的,正好记录自己的起床时间。 那么是怎么触发的呢? 我试用的是 iOS 系统,而 iOS 有个重要的功能是“捷径”,利用捷径可以触发 Actions workflow 的 api, 触发 api 就有时间戳了,再判断是不是早起,给自己发送就好了。 捷径的触发条件是闹钟关闭,为了保险起见,我可能比闹钟起的早,再加一条关闭背单词软件,解决了用 GitHub 记录早起的问题。 关于如何利用捷径配合 Actions 我写过一篇文章 -- 巧妙利用 iOS 的快捷指令配合 GitHub Actions 实现自动化 image 而早起这句诗,我期待好久的 -- 苟利国家生死以,岂因福祸避趋之。还没随机到,随到这一天我决定跑 19.26 km.

GitHubPost 区

利用了我写的 GitHubPoster 项目,自动生成 svg 引入,而自动跑的脚本也在那个项目上。 image

GitHub Repos 区

利用我写的 github-readme-stats 自动替换生成。 image image

娱乐区

全部利用 Issues 评论 -> 触发 Actions -> 自动替换 README 的注释区域生成 image

def replace_readme_comments(file_name, comment_str, comments_name):
    with open(file_name, "r+") as f:
        text = f.read()
        # regrex sub from github readme comments
        text = re.sub(
            GITHUB_README_COMMENTS.format(name=comments_name),
            r"\1{}\n\3".format(comment_str),
            text,
            flags=re.DOTALL,
        )
        f.seek(0)
        f.write(text)
        f.truncate()

做饭区

和上面类似,因为做的太多,我生成了个表格 image

def parse_cook_issue_table(me, issues):
    comments_str = MY_FOOD_STAT_HEAD
    food_dict = defaultdict(lambda: ["", "", 0])
    for issue in issues:
        comments = issue.get_comments()
        for c in comments:
            if not isMe(c, me):
                continue
            date_str = format_time(c.created_at)
            food_list_str = c.body.splitlines()[0]
            food_list = food_list_str.split(" ")
            for food in food_list:
                if food not in food_dict:
                    food_dict[food][0] = f"[{date_str}]({c.html_url})"
                    food_dict[food][1] = f"[{date_str}]({c.html_url})"
                else:
                    food_dict[food][1] = f"[{date_str}]({c.html_url})"
                food_dict[food][2] += 1
    for k, v in food_dict.items():
        comments_str += MY_FOOD_STAT_TEMPLATE.format(
            name=k, first_date=v[0], last_date=v[1], times=v[2]
        )
    return comments_str

月度数据

每次自动生成还会 edit issue 的内容生成月度数据整合 image

guoqiao commented 2 years ago

这个idea真是不错