Note-51408-1

Token ID: 1

ERC-721 1 Transfers

Metadata

{
  "type": "note",
  "title": "让课程表通过日历更新",
  "tags": [
    "post",
    "开发",
    "作品"
  ],
  "summary": "你手中的课程表是不是也是这样?所有课程叠在一起,每次上课前要算周数、找教师、算时间。也许过一段时间你会记下来这一切,但很快一个学期过去了,你又要重新开始这一切。 我在入学之前也了解过这个问题,大抵搜了几款网上推荐的,应用商店排名高的“课程表”App,说实话,它们更像是大学生交友…",
  "sources": [
    "xlog"
  ],
  "external_urls": [
    "https://outti.me/ics"
  ],
  "date_published": "2023-01-28T05:51:00.000Z",
  "content": "\n![81696c97-741c-466d-8810-9276bdaa993b.JPG](ipfs://bafybeifdtxwbcms6ptfmq6judny3ikkxemqseukq6rjdlpi35qediqrz64)\n\n你手中的课程表是不是也是这样?所有课程叠在一起,每次上课前要算周数、找教师、算时间。也许过一段时间你会记下来这一切,但很快一个学期过去了,你又要**重新开始**这一切。\n\n我在入学之前也了解过这个问题,大抵搜了几款网上推荐的,应用商店排名高的“课程表”App,说实话,它们更像是`大学生交友平台`。\n\n有一个`小爱课程表`倒是挺符合我的感受的,而且接受个人开发者做适配,不过我尝试申请资格申请了两回也没消息,交流群里面也是三天两头的报BUG,而且我在简单的体验过程中也发现了不少问题...\n\n---\n不过此时我将目光投向了自带的`日历`App,想起许久之前Apple自带日历还不支持中国节假日的时候(烦恼),曾在网络上有许多通过订阅日历的方法来解决这个问题。这种方法不仅能够通过服务端分发日程,并且还能够定期更新,最重要是的创建出来的日程完全跟普通创建的日程提醒功能一样,这让我对怎么实现的非常好奇。\n\n# 协议\n首先我需要搞清楚别人是怎么实现的。\n\n在访问订阅链接时,会下载下来一个`.ics`文件,咕噜咕噜一番,了解到这个属于`iCalendar`协议,这个`i`开头的单词让我一下想到了苹果,仔细一看果然有不少关系。然后分发协议是一个名为`WebCal`的标准,订阅日程便是基于以上两项技术实现的。\n\n你可以在[iCalendar](https://icalendar.org/ \"iCalendar\")找到格式的相关信息。\n\n# iCalendar格式\n> 我根据自身水平,最大努力将格式的关键部分表述出来,但仍然可能存在错误,烦请指正。\n\n我使用Apple日历导出来一份`.ics`文件,以便我理解它的格式:\n```\nBEGIN:VCALENDAR\nVERSION:2.0\nX-WR-CALNAME:飞行计划\nX-APPLE-CALENDAR-COLOR:#63DA38\nBEGIN:VEVENT\nDESCRIPTION:起飞降落时间为航班计划时间,仅供参考。\nDTEND;TZID=Asia/Shanghai:20200901T170000\nDTSTART;TZID=Asia/Shanghai:20200901T150500\nSUMMARY:乘坐HO1072 长沙黄花-上海浦东 当地时间15:05-17:00[航旅纵横]\nURL;VALUE=URI:umetrip://OPENAPP\nEND:VEVENT\nEND:VCALENDAR\n```\n其中有部分节点,比如`动态时区`我去掉了,经过测试这并不影响实际出来的日程,并且作为面向`东八区`的教程,让我看着很头大。\n\n该文件由 “BEGIN:VCALENDAR” 和 “END:VCALENDAR” 两个头包括在一起,详细的文件格式你可以去其官网上找到更多资料。\n\n- X-WR-CALNAME 定义该日历的名称\n- X-APPLE-CALENDAR-COLOR 这个是 Apple 日历定义图标颜色的\n\n然后是 “BEGIN:VEVENT” 和 “END:VEVENT” 段,这将定义一次事件\n\n- CREATED 创建日期\n- DESCRIPTION 备注 / 描述\n- SUMMARY 标题\n- DTEND;TZID 结束日期,其指定了时区\n- DTSTART;TZID 开始日期,其指定了时区\n- URL;VALUE 事件的 url 地址,可以点开\n\n你可以使用 Outlook 网页版快捷测试自己的日历。\n所以我照葫芦画瓢,写了一个:\n```\nBEGIN:VCALENDAR\nVERSION:2.0\nX-WR-CALNAME:课程表\nX-APPLE-CALENDAR-COLOR:#63DA38\nBEGIN:VEVENT\nDESCRIPTION:教师:曹华山\\n学分:5.0\nDTSTART;TZID=Asia/Shanghai:20201003T160000\nDTEND;TZID=Asia/Shanghai:20201003T193000\nLOCATION:教学楼C404\nSUMMARY:网页设计综合实训\nURL;VALUE=URI:hello\nEND:VEVENT\nEND:VCALENDAR\n```\n将其保存到文本文件,并使用 ics 后缀名,即可尝试导入到 Outlook,你便可以看到添加后的效果。\n\n![a355fdfd-e4f8-49fa-a8d9-a544cb91c5c7.png](ipfs://bafkreidw5t6qwrkzohuph6uulm7jwcrmtfx4mosmgg2nevnrn576xj7myq)\n\n在调试过程中发现,各家的日历都有一些`专有参数`,比如Apple日历:`X-APPLE-CALENDAR-COLOR`便可以定义日程的显示颜色。\n\n在后面的研究中应该多试试几款日历App,研究研究有哪些专有参数,让课程表更具特色一些。那么接下来就是转换课程数据了~\n\n# 数据转换\n首先应当让你学校教务系统提供的课程表变成结构化数据,因为不同学校不一样,这里就用我学校的教务网站做例子。\n\n不过我们学校就很离谱,查询课程表返回的是一张图片...\n\n\n![cf63f138-6f9f-4d78-bf48-246853433bc1.png](ipfs://bafkreicrw2igtuur7gkygcamthxymm2ok76fqnp4nayc5swr45r5txj744)\n\n这是怕有人偷走你的课程表吗...\n\n不过好在天无绝人之路,如果按`课程`或`教室`来查询课程表,返回的是可处理的文字(不知道为什么要这么设计)\n\n那么我便从这里试着入手:\n\n## 按课程查询\n\n简单看一下查询课程的逻辑,便可以得到课程列表。不过教务系统查询的时候竟然有验证码:\n\n![fbfd0c90-ada2-4fc1-82b8-155f5a413dc6.png](ipfs://bafkreiewyuzyx4ws3jdzdxf7gzamnwbshqachz7nf43zo773mpqagenzhi)\n\n但是,这个验证码实在是不复杂,便用简单的OCR解决掉了。经过一番折腾,整理出来了这样的数据:\n```json\n\tarray(2) {\n  [0]=>\n  array(6) {\n    [\"name\"]=>\n    string(25) \"130601|客户关系管理\"\n    [\"teacher\"]=>\n    string(6) \"韩梅\"\n    [\"type\"]=>\n    string(19) \"专业课/必修课\"\n    [\"week\"]=>\n    string(4) \"1-18\"\n    [\"day\"]=>\n    string(11) \"二[1-2节]\"\n    [\"location\"]=>\n    string(13) \"教学楼A401\"\n  }\n  [1]=>\n  array(6) {\n    [\"name\"]=>\n    string(28) \"130625|商务谈判与礼仪\"\n    [\"teacher\"]=>\n    string(9) \"王晓霞\"\n    [\"type\"]=>\n    string(19) \"专业课/必修课\"\n    [\"week\"]=>\n    string(4) \"1-18\"\n    [\"day\"]=>\n    string(11) \"三[3-4节]\"\n    [\"location\"]=>\n    string(13) \"教学楼C502\"\n  }\n}\n```\n然后根据教务系统返回的校历,作息时间,对整个课程数据进行处理,接下来就是生成`ics`文件了。\n\n## 生成ICS文件\n按照目标格式拼凑数据,差不多就是之前这段:\n```\nBEGIN:VCALENDAR\nVERSION:2.0\nX-WR-CALNAME:课程表\nX-APPLE-CALENDAR-COLOR:#63DA38\nBEGIN:VEVENT\nDESCRIPTION:教师:曹华山\\n学分:5.0\nDTSTART;TZID=Asia/Shanghai:20201003T160000\nDTEND;TZID=Asia/Shanghai:20201003T193000\nLOCATION:教学楼C404\nSUMMARY:网页设计综合实训\nURL;VALUE=URI:hello\nEND:VEVENT\nEND:VCALENDAR\n```\n然后将文件导入到outlook,便可以看到效果:\n\n\n\n## 进行订阅\n要实现`WebCal`协议其实很简单,本质上还是属于http请求,只需要在返回头加上:\n```\nContent-type: text/calendar; charset=utf-8\nContent-Disposition: attachment; filename=\"table.ics\"\n```\n便可正常在日历App中订阅。\n\n但是参考 iCalendar 的规范,每个事件还得有一个 “UID” 字段,这样便于客户端识别事件以更新。这个 UID 虽然有规范,但实际上你只需要做到和其他事件的 UID 不相同即可,这里我简单的用单个课程的名字,日期和节数进行 md5 计算。\n\n# 最后的效果\n在手机上:\n![87eba7a3-1abf-4b77-a65f-87320789c9e4.png](ipfs://bafkreibyelk7vamp5sgxmpoefwtklg7dv2iyoh4sty35k4bgrkvyxluosu)\n在outlook上:\n![c4b7f146-b0b4-4f31-b325-8dec435fc9aa.png](ipfs://bafkreigocbhkz3gn3ltctwoktkdvplymq2jbg7k7yk2psffxkd7o5zc7we)\n顺便一提,Windows10及以上的系统是能够通过outlook实现订阅到系统日历,也支持锁屏提醒!\n\n# 变得易用\n这样基本的流程便完成了,不过最终服务人群还是同学,所以要将服务打造的简单易用!\n\n现在是将更新任务(每周从教务系统拉数据)部署在云函数上,直接生成静态文件。前端随便找个地方放了就能提供服务了。\n\n数据上的话策略是仅从教务系统拉取前两周,本周,未来四周的数据,这样每次更新都会有更好的性能表现。\n\n目前也已经将服务部署在了站点上:[订阅课程表](https://ics.statict.cn \"订阅课程表\")\n目前测试过了,所有有日历App的Apple设备,Windows10及Windows11,以及小米、华为、Vivo设备均可直接导入。\n\n目前其他安卓设备可以使用`ICSX5`这款软件,可以覆盖绝大多数安卓设备。",
  "attributes": [
    {
      "value": "ics",
      "trait_type": "xlog_slug"
    }
  ]
}