关于这个网站
毫无疑问,这是一个blog。
在Google app engine发布之后,我第一个想法就是学习Python——当时的GAE只支持Python,然后在上面写出一个自己的blog程序。在阅读他人的blog的时候,如果发现作者使用的是自己写的程序,就会景仰一下,慢慢地生出了“写一个自己的blog程序”的想法。现成的blog平台,譬如WordPress,movabletype并非不好,相反,他们是如此的强大,强大到我觉得无福消受。我试图从学习php开始,然而可耻地失败了,失败在想法中的开始从未开始。GAE发布之后,我感觉这是一个机会,让我学习一种编程语言的机会。于是,下载了教程,在一台配置落伍的TCL笔记本上安装了Python环境。
和我预料的一样,在看完《Python简明教程》之后,我对学习本身很快丧失了兴趣。于是动手编程。这种摸着石头过河的方法未必错误,可是如果你连石头的位置都摸不到,那肯定是走错了方向。“重复造轮子的行为时愚蠢的”,这是我的理由,所以我下载了其他人编写的blog程序,然后按照自己的想法修改,于是就有了现在这个blog程序。
和所有的blog程序一样,这个程序的功能包括但不限于:
- 发布文章和页面
- 评论。文章评论可关闭
- tag和按月(年)存档
- RSS和sitemap输出
- 写作API
除此之外的功能有:
- post有4种类型,分别为文章、页面、评论和短消息(微博),你没有看错,这个blog程序中,评论和文章的地位是相等的
- 文章和页面可以另外设置一个链接
- 文章和页面可以相互转换
- 每条评论有属于自己的URL;在任何一个页面上都可以评论,甚至包括评论本身
- 支持HTML,纯文本,Markdown,Textile等4种格式写作
- WordPress格式的导入和导出
- 集成了一些应用,譬如
豆瓣、flickr、Google统计等
这是一个完全按照自己的想法拼凑的blog程序,加入的都是我认为有用或者有趣的零件,未必适合他人。我仍然把它放在了网上供人围观。
Hello world!
门户网站与微博
作为微博客的始祖,twitter从一开始公司内部的通讯工具到设想中“地球的脉搏”,一直呈现上升的趋势,并且在可见的未来,上升的方向和速度都不会改变。在twitter开辟了一块疆土之后,世界各地的网民蜂拥而至,这自然引起了其他网站的注意,他们争先恐后地推出自己的微博客服务,试图在twitter完全垄断这个市场之前,圈起自己的一亩三分地。相对而言,国外的网站更有理性和创造性。Yahoo!的meme成为了分享精彩图片和语言的集散地,Google新近推出的buzz则在社会化联系上做出了深层次的尝试。转过来看看国内各大门户网站的微博客服务,试用之后,只能说乏善可陈。在twitter等网站被防火墙挡在国门之外的时期,对于国内门户网站来说,不啻一次极好的机会。用户已然经过twitter的教导,它们要做的不过是收割而已。只是它们收割的姿势是如此的拙劣。
首先反应过来的是新浪。尽管某新浪内部人士声称“很多人会认为新浪微博是模仿Twitter而生,但事实上,在2009年5月我第一次和CEO曹国伟谈起设想已久的“一句话博客”之前,我从未上过Twitter,或者任何与之形态相近的网站”。但是这样苍白的声明毫无意义,人们不会因为新浪微博模仿twitter而去指责它,事实上,这是中国互联网的传统。新浪在运营微博的时候,毫无保留地继承了新浪博客的特色,即名人效应。新浪博客依靠明星的光环照耀,一度也确实非常耀眼。正是这样经受过验证的成功,让他们理所当然地认为,复制这种运营模式更加稳妥。于是,新浪微博成为了小字辈的新浪博客。新浪完全没有意识到,twitter的成功不是依靠明星,或者说后来的验证账户,而是实实在在的草根,那种你在街头会擦肩而过的人。也许,它也意识到了,只是相信在中国,光环效应的影响力更加强大。
随后上线的搜狐微博和网易微博同样没有任何值得称道之处。再宽容的用户,也不会将网易微博字数限制扩大到163个这样的细节称之为“创新”。搜狐将微博内置在博客中,试图公用博客好友联系人,这样一来,却彻底地让微博沦为了博客的附属品。相对于搜狐微博,自家的chinaren校园微博反而更像是一款独立的产品。在门户网站中比较有锐气的网易,则反新浪之道而行之,在页面上醒目地写道:“我们没有名人认证”。这不是贵族学校和平民学校的区别,只是招生的手段不同而已。
好戏还在后头。腾讯作为中国互联网最成功的企业,依靠着庞大的用户基数,在市场竞争中杀伤力极强。模仿然后超越,这就是腾讯的一贯战略。让对手感到可怕的是,你找不到遏制它的办法,除非你“上面有人”。腾讯之前的滔滔几乎是试水的产品,同时培养用户习惯。即使这样,滔滔在数据上显示仍然非常成功。腾讯随后将中心放在了另一款重点产品邮箱上,在邮箱中植入了微博。可以想象,腾讯的目标是将邮箱、微博、空间等产品融和在一起,筑起一道牢固的篱笆,而微博在其中起着连接的作用。
把你的appspot转向自定义域名
GAE支持绑定自己的域名,所以很多用户都在使用自定义域名。和blogger.com不同,GAE绑定域名之后,原来的yourname.appspot.com并不会自动转向自定义域名。需要做301转向的话,可以使用以下的代码:
def redirect_from_appspot(wsgi_app): def redirect_if_needed(env, start_response): if env["HTTP_HOST"].startswith('my_app_name.appspot.com'): import webob, urlparse request = webob.Request(env) scheme, netloc, path, query, fragment = urlparse.urlsplit(request.url) url = urlparse.urlunsplit([scheme, 'www.my_domain.com', path, query, fragment]) start_response('301 Moved Permanently', [('Location', url)]) return ["301 Moved Peramanently","Click Here %s" % url] else: return wsgi_app(env, start_response) return redirect_if_needed
然后定义一下application:
from google.appengine.ext import webapp from google.appengine.ext.webapp import util ... def main(): application = webapp.WSGIApplication(ROUTES, debug = True) application = redirect_from_appspot(application) util.run_wsgi_app(application)
需要注意的是,如果启用了XMPP服务,在转向之后,XMPP不能正常工作。
我的独立微博客
在GAE上搭建了一个独立的微博客,所谓独立,就是没有和访问者的交流,纯粹记录型的。在编写初期,也考虑过增加互动性,想到现在交流的途径是如此之多,这里没有也无所谓,这才作罢。以前一直有这个程序存在,由于不支持IM显得很不方便,很久都没有使用。在Google增加了XMPP之后,搭建一个机器人变得容易,又兴起了这个念头。这个微博客目前的功能有:
- 支持页面、IM、email、移动等方式发布
- 支持导入twitter导出的XML文件
- 和 twitter 的双向同步
- 消息字数不再局限于140个字,当超过140字时,同步到twitter的消息将截断并增加指向原消息的链接
关于开源。有些朋友对这个程序感兴趣,询问过是否开源,感谢你们的关心。不过,暂时没有开源的打算。第一,因为自己觉得代码写得非常糟糕,只是能勉强运行而已。将如此质量的代码开源,恐怕会贻笑大方。其实,这个微博客并没有过多的技术含量,随便找一套运行在GAE上的开源博客程序略作修改就可以达到目的。第二,这个微博客完全模仿了 twitter 的样式,甚至可以说是剽窃,将不完全属于自己的程序开源也是不合适的。
两分钟搭建自己的twitter机器人
在Google App Engine支持XMPP之后,搭建一个属于自己的twitter发布机器人已经变得非常容易,在此之前,这项工作显得很复杂,即使有imified这样专业的机器人服务的存在。简单介绍一下如何搭建,实现最简单的发布功能。
在app.yaml中启用xmpp消息服务:
inbound_services: - xmpp_message
这行代码是加在handlers内容区块之外的。
具体的代码:
from google.appengine.api import xmpp from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app TWITTER_USERNAME = "your twitter name" TWITTER_PASSWORD = "your twitter password" YOUR_EMAIL = "your email" class XMPPHandler(webapp.RequestHandler): def post(self): message = xmpp.Message(self.request.POST) if message.sender.split('/')[0] == YOUR_EMAIL: authStr = TWITTER_USERNAME +':'+ TWITTER_PASSWORD msg = message.body msg = msg.encode('utf8') url='http://twitter.com/statuses/update.json' form_fields={'source':'','status':msg} form_data=urllib.urlencode(form_fields) result=urlfetch.fetch(url=url, payload=form_data, method=urlfetch.POST, headers={"Content-type": "application/x-www-form-urlencoded", "Accept": "text/xml", "Authorization": "Basic "+authStr.encode("base64")[0:-1]}) if result.status_code == 200: message.reply(u"发布成功.") else: message.reply(u"发布失败,请重试!") application = webapp.WSGIApplication([('/_ah/xmpp/message/chat/', XMPPHandler)], debug=True) def main(): run_wsgi_app(application) if __name__ == "__main__": main()
上传就可以用YOUR_EMAIL定义的email地址加[email protected]为好友,然后就可以给它发送twitter了。
QQ域名邮箱
QQ推出了域名邮箱,瞄准的是企业用户。长久以来,尽管QQ邮箱是腾讯公司在品质上难得一见的好产品,但由于QQ本身的定位更偏向于年轻和娱乐化,导致许多企业级的用户在选择其邮箱产品时采取了更谨慎的态度。QQ域名邮箱的推出,正是对这样难堪的现状试图扭转局面的尝试。Google Apps和Windows Live 管理中心已经逐步成熟和占领了很大市场,这对于一向靠模仿然后超越的腾讯来说,现在是已经可以发动的时机。前行者在披荆斩棘中闯出了一条路,并且告诉人们这条路上可以挖掘出黄金,腾讯怎能坐视不理?
同时,腾讯已经发扬了其一切和QQ绑定的原则,所谓的域名邮箱,仍然和用户的QQ邮箱绑定,占用的是原有的空间。换句话说,如果没有QQ号码,仍然无法使用域名邮箱。从QQ邮箱只能创建10个用户的策略来看,这又是一款等级制的产品。应该注意的是,开通域名邮箱需要填写管理员的姓名、联系电话,有经验的用户知道这意味着什么。
test metaweblog api
Does the metaweblog api work? If it works, I will update this post later.
update:It works!
Pubsubhubbub的故事
一般讲故事都是这样开始的:从前有一个……:
从前有一个叫做Sub的人,他天天跑到Pub家去要钱,有一种说法是去讨回被欠的工资。总之,他不管Pub有钱没钱,三天两头地去跑,想想也是,Pub什么时候有钱也不知道,万一哪天有钱了,不就要到了么?
Sub去得太频繁了,Pub终于不胜其烦了,他想出了一个办法。Pub花很少的钱雇佣了一个叫做Hub的人给他看守大门,并且告诉Hub:以后谁来要钱都让他处理。毕竟是给人打工,Hub无可奈何地硬着头皮答应了。
这一天,Sub一如既往地去Pub家,到了以后,他惊讶地发现,Pub家门口贴着一张声明,声称以后所有的财务问题由看大门的Hub先生全权处理。
不管怎样,这个Hub看起来比Pub容易打交道一点。Hub看到Sub以后,问他:你是来要钱的吗?Sub说是。于是Hub说:以后你就别天天跑来了。Pub先生说了,有钱的时候他会让我去通知你一声的。
就这样,Sub回去了。
果然,后来Pub有了钱的时候,会让Hub上门来通知Sub去他家里拿钱。Sub很高兴,天天上门跑不但辛苦,而且不受人待见,现在只在家等着就行了。当然,Pub也很高兴,没有了Sub上门烦他,并且什么时候有钱还是自己说了算。他对Hub的工作很满意。
这个故事被两位Google的员工:Brett Slatkin 和 Brad Fitzpatrick 听说以后,他们从中受到了启发。并因此开发了一种叫做PubSubHubbub的协议。
为了让这个blog支持这种协议,我仿效了当年Pub的做法,雇佣了一个看大门的,不过我比他精明的地方在于:我雇佣的是一个免费的、开源门卫:PubSubHubbub Publisher 。
然后,我要做的,是在大门上贴一张声明,如果你家大门是RSS结构的话,这种声明看起来是这样子:
<?xml version="1.0"?> <rss xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/> ... </channel> </rss>
基于jQuery的文本编辑器markItUp!
markItUp!这个名字很有趣,和Yahoo!一样后面带了一个感叹号的尾巴。markItUp!是一款基于jQuery的轻量级文本编辑器,和一般的WYSIWYG(所见即所得)编辑器不同,呈现在文本框中的依然是代码,编辑器简化了插入代码的工作。
在试用过NicEdit之后,再次选择了markItUp!,因为markItUp!的扩展性更好,支持快捷键,动态预览,自定义皮肤,总体说来,比NicEdit更为成熟。
调用markItUp!编辑器:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="markitup/jquery.markitup.js"></script>
编辑器格式,如html,ubb,wiki等等:
<script type="text/javascript" src="markitup/sets/default/set.js"></script>
CSS文件,其中有皮肤的样式:
<link rel="stylesheet" type="text/css" href="markitup/skins/markitup/style.css" /> <link rel="stylesheet" type="text/css" href="markitup/sets/default/style.css" />
插件的安装:将插件的set.js文件内容放入sets编辑器格式下的set.js文件中,将插件的css文件内容放入sets编辑器格式下的style.css文件中。
其实,写这篇文章只是为了测试一下新安装的markItUp!使用效果如何。
时间问题
处在UTC时间差为0的程序员在开发程序时,往往不考虑时间问题,在修改程序时,不得不给它打补丁。
entry.published += datetime.timedelta(hours=UTC_OFFSET)