如何优雅地记录已阅书籍和电影

背景需求

2014 年,那时候我还在读大三,某一天突然萌发了一个想法,要将自己看过的书和电影记录下来。我隐隐约约感受到,沉淀自己的精神生活,竟然让我觉得人生充满意义。记录的瞬间让我觉得会有成就感;等哪天,拿起这份清单,我可以清楚回顾某段时间内看过了哪些书籍和电影,也从侧面知晓当时精神生活的丰富程度

方案演进

那么如何记录我的电影/书籍清单呢?这个方法还是经历了挺多版本迭代的

方案1:豆瓣

在中国,如果有跟我一样沉淀精神生活想法的人,可能大多数会使用豆瓣。他们看完书或电影之后,到豆瓣点一下已看,顺便评分,写上观后感

豆瓣是文青的精神角落,但是对我来说,它不是一个好方案,因为它:

  • 不够纯粹:对于我的需求,豆瓣整个页面的元素太过复杂,入口太深
  • 不够简洁:看完一部电影,先打开浏览器进入豆瓣(或者豆瓣 App),可能需要登录,搜索电影,点击已阅,评分,写点影评,这个流程对于懒人来说是多么可怕
  • 不够优雅:把自己的数据给别人,终归心里不自在,哪天想拿这些数据做统计或者迁移都是个问题

方案2:Markdown

与其寄人篱下,不如自立门户。最简单的方法,用一个 txt 纯文本来记录就行了吗?同时作为程序员我们得更有追求,使用 markdown 格式可以更好更方便地排版

点这里可以看下界面效果,对我来说简洁大方即可,因此后续方案的改进也只是改进了记录方法

但是只有一个文本是不够的,因为没有同步到网上,多设备共享就成了问题

方案3:Markdown + GitHub + Jekyll

Jekyll 是我接触的第一个静态网页生成框架,它与 GitHub Page 的配合使用,使一个博客的搭建变得异常轻松。于是,搭建一个 Jekyll 博客,清单作为博客文章,让 GitHub 托管就成了一个不错的方案。这样就解决了多设备共享的问题

方案4:Markdown + GitHub + Hexo

Jekyll 博客只有我这篇清单,而我真正的个人博客是在博客园。2016 年年初,我开始搭建个人博客,废弃了 Jekyll,使用了更为优雅简洁的 Hexo

电影/书籍清单也顺带迁移到这里

至此,阅读完一本书,或者看完一部电影,只要在我的电脑上,更新 .md 文件,使用 Hexo 生成好静态网页文件,然后上传到 GitHub

方案5:Markdown + GitHub + Hexo + Travis CI

2017 年年末,认识了 Travis CI,于是使用 Travis CI 来简化 Hexo

引入了 Travis CI,更新清单就省略了一个使用 Hexo 生成静态网页的步骤

终极方案:Markdown + GitHub + Hexo + Travis CI + 公众号 + 腾讯云

以上看似完美的方案,其实实践下来还是挺麻烦的。每次电影院看完电影,还要等回家之后打开电脑,更新博客,这个流程还是不够懒惰。于是我想到了公众号,毕竟移动互联网浪潮下,真正几乎不离身的不是电脑,而是手机

一个可行的想法是:使用公众号连接自己的服务器,然后利用服务器更新清单文件,上传到 GitHub,剩下的交给 Travis CI 去更新博客。这个想法大概在我脑里徘徊了一年,今日终于克服拖延症得以实现

最终的效果就是,阅读完一本书,或者看完一部电影,只要打开我的公众号,回复如下格式的命令,一会之后我的博客就自动更新完毕啦

add/del name [m/b/s]

其中 add/del 表示增加或删除,必填;name 必填,表示名字;类型选填,m/b/s 表示电影/书籍/连续剧,默认是电影

技术实现

我是专职 iOS 开发,对后台开发的知识处在青铜级别,所以这里记录下服务器端关键代码的实现。如何打通公众号和自己的服务器,以及如何配置服务器在这里就不赘述

这个项目使用的语言是 php + python,主要涉及以下几个文件:

  • index.php:负责与公众号接口对接,对用户发送的消息进行验证解析,并提取电影/书籍名称,以及类型,传递给 blogUpdater.php 处理,并返回博客链接给用户
  • blogUpdater.php:负责调用 isee.py,传递名称、类型、年月日等
  • ReadList.txt : 轻量级数据库,维护所有阅读数据,数据示例如下,其中 m 表示 movie,b 表示 book
2018 04 23 m 起跑线
2018 02 01 m 唐人街探案2
2018 02 01 b 活着本来单纯
2018 01 01 m 神秘巨星
2018 01 01 m 无问西东
2018 01 01 m 奇门遁甲
2017 12 01 m 解忧杂货店
2017 12 01 b 少有人走的路
2017 11 01 m 缝纫机乐队
  • isee.py : 关键文件,主要负责更新 ReadList.txt,并输出 markdown 文件,最后执行 git 操作。其主要逻辑如下
1. 按行读取文件 ReadList.txt,每一行的数据包括名字、类型、年月日以及链接,如果是 del 命令则比对名称和类型,如果匹配说明该数据是要删除的,不添加到 list,否则默认添加到 list
2. 如果是 add 命令则将新数据添加到 list
3. 对 list 的内容进行去重
4. 将 list 的内容输出到 tmpReadList.txt,输出结束之后删除 ReadList.txt,重命名其为新的 ReadList.txt
5. 将 list 的内容输出到 markdown 文件,为了优化可读性,将最近的记录放在前面,排序算法如下:年倒序,月正序(即201801、201802...201701、201702...)
6. 最后执行 git 操作,上传 markdown 文件

踩坑记录

以下部分是开发过程中踩到的坑,记录一下以备忘

公众号接口调试

可以使用微信公众号的在线接口调试工具来测试服务器接口是否正常

php 调用 Shell 接口以执行 Python

关键代码:

1
2
$cmd = "python3 /var/www/html/Norcy.github.io/isee.py ".$objectName." ".$type." ".$year." ".$mouth." ".$date." >/dev/null  &";
shell_exec($cmd);

注意以下几个点:

  1. 使用 shell_exec 来调用 shell 命令
  2. & 的作用是 python 脚本会在后台执行
  3. 如果是调试模式,可以使用 2>&1var_dump 来查看输出

    1
    2
    $cmd = "python3 /var/www/html/Norcy.github.io/isee.py ".$objectName." ".$type." ".$year." ".$mouth." ".$date." 2>&1 &";
    var_dump(shell_exec($cmd));
  4. >/dev/null2>&1 是什么呢?

/dev/null :代表空设备文件
>  :代表重定向到哪里
0 : 表示 stdin 标准输入
1 : 表示 stdout 标准输出,系统默认值是1,所以">/dev/null"等同于"1>/dev/null"
2 : 表示 stderr 标准错误
& : 表示等同于的意思,2>&1,表示2的输出重定向等同于1
1 > /dev/null 2>&1 : 标准输出输出到空文件,标准错误也输出到空文件
cmd >a 2>a 和 cmd >a 2>&1 为什么不同?
cmd >a 2>a :stdout 和 stderr 都直接送往文件 a,a文件会被打开两遍,由此导致 stdout 和 stderr 互相覆盖
cmd >a 2>&1 :stdout 直接送往文件 a,stderr 是继承了 FD1 的管道之后,再被送往文件 a。a 文件只被打开一遍,就是 FD1 将其打开

公众号超时逻辑

直接访问 php 执行代码的时候没有任何问题,但是通过公众号访问,返回的数据却是空的,没任何提示。找了许久,最终原因是 php 的处理时间太长,公众号接口超时

其实主要的耗时操作是 isee.py 的执行,因此只需要在执行 python 的时候,命令后面添加 &,让其后台执行,就可以解决超时逻辑

Python 调用 Shell 以执行 Git

由于 blogUpdater.php 和 isee.py 所在的目录不一样,因此这里是一个大坑,执行 Shell 的时候需要先将当前目录切换到 isee.py 所在的目录

1
2
3
4
5
os.chdir(sys.path[0]);
os.system("/usr/bin/git pull origin HexoBackup");
os.system("/usr/bin/git add .");
os.system("/usr/bin/git commit -m 'Update From PublicAccount'");
os.system("/usr/bin/git push origin HexoBackup");

代码中文乱码问题

  • python 文件页首添加 #coding=utf-8
  • php 文件页首添加
1
2
3
$locale='en_US.UTF-8';  
setlocale(LC_ALL,$locale);
putenv('LC_ALL='.$locale);

终端中文乱码问题

直接修改当前用户目录下的 .bashrc 文件,在最后添加如下:

1
2
3
4
export LC_ALL=C
export LANG="zh_CN.utf8"
export LC_ALL="zh_CN.utf8"
export LC_CTYPE="zh_CN.utf8"

用户读写权限问题和文件所有者权限问题

Apache 运行时用户是 www-data,而不是我 ssh 登录时的 ubuntu 用户,因此会遇到一个又一个的文件权限问题。我的方法是 ssh 登录之后,切到 www-data 用户来执行所有操作,并更改相关的文件权限和所属群组

相关命令有 sudo -isu - www-datachmod -R 777 ./chown -R www-data:www-data ./whoami

使用 ssh 而不是 https 的方式来配置 GitHub

  1. 使用 git remote -v or cat .git/config 来查看当前的 git 配置
  2. 编辑 .git/config 文件 或者执行 git remote set-url origin git@github.com:username/username.github.io.git 来更改配置
  3. 其他的按照官方文档即可

未来改进

  1. json 代替 txt,通用性更高
  2. 抓取豆瓣链接,将每行数据变成一个超链接,方便随时跳转到豆瓣
  3. 抓取豆瓣海报,可以做成海报墙的形式
  4. 对数据进行统计,画出各种统计图

至此,虽然是简简单单的功能,但是,it makes my world better.

一杯冰可乐