时光

时光的时光轴

寄以时间,予以文字
telegram
github
微信公众号

让课程表通过日历更新

81696c97-741c-466d-8810-9276bdaa993b.JPG

你手中的课程表是不是也是这样?所有课程叠在一起,每次上课前要算周数、找教师、算时间。也许过一段时间你会记下来这一切,但很快一个学期过去了,你又要重新开始这一切。

我在入学之前也了解过这个问题,大抵搜了几款网上推荐的,应用商店排名高的 “课程表” App,说实话,它们更像是大学生交友平台

有一个小爱课程表倒是挺符合我的感受的,而且接受个人开发者做适配,不过我尝试申请资格申请了两回也没消息,交流群里面也是三天两头的报 BUG,而且我在简单的体验过程中也发现了不少问题...


不过此时我将目光投向了自带的日历App,想起许久之前 Apple 自带日历还不支持中国节假日的时候(烦恼),曾在网络上有许多通过订阅日历的方法来解决这个问题。这种方法不仅能够通过服务端分发日程,并且还能够定期更新,最重要是的创建出来的日程完全跟普通创建的日程提醒功能一样,这让我对怎么实现的非常好奇。

协议#

首先我需要搞清楚别人是怎么实现的。

在访问订阅链接时,会下载下来一个.ics文件,咕噜咕噜一番,了解到这个属于iCalendar协议,这个i开头的单词让我一下想到了苹果,仔细一看果然有不少关系。然后分发协议是一个名为WebCal的标准,订阅日程便是基于以上两项技术实现的。

你可以在iCalendar找到格式的相关信息。

iCalendar 格式#

我根据自身水平,最大努力将格式的关键部分表述出来,但仍然可能存在错误,烦请指正。

我使用 Apple 日历导出来一份.ics文件,以便我理解它的格式:

BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:飞行计划
X-APPLE-CALENDAR-COLOR:#63DA38
BEGIN:VEVENT
DESCRIPTION:起飞降落时间为航班计划时间,仅供参考。
DTEND;TZID=Asia/Shanghai:20200901T170000
DTSTART;TZID=Asia/Shanghai:20200901T150500
SUMMARY:乘坐HO1072 长沙黄花-上海浦东 当地时间15:05-17:00[航旅纵横]
URL;VALUE=URI:umetrip://OPENAPP
END:VEVENT
END:VCALENDAR

其中有部分节点,比如动态时区我去掉了,经过测试这并不影响实际出来的日程,并且作为面向东八区的教程,让我看着很头大。

该文件由 “BEGIN” 和 “END” 两个头包括在一起,详细的文件格式你可以去其官网上找到更多资料。

  • X-WR-CALNAME 定义该日历的名称
  • X-APPLE-CALENDAR-COLOR 这个是 Apple 日历定义图标颜色的

然后是 “BEGIN” 和 “END” 段,这将定义一次事件

  • CREATED 创建日期
  • DESCRIPTION 备注 / 描述
  • SUMMARY 标题
  • DTEND;TZID 结束日期,其指定了时区
  • DTSTART;TZID 开始日期,其指定了时区
  • URL;VALUE 事件的 url 地址,可以点开

你可以使用 Outlook 网页版快捷测试自己的日历。
所以我照葫芦画瓢,写了一个:

BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:课程表
X-APPLE-CALENDAR-COLOR:#63DA38
BEGIN:VEVENT
DESCRIPTION:教师:曹华山\n学分:5.0
DTSTART;TZID=Asia/Shanghai:20201003T160000
DTEND;TZID=Asia/Shanghai:20201003T193000
LOCATION:教学楼C404
SUMMARY:网页设计综合实训
URL;VALUE=URI:hello
END:VEVENT
END:VCALENDAR

将其保存到文本文件,并使用 ics 后缀名,即可尝试导入到 Outlook,你便可以看到添加后的效果。

a355fdfd-e4f8-49fa-a8d9-a544cb91c5c7.png

在调试过程中发现,各家的日历都有一些专有参数,比如 Apple 日历:X-APPLE-CALENDAR-COLOR便可以定义日程的显示颜色。

在后面的研究中应该多试试几款日历 App,研究研究有哪些专有参数,让课程表更具特色一些。那么接下来就是转换课程数据了~

数据转换#

首先应当让你学校教务系统提供的课程表变成结构化数据,因为不同学校不一样,这里就用我学校的教务网站做例子。

不过我们学校就很离谱,查询课程表返回的是一张图片...

cf63f138-6f9f-4d78-bf48-246853433bc1.png

这是怕有人偷走你的课程表吗...

不过好在天无绝人之路,如果按课程教室来查询课程表,返回的是可处理的文字(不知道为什么要这么设计)

那么我便从这里试着入手:

按课程查询#

简单看一下查询课程的逻辑,便可以得到课程列表。不过教务系统查询的时候竟然有验证码:

fbfd0c90-ada2-4fc1-82b8-155f5a413dc6.png

但是,这个验证码实在是不复杂,便用简单的 OCR 解决掉了。经过一番折腾,整理出来了这样的数据:

	array(2) {
  [0]=>
  array(6) {
    ["name"]=>
    string(25) "130601|客户关系管理"
    ["teacher"]=>
    string(6) "韩梅"
    ["type"]=>
    string(19) "专业课/必修课"
    ["week"]=>
    string(4) "1-18"
    ["day"]=>
    string(11) "二[1-2节]"
    ["location"]=>
    string(13) "教学楼A401"
  }
  [1]=>
  array(6) {
    ["name"]=>
    string(28) "130625|商务谈判与礼仪"
    ["teacher"]=>
    string(9) "王晓霞"
    ["type"]=>
    string(19) "专业课/必修课"
    ["week"]=>
    string(4) "1-18"
    ["day"]=>
    string(11) "三[3-4节]"
    ["location"]=>
    string(13) "教学楼C502"
  }
}

然后根据教务系统返回的校历,作息时间,对整个课程数据进行处理,接下来就是生成ics文件了。

生成 ICS 文件#

按照目标格式拼凑数据,差不多就是之前这段:

BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:课程表
X-APPLE-CALENDAR-COLOR:#63DA38
BEGIN:VEVENT
DESCRIPTION:教师:曹华山\n学分:5.0
DTSTART;TZID=Asia/Shanghai:20201003T160000
DTEND;TZID=Asia/Shanghai:20201003T193000
LOCATION:教学楼C404
SUMMARY:网页设计综合实训
URL;VALUE=URI:hello
END:VEVENT
END:VCALENDAR

然后将文件导入到 outlook,便可以看到效果:

进行订阅#

要实现WebCal协议其实很简单,本质上还是属于 http 请求,只需要在返回头加上:

Content-type: text/calendar; charset=utf-8
Content-Disposition: attachment; filename="table.ics"

便可正常在日历 App 中订阅。

但是参考 iCalendar 的规范,每个事件还得有一个 “UID” 字段,这样便于客户端识别事件以更新。这个 UID 虽然有规范,但实际上你只需要做到和其他事件的 UID 不相同即可,这里我简单的用单个课程的名字,日期和节数进行 md5 计算。

最后的效果#

在手机上:
87eba7a3-1abf-4b77-a65f-87320789c9e4.png
在 outlook 上:
c4b7f146-b0b4-4f31-b325-8dec435fc9aa.png
顺便一提,Windows10 及以上的系统是能够通过 outlook 实现订阅到系统日历,也支持锁屏提醒!

变得易用#

这样基本的流程便完成了,不过最终服务人群还是同学,所以要将服务打造的简单易用!

现在是将更新任务(每周从教务系统拉数据)部署在云函数上,直接生成静态文件。前端随便找个地方放了就能提供服务了。

数据上的话策略是仅从教务系统拉取前两周,本周,未来四周的数据,这样每次更新都会有更好的性能表现。

目前也已经将服务部署在了站点上:订阅课程表
目前测试过了,所有有日历 App 的 Apple 设备,Windows10 及 Windows11,以及小米、华为、Vivo 设备均可直接导入。

目前其他安卓设备可以使用ICSX5这款软件,可以覆盖绝大多数安卓设备。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。