前面通过Google Data API解决了光靠Email不能解决的标签和插图问题,自然,就想到应该可以插入LaTeX语法的数学公式吧,只是把这些公式转成图片插入就可以了。这中间只是多了一个自动编译并转为图片的过程,至少我之前是这么想的。
但在实际的操作中总有意想不到的问题,我第一次碰到了多线程或者多进程的问题。在之前写一些小东西的时候,是没有涉及过多线程或多进程的需求的,可在这里,去编译tex源文件的时候,它出现了。
最先我直接通过os.system把对tex源文件的编译写到某个函数中,可这样是无法执行的,我猜想应该是os.system还没有执行完,这个函数就返回了,而这个函数一返回,就把里面的os.system直接中断了。后来我用subprocess和threading来处理对tex源文件的编译,执行是没有问题了,但我无法在编译tex源文件处做阻塞,一阻塞就不能正常编译。不阻塞倒能正常编译,可我后继的操作必须在tex源文件编译完毕后才能进行,不能并发执行的。
最后这个问题我还是无解,我想可能与python是作为vim的脚本执行有关,这时python执行的这个进程与vim的进程的关系?所以我不得不把原本应该在函数内完成的事放到外部完成,虽然很dirty,但它能正常工作了。
import vim,os,markdown2,re,datetime reInLineMath = re.compile(r'\$.*?\$') reBlockMath = re.compile(r'\\\[.*?\\\]', re.S) def getFileName(): 'get a random filename like 20090423' d = datetime.date.today().strftime('%Y%m%d') return d def createTexFile(body, mathInLineList, mathBlockList): mathInLineList = '\n\\newpage\n'.join(mathInLineList) mathBlockList = '\n\\newpage\n'.join(mathBlockList) texcode = ''' \\documentclass{article}\n \\usepackage{tikz}\n \\usepackage{amsmath}\n \\pagestyle{empty}\n \\\begin{document} %s\n\\newpage\n%s\n \\end{document}''' % (mathInLineList, mathBlockList) file = open('/home/zys/temp/%s.tex' % getFileName(),'w') print >> file,texcode file.close() return file.name subject = vim.current.buffer[0] body = '\n'.join(vim.current.buffer[2:]) mathInLineList = reInLineMath.findall(body) mathBlockList = reBlockMath.findall(body) if mathInLineList.__len__() > 0 or mathBlockList.__len__() > 0: texFile = createTexFile(body, mathInLineList = mathInLineList, mathBlockList = mathBlockList) os.system('rxvt -e pdflatex --output-directory=/home/zys/temp/ %s' % texFile) os.system('rxvt -e convert -trim -density 120 -antialias %s.pdf %s. jpg' % (texFile.split('.')[0],texFile.split('.')[0])) mathList = mathInLineList + mathBlockList if mathList.__len__() == 1: body = body.replace(mathList[i], '' % (texFile.split('.')[0])) else: for i in range(mathList.__len__()): body = body.replace(mathList[i], '' % (texFile.split('.')[0], i))
主要的代码就这些,用正则表达式从正文中取出tex相关的数学公式,然后把这些公式做成一个单独的tex源文件,一页一个公式,编译后得到一个pdf文件,用convert去把这个pdf文件转成jpg图片,这里带一个-trim参数,得到没有边距的图。如果是多页会得到一组编号的jpg图,再回头用这些图的本机地址去替换正文中的tex数学公式。
另外,代码高亮是通过highlight来做的,在vim中选中代码块,执行highlight就可以得到内嵌css的html带pre标签的代码。
下面纯属演示数学公式效果- -
八卦传播问题
假设某地区的总人口为,在短期内不变,
表示知道消息的人数所占的百分比,初始时刻的百分比为
,传播率为
,另外有一部分人知道消息,但不传播,不传播率为
,则数学模型为:
求解得:
于是有:
此表明随时间的增长,消息慢慢地会淡化,逐步被人遗忘。
参考
在<我的博客解决方案>中,最后有一些待解决的问题,昨天看了下Google Date API,算是解决了(主要是插图和标签的问题)。
标签问题
标签使用Blogger Data API是比较好搞定的,本身就有一个AddLabel函数。import gdata.blogger.service import atom def postBlog(subject=None, body=None, labels=None, account=None, password=None): 'to post blog via GData Blogger API' print 'To Post ...' client = gdata.blogger.service.BloggerService() client.ssl = True post = gdata.blogger.BlogPostEntry() post.title = atom.Title(text = subject) post.content = atom.Content(content_type = 'html', text = body) #post.AddLabel('Computer') if labels[0]: map(post.AddLabel, labels) try: client.ClientLogin(account, password) except gdata.service.BadAuthentication: print account, password print "ERROR: Login failed!!. (Wrong username/password?)" return False try: BLOG_ID = client.Get('/feeds/default/blogs').entry[0]. GetSelfLink().href.split('/')[-1] except: print "ERROR: Can not get the BLOG_ID!!" return False try: client.AddPost(post, blog_id = BLOG_ID) except: print "ERROR: Can not add the blog!!" print "Is the format all right?" return False print "Blog `%s` post successfully." % subject2
注意,使用Blogger的API时,一定要使用安全链接(ssl = True),否则是接不上的。传说与GFW有关,昏!
插图问题
插图的问题是这样解决的:
- 通过正则表达式,从正文中获取所有插图的本地地址。
- 把这些图片通过Picasa Web Albums Data API上传到我的Picasa中指定的相册。
- 获取上传后,在Picasa中的这些图片的URL。
- 把正文中,所有图片的本地地址替换成Picasa中的URL。
-
import gdata.photos.service import gdata.media import gdata.geo def uploadImages(filelist, account, password): '''Upload all images. And thd filelist is the re.findall() in blog.''' print "Upload All Images ..." try: gd_client = gdata.photos.service.PhotosService() gd_client.email = account gd_client.password = password gd_client.source = 'zys-blogimage-1' gd_client.ProgrammaticLogin() except: print 'ERROR: Could not Login in Picasa!!' return False album = gd_client.GetUserFeed().entry[1] album_url = '/data/feed/api/user/%s/albumid/%s' % (account, album.gphoto_id.text) replaceList = [] for f in filelist: print "Uploading `%s` ..." % f[1] try: photo = gd_client.InsertPhotoSimple(album_url, getFileName(), f[0], f[1], content_type='image/j peg') except: print 'ERROR: upload %s failed!!' % f[1] return False replaceList.append((f[1], photo.GetMediaURL())) print "Completed. --> `%s`" % photo.GetMediaURL() print "All images have Uploaded." return replaceList
整理一下思绪,把当初的想法记录一下。
问题描述
建立一个博客发布平台,以便分享和记录自己的一些想法。
功能需求
- 在页面布局上基本兼容各种浏览器。
- 在页面主题上简洁、或可以让我完全自定义。
- RSS完全供稿。
- 自动投递,使我第一时间获取评论内容。
- 二级域名。
- 可以使用通用接口发布文章,Email或单独的API。
- 可以最大限度控制文章的格式,或直接支持使用HTML。
- 文章的保存有保证。
- 我可以用VIM写文章。
- 具备一定的分类管理功能。
- 访问速度不能太慢。
理想方案
打开VIM,写东西,发送。(自动发表、分类存档、备份源文件)
自己开发还是使用现成的?
自己开发的好处我可以完全控制所有的环节,随意添加我需要的功能,花点钱还能弄个顶级域名。但代价是,要花费比较多的时间,还要每年投入个几百元的主机费用。还有以后系统升级时可能非常折腾。而我现在又没很多的时间也没有钱,所以还是用一个现成的好。
用现成的我就选了Blogger。
实现方案
在VIM中如何发送?
一个比较通用方式是,在本机架设一个SMTP服务器,然后使用一个可以用VIM作编辑器的客户端,写好内容后本地投递。但这种方式太麻烦了,不但要一个独立的SMTP服务器,而且在写东西时你实际上还需要去打开一个客户端。
最简单的方式应该感谢gmail的开放API。因为gmail有开放的API,所以你使用这个API甚至可以把你的gmail账户当成是一个SMTP服务器。还有一个关键的因素就是,gmail有python的API,而VIM的脚本中是可以直接嵌入python的。剩下的事就比较简单了。
首先,从http://libgmail.sourceforge.net/下载libgmai。
在VIM中使用libgmail直接发送邮件到指定地址(参考: http://djcraven5.blogspot.com/2006/10/send-gmail-message-from-vim.html):
" Make sure the Vim was compiled with +python before loading the
script...
if !has("python")
finish
endif
:command! -nargs=? GMSend :call GMailSend("<args>")
function! GMailSend(args)
python << EOF
import vim
to = vim.eval('a:args')
GSend(to)
EOF
endfunction
python << EOF
########### BEGIN USER CONFIG ##########
account = 'xxxx@gmail.com'
password = 'xxxxx'
########### END USER CONFIG ###########
def GSend(to):
"""
Send the current buffer as a Gmail message to a given user.
"""
import libgmail
subject = vim.current.buffer[0]
attachments = vim.current.buffer[2].split(',')
if attachments[0] == 'None': attachments = None
body = '\n'.join(vim.current.buffer[4:])
ga = libgmail.GmailAccount(account, password)
try:
ga.login()
except libgmail.GmailLoginFailure:
print account, password
print "Login failed!!. (Wrong username/password?)"
gmsg = libgmail.GmailComposedMessage(to, subject, body, filenames
= attachments)
result = ga.sendMessage(gmsg)
if result:
print "Message sent `%s` successfully." % subject
else:
print "Could not send message."
EOF
格式如何控制?
Blogger中可以直接使用HTML,所以直接发送HTML格式的邮件就可以了。
但是,如果直接写HTML不是太折腾了吗?所以我想用一种wiki的语法来写,然后解析成HTML后发送出去。最先考虑的是用与MoinMoin一样的语法,不过MoinMoin中似乎并没有把它的语法parser分离出来,google了一下,也有人对此进行了相关的探索,但我没找到比较圆满的结果。于是我决定使用markdown,它比较简单,网上相关的扩展实现也不少,使用面还是很广的,重要的是它有python的实现,可以从这里下载(http://pypi.python.org/pypi/markdown2/)。
markdown2只有一个文件,使用非常简单:
>>> import markdown2
>>> markdown2.markdown('*syntax*')
u'<p><em>syntax</em></p>\n'
>>>
要在VIM中正常使用markdown2解析后的结果,需要对结果进行一次utf8的编码。
body = markdown2.markdown(body).encode('utf8')
然后对于解析后得到的HTML结果,可以先生成一个本机的临时文件,在本地浏览器中预览一下。
file = open('/home/zys/temp/' + subject + '.html','w')
print >> file,body
file.close()
cmd = 'firefox /home/zys/temp/%s.html' % subject
os.system(cmd)
备份源文件
每一篇文章的markdown2格式的源文件,都在发布文章的同时发送到我指定的邮箱当中保存。
file = open('/home/zys/temp/' + subject + '.markdown', 'w')
print >> file,source
file.close()
if not attachments: attachments = []
attachments.append('/home/zys/temp/' + subject + '.markdown')
gmsg2 = libgmail.GmailComposedMessage('xxxxx@gmail.com',
'[带着梦想走天涯]' + subject, body, filenames = attachments)
TODO
经过上面提到一番折腾后,已经可以比较顺手地使用了,但还有一些比较麻烦的问题还没有解决。
在文章中插图。这点的麻烦之处在于自动上传图片。如果在邮件当中添加图片附件,那么这些图片会被自动上传到picasa中,同时自动在文章的最前面插入这些图片,只是最前面,你不能把它插入到文章的其它部分中。如果在文章中间手动使用HTML标签插入图片,那么需要自己先将图片上传,获得URL后才能进一步操作。其实在gmail中已经可以自由插图,系统会自动上传,但在本机的VIM中,如何在邮件中自由插图我还无解T_T。这个在文章中间插图的需求还影响到其它一些功能的实现,如使用LaTeX的语法写一些公式或画一些图,本来可以自动转成图片插入到HTML页面中的。
为文章添加标签。很遗憾,通过邮件方式发布文章,我就是不知道怎么添加标签,google也无结果。
markdown2的hack。把markdown2改成尽量接近MoinMoin的语法,还要给它添加表格的相关语法,因为直接用HTML写一个表格还是比较烦的。
结束语
反正现在使用这个解决方案还是可以说比较顺手的。接下来会去看一下Blogger Data API,看能不能解决存在的问题。