饭否定时提醒工具
是什么
使用GAE写了一款饭否提醒工具,@timers其作用是在规定的时间给饭否以提醒。当然,内容可以自定义,比如几点几分去偷人家的菜,等等,方便一直泡在饭否上的饭友使用全新的方式来提醒自己。当然了,如果饭否支持将@消息和私信发到手机上的话,这款应用会更有用。
怎么用
- 加@timers为好友。
- 向@timers发送格式如"@timers dp 10 任意提醒"消息。消息可以分4段:回复段,模式段,时间段,内容段。段之间以1个或多个半角空格隔开。
- 回复段:@timers 固定。之所以要加@timers为好友,是为了让@timers能收到您的消息。(如果您没有加@timers为好友,其实也可以点击@timers的任意一条消息点“回复”,@timers也能收到你的消息的。
- 模式段:即提醒方式,d为直接回复(direct reply)给您;p为私信回复(private)给您;可用模式为d或p或dp。
2009.6.19更新:新增消息确认功能,@timers 收到消息后会及时回复一条“收到,我将于xxxx-xx-xx xx:xx提醒您。谢谢使用!”此功能默认开启。如果不需要此功能,只需要在模式段加入q即可。q为quiet之意。现在可用的模式有:dpq,其中dp选一或二,q可选可不选。
- 时间段:即何时提醒您。它支持如下方式的时间格式:
- 正整数时间格式: @timers dp 20 告诉我做某事。#此处的20可以是任意的正整数。
- 指定当天的几点几分:@timers dp 23:40 告诉我做某事。#程序会在当天的23:40向您发送提醒。(如果发送消息的当前时间是18:00,而发给@timers的提醒时间为11:00,则它收到消息后,1分钟内会提醒您。因为时间已经过了。这是一个特例。)
- 指定当月某日的几点几分:@timers dp 20 23:40 告诉我做某事。#程序会在当月20日的23:40向您发送提醒。
- 指定某月某日的几点几分:@timers dp 12-20 23:40 告诉我做某事。#程序会在12月20日的23:40向您发送提醒。
- 指定具体的某年某月某日的几点几分:@timers dp 2010-12-20 23:40 告诉我做某事。#程序会在2010年12月20日的23:40向您发送提醒。
- 需要说明的是,dp、数字、空格、中划线、冒号,全部都是半角字符。否则程序无法识别时间、提醒格式。
- 消息段。这段即是提醒正文部分。没有特殊要求,只要不超过饭否规定的字数即可。
怎样,不算太复杂吧?
为什么
这里说一下该程序的实现思路。与上一篇《GAE牛刀小试:从twitter到9911同步消息》类似,此程序同样使用GAE,使用cron。
- 程序每分钟执行一次。
- 每次执行,先查询尚未提醒的任务。
- 对于每一条未执行的任务,如果提醒时间小于或等于当前时间,则执行提醒(@或私信),同时将消息的状态设置为已经执行;如果大于,则略过。
- 查询数据库中最新消息的ID。
- 以此ID为参数,通过API读取@timers新收到的所有消息,保存在数据库中。
帮助我
如果您有任何建议、意见,请告诉我,我会修改程序,争取让它更好用。
源代码
公布源代码是个好习惯。比起自己的硬盘来,我相信网络空间更持久。虽然they say nothing lasts forever。 点击下面右侧的向下的▲查看源码。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#latest edit: 2009.06.19
#to ensure the utf8 encoding environment
import sys
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
reload(sys)
sys.setdefaultencoding(default_encoding)
import urllib
import base64
import re
import time #time zone convertion
from google.appengine.api import urlfetch
from google.appengine.ext import db
def time_from_0_to_8(timestr,timezone=8):
TIMEFORMAT="%a %b %d %X +0000 %Y"
#Sat Jan 03 23:08:54 +0000 2009
ISOTIMEFORMAT='%Y-%m-%d %X'
x=time.strptime(timestr, TIMEFORMAT)
m=time.mktime(x)+60*60*timezone
p=time.strftime(ISOTIMEFORMAT,time.localtime(m))
return p
def timestr_add_mins(timestr,mins=0,future=""):
'''
receive time str, format like: 2009-06-10 13:00:33
and integer mins
return seconds;
'''
ISOTIMEFORMAT='%Y-%m-%d %X'
x=time.strptime(timestr, ISOTIMEFORMAT)
m=time.mktime(x)+60*mins
p=time.strftime(ISOTIMEFORMAT,time.localtime(m))
return p
def add_time(p_time="",send_time=""):
ISOTIMEFORMAT='%Y-%m-%d %X'
now=time.localtime()
#print now.tm_year
p=""
match = re.search(
r"""(?:(?P\d{4})-(?=\d+))?
(?:(?:(?P\d{1,2})-)?(?P\d{1,2})\s+)?
(?P\d{1,2}):(?P\d{1,2}) |
(?P\d+)
""", p_time, re.VERBOSE)
if match:
min3 = match.group("min3")
if min3:
x=time.strptime(send_time, ISOTIMEFORMAT)
x=time.mktime(x)+int(min3)*60
x=time.strftime(ISOTIMEFORMAT,time.localtime(x))
return x
year = match.group("year")
if year==None:
year=now.tm_year
month = match.group("month")
date = match.group("date")
if month==None :
month=now.tm_mon
if date==None:
date=now.tm_mday
hour=match.group("hour")
mins=match.group("mins")
return """%s-%02d-%02d %02d:%02d:00"""%(year,int(month),int(date),int(hour),int(mins))
class Msgs(db.Model):
msg_id = db.StringProperty()
time = time = db.StringProperty() #the excution time; format: 2009-01-31 23:59
send_time = db.StringProperty()
d = db.BooleanProperty(default=False)
p = db.BooleanProperty(default=False)
q = db.BooleanProperty(default=False)
task= db.TextProperty()
user_id = db.StringProperty()
user_name = db.StringProperty()
done = db.BooleanProperty(default=False)
def print_all(self):
print "ID:%s in %s mins was %s, DPD:%d%d%d, by %s(%s). Task:%s" % \
(self.msg_id,self.time,self.send_time,self.d,self.p,\
self.done,self.user_name,self.user_id,self.task)
def reply_msg(user,sn,msg,reply_id=""):
auth=base64.b64encode(user+":"+sn)
auth='Basic '+auth
form_fields = {
"status": msg,
"in_reply_to_status_id":reply_id
}
form_data = urllib.urlencode(form_fields)
result = urlfetch.fetch(url="""http://api.fanfou.com/statuses/update.xml""",\
payload=form_data,
headers={'Authorization':auth},
method=urlfetch.POST
)
if result.status_code != 200:
print "Send Msg:%s Error!"%msg
def private_msg(user,sn,msg,to_id):
auth=base64.b64encode(user+":"+sn)
auth='Basic '+auth
form_fields = {
"text": msg,
"user":to_id
}
form_data = urllib.urlencode(form_fields)
result = urlfetch.fetch(url="""http://api.fanfou.com/direct_messages/new.xml""",\
payload=form_data,
headers={'Authorization':auth},
method=urlfetch.POST
)
if result.status_code != 200:
print "Send Private Msg:%s Error!"%msg
#get one page of to user's replies
def getPage(user,sn,since="",page=1):
auth=base64.b64encode(user+":"+sn)
auth='Basic '+auth
result = urlfetch.fetch(url="http://api.fanfou.com/statuses/replies.xml?since_id=%s&page=%d" % (since,int(page)),headers={'Authorization':auth})
if result.status_code == 200:
return result.content
else:
return False
#parse replies
#this is a private function used only by parse.
def parseMsg(msg,send_time):
#the msg is formated as: "@... d[pq] \d+ \w+"
#return tuple (d,p,q,time,content), the first 3 are boolean type; time :integer;content:task
match = re.search(r"@\S+\s+(?P\w+)\s+(?P



支持下老大,这创意太棒了!
目前见过的第一个GAE应用,感觉很神奇,顺便忽然对python产生兴趣。
python代码写出来是最整齐的。
python的语法(数据结构)有意思。
google支持python。
呵呵。