惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
GbyAI
GbyAI
S
SegmentFault 最新的问题
量子位
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
MyScale Blog
MyScale Blog
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
aimingoo的专栏
aimingoo的专栏
V
Visual Studio Blog
U
Unit 42
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Cloudflare Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
J
Java Code Geeks
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
IT之家
IT之家
Martin Fowler
Martin Fowler
宝玉的分享
宝玉的分享
雷峰网
雷峰网

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派
用GitHub Action,制作一款推理日历 - 少数派
2024-03-26 · via 少数派

前言

豆瓣刚出小组件的时候,我用过一段时间豆瓣电影日历,当时的体验还不错。后来在慕尼黑Hugendubel书店,有一个区域是专门卖各种日历的,有风景画,哈利·波特主题,和二次元等等。我是为了看推理小说才去的那家书店,所以萌生了做一款推理主题日历的想法。

我想先从最简单的功能开始,因为是在手机上观看,日历卡片设计成了竖屏,日历的条目包括推理主题的书籍和电影,最上面是一张作品的海报,下方是作品名称,类型等信息。

我先用Canvas设计了一个海报,然后每天手动更新图片和信息。结果第二天我就出了差错,只更新了日期,但没更新星期几。虽然Canvas的设计我觉得还挺好看的,但手动更新时间毕竟不是长久之计,我开始考虑用Python生成海报。

手动设计的海报,结果忘记更新星期几了

开发过程

因为最初的想法只是根据手动输入的网址生成一张海报,然后用脚本自动标记上时间,防止时间出现错误,所以我先用Pillow这个Python包写了一下海报生成的代码。我主要是设计了一下海报和文字的位置和颜色,其中颜色是根据条目的主题而变化的,每天都不一样。豆瓣评分的图标用的是GitHub上常见的设计。

我随便选了一个可以商用的字体,叫作「站酷文艺体」。可有一次我发现《和騎士度過的那一夜》这本推理短篇集的名字无法正确显示,才意识到字体需要包含简体和繁体,所以更换成了「霞鹜文楷」。

我试用了一下,因为不满足于手动输入图片网址的繁琐,又找了一下网上的豆瓣爬虫,自动抓取豆瓣条目的图片。不过由于豆瓣条目的网址还是需要手动输入,整个流程很费时间。我想到了使用一个json文件来存储这些网址,脚本只需要在json文件里读取最新输入的条目。等以后积累的条目多了,就可以随机选取一条来当作背景图片。

每天输入一条的话,不知道要等到猴年马月才能积累足够的条目。偶然间发现了一个GitHub Action,可以从豆瓣上爬取用户标记过的作品。一次性把全部条目下载下来,每个条目包含了名称,类型,上映/出版日期等信息,十分方便。

	{
		"comment": "《巧克力公寓谋杀案》",
		"rating": {
			"count": 1,
			"max": 5,
			"star_count": 4,
			"value": 4
		},
		"sharing_text": "我的评分:★★★★ 《巧克力公寓谋杀案》 https://book.douban.com/subject/36480672/ 来自@豆瓣App",
		"sharing_url": "https://www.douban.com/doubanapp/dispatch?uri=/subject/36480672/interest/4036595172",
		"tags": [],
		"charts": [],
		"platforms": [],
		"vote_count": 1,
		"create_time": "2024-03-15 20:05:51",
		"status": "done",
		"id": 4036595172,
		"is_private": false,
		"subject": {
			"rating": {
				"count": 2253,
				"max": 10,
				"star_count": 3.5,
				"value": 6.8
			},
			"controversy_reason": "",
			"pubdate": [
				"2024-1"
			],
			"pic": {
				"large": "https://img2.doubanio.com/view/subject/l/public/s34735111.jpg",
				"normal": "https://qnmob3.doubanio.com/view/subject/m/public/s34735111.jpg?imageView2/2/q/80/w/200/h/300/format/jpg/sharpen/1"
			},
			"honor_infos": [],
			"other_versions_count": 0,
			"is_show": false,
			"vendor_icons": [
				"https://img1.doubanio.com/f/frodo/161387ce451872cbf51fcb288cd5ffd1dcd89705/pics/vendors/logo_dedao@2x.png",
				"https://img1.doubanio.com/f/frodo/f6f620132e6d8a02d171f03114bbe2339aa8af97/pics/vendors/logo_doubanread@2x.png"
			],
			"card_subtitle": "紫金陈 / 2024 / 湖南文艺出版社",
			"book_subtitle": "",
			"id": "36480672",
			"author": [
				"紫金陈"
			],
			"is_released": true,
			"vendor_original_price": "",
			"color_scheme": {
				"is_dark": true,
				"primary_color_light": "a55634",
				"_base_color": [
					0.05000000000000001,
					0.6837606837606838,
					0.9176470588235294
				],
				"secondary_color": "f9f6f4",
				"_avg_color": [
					0.045662100456621,
					0.6666666666666666,
					0.8588235294117647
				],
				"primary_color_dark": "7f4228"
			},
			"type": "book",
			"cover_url": "https://dou.img.lithub.cc/book/36480672.jpg",
			"min_sale_price": null,
			"press": [
				"湖南文艺出版社"
			],
			"pages": [
				"424"
			],
			"sharing_url": "https://book.douban.com/subject/36480672/",
			"url": "https://book.douban.com/subject/36480672/",
			"title": "长夜难明 : 双星",
			"uri": "douban://douban.com/book/36480672",
			"subtype": "book",
			"intro": "闹市街头,女子坠楼身亡,腹部有刀伤。\n两天后,一段赵泽宇手持带血匕首逃离案发现场的视频,被人在网上公开。赵泽宇是江北市原市长赵忠悯的独生子,江北知名企业家,案件顿时引发全社会关注。赵泽宇被警方刑拘,可他坚称自己没有杀人,是被人陷害的,事发后他因害怕仓促逃离现场。死者实为跳楼自杀。\n警方当然不信这番狡辩,可通过一系列的技术手段还原案发经过,结果证实死者竟真的是自杀。\n现在警方面临的问题更加棘手了。从证据角度讲,死者是自杀的,赵泽宇无罪,警方应该放人;可视频在前,全网皆知,加上赵泽宇的家庭背景,如果警方对外通报死者是自杀的,谁会相信?人民群众会质疑警方徇私枉法。\n事到如今,各方都希望赵泽宇“有罪”,最好还是重罪,这样才能平息这场风波。",
			"buy_more_uri": "",
			"null_rating_reason": "",
			"article_intros": [
				{
					"useful_count": 1,
					"uri": "douban://douban.com/review/15811580",
					"comment_count": 1,
					"intro": "没有多么长夜难明,不如改名《巧克力公寓谋杀案》",
					"total": 1,
					"type": "review"
				}
			],
			"vendor_sale_price": "",
			"has_ebook": true
		}
	},

因为是「推理日历」,我在脚本中加了筛选条件,随机选取数据库中的条目,直到选到悬疑或者推理类的作品为止。然而并不是所有的条目都有类型标注,所以我筛选的方式是判断简介里面是否出现了「悬疑」,「推理」,「侦探」等关键词。

我能想到的发布方式有好几种。最简单省事儿的办法就是发布在社媒上,比如豆瓣相册,小红书,公众号之类的地方。头两天的海报我也确实是这么做的。之前用过Flask,可以在pythonanywhere上发布,优点是站点访问速度较快,但每三个月就要点一下更新,不然站点会过期。

更正式的发布方式,是做成类似「ONE·一个」那样的APP,但我没搞过移动端的开发,对网上看到其他人用的flutter之类的不熟。而且不付费注册的话,只能把APP发布在Test Flight里,不能上架应用商店。其实除了APP,ios还可以使用小组件发布一些轻量级的应用,我看到了两款日语单词学习组件,调用了词典网站或者APP的API,可以随机展示日语单词和翻译,用的就是Scriptable。

我决定使用的办法,就是用GitHub Pages发布日历并且设置成每天自动更新,然后移动端使用小组件来展示网页。日历的网址是https://code-cp.github.io/mystery-calendar/,小组件叫作Web Widget。这款小组件可以根据输入的网址显示网页快照。

不过我适用了一段时间后,发现Web Widget有时候无法更新网页。我发现了另一款相似的小组件Glimpse 2,网页的更新更加及时,试用了几天感觉很不错。

上文提到了GitHub Action,我用它来运行代码库中生成日历的脚本。在代码库中新建一个.github/workflows文件夹,然后创建yml格式的配置文件。GitHub会根据配置文件里设定的运行时间(cron: '0 1 * * *')来执行里面的步骤,比如可以每隔一个小时,每天某个时间运行等等。具体如何设置时间,可以参考这个网站

不过GitHub Action并不能完全按照yml文件里的时间来执行,这取决于GitHub的runner的承载能力。我看网上的讨论说,最好把分钟数(也就是第一位的0)改成非0的值,因为大多数的Action都是在0分的时候执行。

name: run-main

on:
  workflow_dispatch:
  schedule:
    - cron: '0 1 * * *' 

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

      - name: checkout repo content
        uses: actions/checkout@v2 # checkout the repository content to github runner

      - name: setup python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10' # install the python version needed
          
      - name: install python packages
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          
      - name: execute py script # run main.py
        run: |
            cd src/ 
            python main.py
          
      - name: commit files
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git add -A
          git diff-index --quiet HEAD || (git commit -a -m "updated logs" --allow-empty)
          
      - name: push changes
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: main 

但在调试的时候没时间等待它自动运行,往往需要手动执行workflow,可以在配置文件里加上workflow_dispatch:,就可以在Github网站上点击Run workflow来运行了。

这个脚本先执行checkout repo content,因为我要运行的是Python脚本,还要加上setup python,这些都是GitHub提供的。接下来会安装代码库的requirements.txt里的包,然后运行脚本。main.py会生成一个新的日历,保存在images文件夹内,所以需要commit files和push changes,把图片保存在代码库中,GitHub Pages就会在deploy的时候使用新的图片。

GitHub Actions自动运行并且commit, push到了代码库

结语

制作日历之前,我以为这只是一个很简单的工程,没想到有这么多细节需要处理,比如怎么处理不同格式的时间和字体。除了豆瓣评分,我还想要加上IMDb和烂番茄的评分,但暂时没时间去研究那些网站的API了。

手机上显示日历的效果展示

目前这个日历仅仅是一个demo,以后有机会,还是想把它做成「ONE·一个」那样的风格。其实我不仅仅想做一个日历,我还没找到任何一款专门做推理内容的APP,所以更想做一款包含推理资讯,论坛等内容丰富的推理APP。