早在一个月前插件就写好了,不过和往常一样假期沉迷日漫所以就一直拖到了开学前最后一天也就是今天。
明天又要返校了,呜呜呜~~~

0x00.前言

先来说说什么是 SDK,这是维基百科的解释。

软件开发工具包(Software Development Kit, SDK)一般是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、作业系统等创建应用软件的开发工具的集合。
它或许只是简单的为某个编程语言提供应用程序接口的一些文件,但也可能包括能与某种嵌入式系统通讯的复杂的硬件。一般的工具包括用于调试和其他用途的实用工具。SDK还经常包括示例代码、支持性的技术注解或者其他的为基本参考资料澄清疑点的支持文档。

里面谈到了应用程序接口,看到了这个应该很熟悉吧,其英文缩写就是API

0x01.开发

点此链接下载 SDK,并按照作者详细的README说明部署好本地环境。
然后我们就要在CQHandler.py里实现自己的事件处理逻辑了。
先定义一个时间与日期的函数,获取时间就靠它了:

1
from datetime import datetime
2
3
def get_nowtime(type):
4
    nowtime = datetime.now()
5
    if   type == 0:
6
        return nowtime
7
    elif type == 1:
8
        return str(nowtime.strftime("%Y年%m月%d日 %H时%M分%S秒"))   #nowtime_str
9
    elif type == 2:
10
        return str(nowtime.strftime("%Y-%m-%d"))                   #nowdate_str
11
    elif type == 3:
12
        return str(nowtime.strftime("%H:%M:%S"))                   #sign_str

class CQHandler(object)里的def OnEvent_GroupMsg(self, subType, sendTime, fromGroup, fromQQ, fromAnonymous, msg, font)我们开始实现签到处理逻辑。

1
if msg == '查询签到' or msg[1:8] == "CQ:sign":
2
try:
3
    DATE = get_nowtime(2)
4
    TIME = get_nowtime(3)
5
    #最先记录时间

我们要把用户签到的数据存到数据库里,我用的是SQlite,并且每个群有单独的数据库(其实一个数据库应该也可以)。这里分两种情况考虑,一种是还没有数据库的,我们得先创建表后直接插入新的日期列,另一种是有数据库的,要判断是否需要插入新的日期列。

1
if os.path.exists(str(fromGroup) + ".db"):
2
    conn = sqlite3.connect(str(fromGroup) + ".db")
3
    c = conn.cursor()
4
else:
5
    conn = sqlite3.connect(str(fromGroup) + ".db")
6
    c = conn.cursor()
7
    c.execute('''CREATE TABLE "sign_in"(
8
                ID INT PRIMARY KEY,
9
                QQ INT,
10
                RINK INT,
11
                TIMES INT,
12
                SERIES INT,
13
                LAST TEXT)''')
14
                c.execute("INSERT INTO sign_in VALUES (0, 0, 0, 0, 0, '00-00-00')")
15
#连接完数据库第一件事情:查看是否需要插入新的日期列;
16
c.execute("PRAGMA table_info (sign_in)")
17
a = c.fetchall()
18
#获取最后一列的信息,即日期
19
if str(a[-1][1]) == DATE:
20
    pass
21
else:
22
    c.execute("ALTER TABLE sign_in ADD COLUMN \"" + DATE + "\" TEXT")
23
    #插入新的日期列
24
    c.execute("UPDATE sign_in SET RINK = 0 ")
25
    #重置排名

这里又分两种情况考虑,一种是用户不在数据库里,我称之为“未注册”用户,直接INSERT

1
    c.execute("SELECT * FROM sign_in WHERE QQ = {0}".format(str(fromQQ)))
2
    b = (c.fetchone())
3
    if b == None:
4
        logging.info("未注册")
5
        c.execute("SELECT count(*) FROM sign_in")
6
        b = c.fetchone()
7
        id = int(b[0])
8
        #获取 ID 号,注意第二行就是 ID = 1
9
        c.execute("SELECT max(RINK) FROM sign_in")
10
        b = c.fetchone()
11
        rank = b[0] + 1
12
        c.execute("INSERT INTO sign_in (ID, QQ, RINK, TIMES, SERIES, \'" + DATE + "\', LAST) VALUES (?, ?, ?, ?, ?, ?, ?)", (id, str(fromQQ), rank, 1, 1, TIME, DATE))
13
        CQSDK.SendGroupMsg(fromGroup, "签到成功![CQ:at,qq={0}]\n\
14
签到时间:{1} {2}\n\
15
你是今天第 {3} 个在本群签到的人\n\
16
总计签到 1 次\n\
17
连续签到 1 次".format(str(fromQQ), DATE, TIME, str(rank)))
18
        conn.commit()
19
        conn.close()

另一种则是用户在数据库里,判断当天是否签到。(ps:那个“辅助方法”,同样的代码,在这里运行就是报错。无奈之下我换成了网络验证,把代码放在了Flask里,你们不要学我,2333……)

1
else:
2
    logging.info("已注册")
3
    #已注册查询当天是否签到
4
    c.execute("SELECT * FROM sign_in WHERE QQ = {0}".format(str(fromQQ)))
5
    b = c.fetchone()
6
    TIME_1 = b[-1]
7
    times = b[3]
8
    series = b[4]
9
    last = str(b[5])
10
    #读取签到时间
11
    #if len(TIME_1) != 0:
12
    if TIME_1 != None:
13
        logging.info("已签到")
14
        rank = b[2]
15
        CQSDK.SendGroupMsg(fromGroup, "你已签到![CQ:at,qq={0}]\n\
16
签到时间:{1} {2}\n\
17
你是今天第 {3} 个在本群签到的人\n\
18
总计签到 {4} 次\n\
19
连续签到 {5} 次".format(str(fromQQ), DATE, TIME_1, str(rank), str(times), str(series)))
20
    conn.commit()
21
    conn.close()
22
    else:
23
        logging.info("未签到")
24
        c.execute("SELECT max(RINK) FROM sign_in")
25
        b = c.fetchone()
26
        rank = b[0] + 1
27
        #获取 RINK 值
28
        times = times + 1
29
        #总次数增加一天
30
        url = "https://new.yuangezhizao.cn/series/" + last
31
        r = open_url(url)
32
        #辅助方法
33
        if r == "1":
34
            series = series + 1
35
        else:
36
            series = 1
37
        c.execute("UPDATE sign_in SET RINK = {0}, TIMES = {1}, SERIES = {2}, LAST = \'{3}\', \'".format(rank, times, series, DATE) + DATE + "\' = \'{0}\' where QQ = {1}".format(TIME, str(fromQQ)))
38
        CQSDK.SendGroupMsg(fromGroup, "签到成功![CQ:at,qq={0}]\n\
39
签到时间:{1} {2}\n\
40
你是今天第 {3} 个在本群签到的人\n\
41
总计签到 {4} 次\n\
42
连续签到 {5} 次".format(str(fromQQ), DATE, TIME, str(rank), str(times), str(series)))
43
        conn.commit()
44
        conn.close()

最后,

1
except Exception as e:
2
    logging.exception(e)

Flask部分:

1
@app.route('/series/<last>')
2
def series(last):
3
    DATE = get_nowtime(2)
4
    DATE_1 = datetime.strptime(DATE, "%Y-%m-%d")
5
    last_1 = datetime.strptime(last, "%Y-%m-%d")
6
    minus = DATE_1 - last_1
7
    #格式化后比较日期
8
    if str(minus) == "1 day, 0:00:00":
9
        return "1"
10
    else:
11
        return "0"

这样插件就写好了。
数据库Show CREATE Statement,其中RINK是“当日排名”,TIMES是“总次数”,SERIES是“连续签到次数”,LAST是“上一次签到日期”配合前者做判断。

1
CREATE TABLE "sign_in"(
2
                    ID INT PRIMARY KEY,
3
                    QQ INT,
4
                    RINK INT,
5
                    TIMES INT,
6
                    SERIES INT,
7
                    LAST TEXT);

0x02.总结

从源码可以看出没有什么实质性的难度,都是些基本操作,我们只要实现自己的事件处理逻辑即可,适合于定制功能。