惟有于技术中才能明得真相

将文章发送到QQ空间的Firefox插件

突然想要将不明真相的人所写的不明真相文章保存到QQ空间中,当然也是给不明真相的人看的。由于我不愿意每次拷贝粘贴,多费事啊,所以才要写个Firefox插件。原本并不想写Firefox插件,觉得太复杂,得学不少东西,我首先考虑的是能否利用Vimperator或者GreaseMonkey来完成这样的功能,也曾考虑过Ubiquity,它们都是基于命令行,因为我可能还要对选中的内容做些修改,它们就并不合适。最后也只有硬着头皮去学写Firefox插件,还好,根据网上的例子,拼拼湊湊居然也写出来了,虽然功能很简单,界面也相当原始,最讨厌的是它单独占据了一个工具条,而这个工具条上只有一个Button,没办法,因为我看的例子专门讲的就是如何添加工具条的,也懒得去看其它的更好方式。

这里只讲一下实现原理,由于QQ空间并不提供公开API,但它可以通过发送邮件的方式来发布QQ日志,但邮件发送者和QQ空间的所有者必须是同一个用户名。我启动了很简单的用python写的Web Server,它的唯一目的就是POST请求,有两个参数,subject和content,并将它们通过邮件发送到QQ空间中去。在Firefox插件中就是通过XMLHttpRequest发送请求给这个本地Web Server,当然得填充subject和content参数,subject默认为浏览器中当前文档的标题,content就是选中的内容。

至于插件的代码,等找到一个好的网络硬盘再放上来。

Google Calendar农历提醒解决方案

Google Calendar作为一个提醒工具,它的一个缺点就是不支持农历的循环提醒,这对过农历生日的就很不方便了。现在网上的主要解决方案是使用工具生成一个包含每年生日信息的iCalendar文件,然后在Google Calendar中导入它就可以一次添加很多年的生日信息,这里是网上已经存在的一个解决方案,但它有缺点。首先一个问题,它只能用于Windows,这对大多数人并不是一个问题,但对我是个问题。第二个问题,它似乎没有考虑到农历和公历的不同,日期输入采用的是输入公历的控件,所以不能输入2/29,这对大多数人不是问题,但对我是个问题,我的生日刚好是农历二月二十九,当然我可以选择闰年作为开始日期和结束日期,但总归令人不爽。所以我就单独写个程序,程序中Python写的,使用命令行,这可能对大多数人是个问题,但对我不是一个问题。

使用方法:

$ ./lunar_reminder.py -h
Usage: python lunar_reminder.py -d[npm] [output-file]
以iCal格式输出按年重复农历提醒信息,不指定输出文件时输出到标准输出

 -h, --help             输出此帮助信息
 -d, --date=DATE        指定起始农历信息,可以使用如下格式:
                          1980/2/25,1980-2-25,1980.2.25
 -n, --number=N         指定重复的年数,默认只重复一年
 -p, --location=LOC     指定事件的地点
 -s, --summary=MESG     指定事件概要信息
 -D, --description=DESC 指定事件描述信息

# 从2009年开始生成以后50年生日信息,输出到mybirth.ical文件中
$ ./lunar_reminder.py -d 2009/2/29 -n 50 -s "我的生日(农历2/29)" mybirth.ical


源文件:lunar_reminder.py,它依赖于lunar.py

Python农历公历转换

出于某种目的需要在农历和公历之间转换,原本是打算直接用现成的,在网上找了一下,大都只能从公历转换成农历,也包含一些我不想要的功能,于是就打算自己写。我的目的很简单,给一个农历日期得出它的公历日期,以及给一个公历日期得出它的农历日期。我主要是参考了Python版的农历日历Calendar里的算法,它不能从农历转换成公历,并且不能处理闰月,另外我觉得这个算法实现得较啰嗦,原本应该可以实现得更简洁一些。它能够计算1901-2050年之间的农历日期,为了将它的计算范围扩大,我又参考了农历两百年算法(1901~2100)用C实现的算法,将里面的数据做了相应地转换。转换之后我发现两者的数据并不一致,Python版的每年月份天数的数据个别年份有误,而C版的1960年闰月数据有误。当然我只比较了1901-2050年的数据,对于2051-2099看的数据因为只有C版里才有所以无从比较,我测试了几组数据没有大的问题。

在我的实现中主要有两个方法,一个是get_lunar_date,它根据公历返回农历,返回是一个四元组(year,month,day,leap),leap为True表示返回的月份在闰月,为False时表示不是闰月。另外一个是get_solar_date,它根据农历返回公历,由于农历存在闰月,可能有一个农历日期对应着两个公历日期,这个方法返回一个数组,如果农历月份为闰月,这个数组会包含两个公历日期,否则只有一个公历日期。这个方法对日期校验并不十分严格,它允许任意月份的天数为30,严格说来某些月份只有29天,例如农历2009年10月只有29天,但get_solar_date也可以接收2009年10月30,即get_solar_date(2009,10,30),它相当于返回农历2009年11月1日的公历日期,如果严格检验地话应当不允许这一情况。对于闰月也是一样,严格地说农历2009年5月30号只对应着一个公历日期,尽管2009年的5月是闰月,但是闰5月没有30号,严格来讲get_solar_date(2009,5,30)应该只返回一个公历日期,但由于对天数的宽松解释,它仍然返回两个公历日期。这种处理在某些情况下可能是不合适的,但由于我的目的是用于生日提醒,如果一个人是农历30号的生日,但某些年份却没有30日,如果严格处理他可能收不到生日提醒,这里宽松处理天数可能反而比较好。

源代码贴在下面,另外由于前面提到的数据问题,我并不能保证它转换出来的結果一定是正确的,但据我的测试結果大致上是没有问题的,即使数据真有问题也只会影响到一小部分日期,误差也只会在一两天内。当然,另一个错误来源于程序BUG,这毋须多说。

源代码:lunar.py

加强Evernote的GreaseMonkey脚本

Evernote是一个非常强大的记笔记的软件,它的强大之处在于可以摘录任意的网页内容。比较遗憾的是,它仅在Windows和Mac下桌面客户端,在Linux下只能使用它的Web客户端,可是它的Web客户端对键盘操作太不友好,比如它的tabindex设计就太不合理,在编辑笔记时,按tab键根本就看不到焦点在哪里。简单地说,如果你使用键盘完全无法操作,即使你使用Vimperator也是如此。它的工具栏以及左侧的笔记本标签不是一个链接,所以按下f键是就不能定位到它们,自然也就无法操作了。忍了好久,终于决定要写个GreaseMonkey脚本改变Evernote,使它对键盘操作更友好。GreaseMonkey是什么呢?简单地说,它就是Firefox的一个插件,它可以动态地改变网页的内容,例如可以用它去掉网页中讨厌的广告。我用GreaseMonkey对Evernote做了如下改变:
  1. 去掉页头和页脚,同时使使中间的内容占据最大的面积。这看起来很简单,只需要将页头和页脚隐藏就可以了,但Evernote使用的是GWT,它使用的绝对高度,所以不仅要隐藏页头和页脚还要调整中间内容区域的高度。
  2. 给工具栏中Button和左侧笔记本标签添加链接,这样就可以用Vimperator定位到它们。
  3. 调整编辑笔记界面中各元素的tabindex,使得很容易用tab键盘导航到要编辑的区域。
脚本可以从这里安装。