手把手教你做个生成静态网页的小工具:podgen

程序人生之图穷匕见的podcast发了四期(三期正式的)后,有几个读者说在微信上听效果不好,又没法暂停(停下后再听又从头开始了),能不能在iTunes 播客里面听?程序君觉得这还真是个事,于是便考虑在iTunes里注册,一尝试才发现,iTunes不能帮你host你的episodes,它只是个聚合器,有点像已经死掉的google reader,你提交一个rss,iTunes审核后,就收录你的podcast了。所以,首先我得设置个站点放我的这些episodes。

在查阅了不少现有的static site generator(SSG)后,我发现他们生成的rss都不符合iTunes的格式,而且这些工具主要还是面向博客用户,如果要支持语音播放的话还得修改他们的template,加入一个前端的播放器。所以,使用已有的SSG这条路,我就没走下去。

如果不用SSG,一个可行的方案是使用万能的wordpress。不过wordpress对于我这样一个小需求实在是太重了,整个LAMP栈需要装不说,还得自己搭一台服务器上去,不值当。

想来想去,我觉得还是自己写一个类似于jykell的命令行工具,走SSG的路子。部署嘛,有免费的github pages,对我而言,足够好了。名字嘛,俗一点,就叫podgen(podcast generator)好了。接下来,我谈谈做这么个小工具,需要怎么考虑和如何实现。

产品定义

当开始构想podgen时,有几个需求是我重点考虑的:

  • 尽可能地简单,稍稍有一丁点git使用的经验就能使用
  • 尽可能与模板decouple,这样第三方比较容易提供新的模板
  • 尽可能方便不同平台的安装
  • build的速度要快

第三条和第四条促使我先后放弃了python和clojure。安装python的工具在osx和linux下问题不算特别大,但在windows下很可能是个梦魇;而clojure虽然可以打成一个uberjar,但作为一个命令行工具,每次运行启动jvm那一瞬间的迟滞,还是让人很不爽的,所以最终我选择了不那么精通的golang。

产品的功能则按照一切SSG工具的惯例,切分成几个部分:

  • init:初始化项目文件,一般是将模板文件拷贝到项目里,然后生成一些初始化的配置
  • build:把模版文件编译成html,然后拷贝到build目录下
  • server:在本地运行一个http服务器,方便查看修改
  • push:把所有的修改commit后,push到github上。此时,对gh-pages分支下的文件,github会进行hosting。

我们先看用户使用的整个过程,首先他创建一个空的github repo并clone到本地。接下来就可以直接init了:

如果用户什么都不改就运行 podgen build,应该也能工作 —— 打开build之后产生的index.html,有一个最直观的印象:

这个初始的版本可以立即部署到线上:

而访问线上的 username.github.com/projectname 看到的就是这个样子(这里访问的是 tyrchen.github.com/podgen-test):

这个流程对用户来说是足够简单和可验证的。现在新产品实在太多了,如果五分钟用户搞不清楚一个产品怎么用的话,那么,用户就基本丧失试用下去的兴趣了。

OK,现在一切操作都很顺畅,所见即所得,用户希望能修改添加真实的数据进去,通过运行podgen,用户知道要修改的文件在channel.yml和items.yml里。这里,使用yaml而非json格式,也是考虑到yaml相对而言更好编辑一些。

修改编辑拷贝,最终生成这样的效果:

嗯,这就是podgen产品的一个完整的使用过程。生成好的site满意了之后,可以提交到iTunes里等待审核,通过后,别人就可以在「播客」里搜索到了。

产品实现

这样一个小产品,基本功能都是围绕着易用性走的,所以没什么酷炫的地方。

首先是模板和代码分离,这是个很小的点,但非常重要。jekyll在这一点上做得不好,如果你发现了它模板的问题,还得pull request到整个repo去,麻烦。分离还能把决定权交给用户,由用户选择使用什么样的模板来构建。

所以,podgen是两个repo组成的:

  • github.com/tyrchen/podgen:核心代码
  • github.com/tyrchen/podgen-basic:基础模板

现在基于bootstrap的免费模板很多,我选择了startboostrap-landing-page这个模板(repo里有来源)。稍作修改即可。基于bootstrap的模板的好处是desktop和mobile展现起来都不错。

mp3播放器是前端主要的障碍,选一个license合理又使用简单,得花一些心思。比较之下我选择了soundmanager2,基于BSD。

前端搞定之后,这个项目就基本完成60%。

后端首要的难点是选择一个好的CLI library。如果是其他语言,我都有非常熟悉的CLI library,但go我还是第一次认认真真写复杂的CLI(简单参数,没有子命令的不算)。go自带的flag不够强大,所以得找第三方的库。首先我注意到的是consul。由于consul是用golang写的,其命令行又简洁强大,所以我就先从他身上上偷师。可惜hashicorp(consul背后的公司)没有把其强大的命令行工具抽象出来,我只好把consul的command模块抄过来,然后裁剪了一下。不难,很快就把CLI弄好了。

后来在做其他东西的过程中,偶尔发现了 spf13/cobra 这个库。spf13是github上的一个大牛,我曾经vim的配置就是抄他的。这哥们写的cobra库和consul的command模块有异曲同工之妙(也许天下代码一大抄?),我就把自己修改的从consul抄来的CLI全部废掉,换用了cobra,很简单,很好用。

golang毕竟年轻,旁门左道的库少一些。要做一个能让iTunes接受的podcast,必须要有符合其xml规范的rss,而这种偏门的东西,在golang很难找到成熟的。权衡再三,我使用了没有人用过的 andjosh/gopod,抱着不好用就自己写的态度,发现这货还可以。

解析yaml和处理template不是什么事,golang自己的库就能搞定。但静态语言在这里的缺陷就被无限放大了:作为一个产品,我希望不需要改动代码可以随意在yaml文件里增加新的域,同时在template里通过模板语言使用这些新的域。这在python/clojure里不用修改代码就能秒杀的需求,在golang里面根本找不到优雅的解决方案:毕竟,一个yaml解构需要一个golang的struct去解析,可惜这是固定死的,改yaml结构意味着该代码重新编译;如果不这样做,使用类型断言的话,代码又会奇丑无比。

golang的template也挺弱(也许是我的道行的问题),一个paginator,处理当前页高亮,如果当前页是第一页不允许上翻,如果当前页是最后一页不允许下翻等等这样大众的UI需求在golang的template里丑陋地让人吐血,也许写几个helper放在FuncMap里会好一些,但最后我受不了就干脆写了个函数生成这个Html片段。

最后一个不算难点的难点是调用系统命令。比如调用git的各种功能,以及系统的cpmv等帮助用户简化整个使用的流程。如果直接走shell命令,代码很简单,跨平台很难。如果使用libgit及封装好的系统库,跨平台不难,但代码要额外花时间写。考虑这个project我想在今天就能发布一个可用的版本,就走了前面一条路,使用了 github.com/codeskyblue/go-sh 这个库。

开发就说这么多,核心代码不到500行,很容易读。

授权

最后谈谈授权,做一个开源软件,最好指定好软件的授权,方便其他人使用。一般而言,你对衍生的代码的归属以及是否开源不在意的话,可以使用MIT,BSD,Apache。

podgen这个工具花了我一天半的功夫完成了80%的功能,现在已经可用。本着eat your own dogfood的态度,我的podcast使用它生成并已经上线,感兴趣的话可以访问:podcast.tchen.me;如果要订阅的话,osx下的iTunes里已经可以试用,打开File菜单,选择"Subscribe to Podcast",然后输入rss的地址:podcast.tchen.me/rss.xml 即可。如果要在手机上订阅,还需等一等,apple还在审核。

如果你也想做自己的podcast网站,不妨试试这个工具(github.com/tyrchen/podgen),osx下可以直接下载使用,以后会增加 brew install podgen 的安装方式。

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2015-08-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏花叔的专栏

解读一下动态消息,顺便补充一下新的跳转规则

它是一个重磅的功能,意思是:在小程序或者小游戏里,可给聊天框发出一个小程序卡片链接,该链接具备可自主设置的提醒功能,开发者可在未来24小时内对该链接上的部分信息...

1462
来自专栏云计算与大数据

Envoy——Service Mesh体系中的私人订制,把你安排得明明白白!

最近因工作原因开始了解Service Mesh与Envoy,为系统性梳理所学内容,因此沉淀了此文档,但由于所知有限,如文档中有描述不当之处,希望不吝赐教。

2412
来自专栏花叔的专栏

解读小程序互跳功能,首对互相跳转的小程序发布!

花叔漏夜把新功能更新到接口人和Nodes小程序里了。现已发布,说不定这是最早上线的小程序互跳功能案例,请叫我快男花。 先说说昨晚发生了什么: 话说,昨晚11点做...

41712
来自专栏SAP最佳业务实践

SAP最佳业务实践:ETO–项目装配(240)-24期末结算

为进行获利分析结算生产订单及项目 在此活动中,为物料S240-1和项目执行工厂的期末财务会计核算。 成本和收入只是暂时地收集在订单和项目中,在期末处理的时候这些...

4058
来自专栏云计算D1net

云数据备份并不是云灾难恢复

云数据备份不是云灾难恢复。不幸的是,供应商的虚假陈述正在推动企业应该如何使用云备份的误解。许多组织正在考虑云备份,因为它消除了基于磁带的备份技术,自动备份,删除...

3886
来自专栏何俊林

仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)

本文是由奇虎360公司高磊关于使用百度地图仿摩拜单车APP,原文地址:http://blog.csdn.net/gaolei1201/article/detai...

3059
来自专栏FreeBuf

浅谈拒绝服务攻击的原理与防御(4):新型DDOS攻击 – Websocket和临时透镜

0×01 前言 前几天我已经分别发了三篇关于DDOS攻击相关的文章,我也是第一次在freebuf上发表这种文章,没想到有那么多人点击我真的很开心,前几天我为大家...

2225
来自专栏java一日一条

电商网站秒杀与抢购的系统架构

在过去的工作中,我曾经面对过5w每秒的高并发秒杀功能,在这个过程中,整个Web系统遇到了很多的问题和挑战。如果Web系统不做针对性的优化,会轻而易举地陷入到异常...

1872
来自专栏个人分享

一次极限项目管理,设计,开发,联调与测试

     什么是All In? 是你不知道全力做这件事情会得到什么。但你只想把它做好的感觉。

1211
来自专栏Debian社区

Greg Kroah-Hartman批评Ubuntu发行版

Ubuntu根本就是个祸害开源社区发行版。资本家是“无利不起早”的。“新人用Ubuntu系列是最不明智的选择,因为很难利用到别人的经验。Ubuntu修改了太多东...

1695

扫码关注云+社区

领取腾讯云代金券