Closed wxt2005 closed 7 years ago
如果要把数据部分独立出来,可以讨论一下数据的定位了。 是单纯地满足 bgmlist.com 就好?还是作为一个番组信息聚合的项目? 目前不少项目都在使用该数据,是否要满足他们的需求?(企图添加 S1 专楼的我
另外,数据维护面向的群体?会 HTTP 增删查改的人吗?会 GitHub 的人吗?一般大众吗?
在我看来,GitHub 上维护 JSON 提供的是数据,而 API 服务器提供的是服务。数据是去中心化的,服务则是要有各种保障。我该如何知道哪些数据更新了?假设你写完 API 服务器开源了,其他人要自行部署该如何同步到最新数据?
我是认为维护 JSON 的方式比较好,独立为 repository 可以有。
考虑了一下,我觉得去中心化的方案确实较优。大家都可以使用这份数据来构建自己的站点,同时也可以帮助完善内容。
数据定位来说,应该可以不限于 bgmlist.com 所需要的那些,但暂时还是以放送时间、放送站点以及一些主要的 meta data 为主会比较好(你提到的 S1 专楼,可以放在相关链接之类的字段中)。当然有人愿意贡献的话,可以考虑在将来添加更多的字段。
放在 GitHub 上的话,维护者应该主要还是 GitHub 用户了。对于普通用户来说,可以采用 @CnSimonChan 所移到的通过 bot 自动生成 issue 的方式来反馈问题。
一些设想:
bgmdata -s 201607 -o ./json/bangumi-201607.json
之类的命令;或者 const bgmdata = require('bgmdata');
后,可以使用 bgmdata.raw();
之类的 API 来获取特定数据。不过严格来讲这些功能应该算是另一个项目,应该由 bgmdata-cli 之类的包来做,bgmdata 可能应该只提供一个 JSON。讨论下数据格式?
title
是扁平化还是结构化?
{
"titleCN": "偶像大师 灰姑娘女孩",
"titleEN": "THE IDOLM@STER CINDERELLA GIRLS",
"titleJP": "アイドルマスター シンデレラガールズ"
}
{
"title": {
"en-US": "THE IDOLM@STER CINDERELLA GIRLS",
"ja": "アイドルマスター シンデレラガールズ",
"zh-Hans": "偶像大师 灰姑娘女孩",
"zh-Hant": "偶像大師 灰姑娘女孩"
}
}
放送时间是否使用世界标准时间?例如 {"showDate": "2015-01-09", "timeJP": "2300"}
,由 Date.parse('2015-01-09 23:00:00 UTC+8')
计算得,{"showTimeJP": 1420815600000}
。
weekDayJP
是冗余数据,newBgm
应该也算冗余。
另外和 title
一样,扁平还是结构?showTimeCN
足够表示放送信息吗?各视频站放送时间可能不同,是否都要收录?
{
"time": {
// 日本电视台放送开始
"begin": 1420815600000,
// 日本电视台放送结束
"end": 1428678000000,
// 各视频站放送开始
"acfun": 1420821000000,
"bilibili": 1420821000000
}
}
最后是 sites
信息:
{
"site": {
"offical": {
"type": "info",
"url": "http://imas-cinderella.com/"
},
"tudou": {
"type": "onair",
"comment": "注释",
"url": "http://www.tudou.com/albumcover/qgdKuHlPg9g.html",
// or
"id": "qgdKuHlPg9g"
}
}
}
我是觉得 sites
为数组更方便 filter:
{
"sites": [
{
"name": "offical",
"type": "offical",
"url": "http://imas-cinderella.com/"
},
{
"name": "tudou",
"type": "onair",
"comment": "注释",
"id": "qgdKuHlPg9g"
},
{
"name": "saraba1st",
"type": "info",
"id": "1059367"
},
{
"name": "dmhy",
"type": "resource",
"keyword": "娘女孩"
}
]
}
最终的数据:
[
{
"id": 101399,
"title": {},
"time": {},
"sites": []
},
{
"id": 110600,
"title": {},
"time": {},
"sites": []
},
// ...
]
参考你的建议,修改了一些地方:
[
{
// id 建议不要和 bangumi 挂钩比较好,毕竟数据本身是不依赖它的。
// 可以用“年份+开播月份+index”
"id": 161002,
// meta data 尽量还是放在最外层
"title": "アイドルマスター シンデレラガールズ",
"officialSite": "http://imas-cinderella.com/",
"begin": 1420815600000,
"end": 1428678000000,
"comments": "注释",
// 所有翻译的标题放在一起
"titleTrans": {
"en-US": [
"THE IDOLM@STER CINDERELLA GIRLS"
],
// 考虑到多个译名的情况,可以为一个数组
"zh-Hans": [
"偶像大师 灰姑娘女孩",
"爱马仕 灰姑娘"
],
"zh-Hant": [
"偶像大師 灰姑娘女孩"
]
},
// 放送站点、下载站点和其它站点分开
"watchSites": {
"tudou": {
// url 建议还是用实际链接,有些站都换过几次链接格式了,id 不一定通用。
// 可能增加一些维护成本
"url": "http://www.tudou.com/albumcover/qgdKuHlPg9g.html",
// 是否官方放送,例如 C 站就不能算
"official": true,
// 是否只有会员才能看
"premuiumOnly": true,
"begin": 1420821000000,
// 是否为和谐版
"censored": true,
// 预留以后可能引入英文放送站的可能性
"lang": "zh",
"comments": "注释"
}
},
"downloadSites": {
"dmhy": {
"keyword": "娘女孩"
}
},
"otherSites": {
"saraba1st": {
"id": "1059367"
},
"bangumi": {
"id": "68812"
}
}
}
]
id 用「年份+开播月份+index」可以,但这样的话最好是字符串,比如 "1610-1"
之类的,万一哪天业界起死回生了一季度上百部番(
标题、官网、放送时间这些 meta 可能确实是放在外层比较好,放在里面感觉变「特例」了。
标题翻译为数组的话,应该要保证流传最广的那个翻译作为第 0 个元素。
对于站点,各种类型分开目前看是可以,但其他类型直接一个 otherSites 感觉不太好。如果以后收录的站点多起来了全塞里面吗?如果为某个类型的站点新增一个字段以何为根据呢?watchSites 和 downloadSites 独立为字段只是因为 bgmlist.com 要用到吧。
我觉得,数据部分独立为一个项目后,应当与业务逻辑无关,要考虑的是数据结构怎样才能方便人工维护、方便程序读取。你的结构限定了先查询站点类型,再查询站点名称。仅仅作为例子,假设所有站点都可能有 comments 字段,而我要获取含有 comments 字段的那些站点,那我要先把所有类型的站点合并到一个数组里,然后再去 filter,这样就比较麻烦了。我更倾向于数组也是这个理由,把 "tudou"
作为 key 是因为绝大多数情况下我们都以站点名作为查询条件,但总会有其他情况。
站点链接用数组存储我没有什么意见。但是对于所有站点都混杂地放在一起,用 type 值来区分这点,我觉得在维护的时候会造成一些麻烦。各种类型的链接穿插在一起,肉眼分辨起来是很困难的。毕竟现在维护的时候,大部分情况下还是要靠人工的。
标题的问题,现在提出的方案需要默认名称是日文,如果以后需要收录国产或欧美动画呢?可以改成和 translation 一样的模式
站点,我也赞同全部放在一起,用 type 区分的方式。
在上面我有提到,测试部分可以检验字段顺序。或者我们直接写个 format.js,自动修正为规定的格式和顺序,要求提交 commit 前必须 npm run format
一下。这样,如果是添加新站点,直接填进去,npm run format
后就不用管了;如果是修改已有站点,就根据规定好的顺序去找,这个操作复杂度和分成多个字段是一样的。
或许 titleTrans 里应该加上 ja 字段?不懂 translation 是什么模式。
另外放送时间,我想了想还是应该使用 ISO 8601 格式,new Date('2015-01-09 23:00:00 UTC+8').toISOString()
-> 2015-01-09T15:00:00.000Z
,毕竟是人工维护的,可读性强一点比较好。
meta data 里的 title
就确定为作品的原名,如果是国产作品就为中文。这种情况下,如果有日文译名,则在 titleTrans 里增加 jp
字段好了。
那么现在决定的格式大致上是这样:
[
{
"id": "1607-1",
"title": "アイドルマスター シンデレラガールズ",
"officialSite": "http://imas-cinderella.com/",
"begin": "2015-01-09T15:00:00.000Z",
"end": "2015-01-09T15:00:00.000Z",
"comments": "注释",
"titleTrans": {
"en-US": [
"THE IDOLM@STER CINDERELLA GIRLS"
],
"zh-Hans": [
"偶像大师 灰姑娘女孩",
"爱马仕 灰姑娘"
],
"zh-Hant": [
"偶像大師 灰姑娘女孩"
]
},
"sites": [
{
"type": "onair",
"name": "tudou",
"url": "http://www.tudou.com/albumcover/qgdKuHlPg9g.html",
"official": true,
"premuiumOnly": true,
"begin": 1420821000000,
"censored": true,
"lang": "zh",
"comments": "注释"
},
{
"type": "onair",
"name": "bilibili",
"url": "http://bangumi.bilibili.com/anime/5057/",
"official": true,
"premuiumOnly": false,
"begin": 1420821000000,
"censored": false,
"lang": "zh",
"comments": ""
},
{
"type": "resource",
"name": "dmhy",
"keyword": "娘女孩"
}
{
"type": "info",
"name": "saraba1st",
"id": "1059367"
},
{
"type": "info",
"name": "bangumi",
"id": "12345"
}
]
}
]
如果我想显示所有项目的中文名,该如何区分 1) 项目本来就是中文所以翻译列表里没有中文 和 2) 项目名暂时还没有中文翻译所以翻译列表里没有中文 ?
JSON 的 key 一般用全小写 + 下划线分割单词
sites 里的主要字段统一命名为 value,怎么理解是之后的事
或许顶层得再加个 lang
字段指明作品语言,但感觉这样怪怪的。
JSON 的 key 我看到的是驼峰式的比较多,JS 在取值时出现下划线还是比较难受的。Google JSON Style Guide(中译)
sites 里的主要字段是指什么?
那可能真的得加个字段 lang
来指明作品的语言了,这样也方便筛选各种语言的番组。
sites
里的字段这样看起来确实有点乱,但是全用 Value
似乎也不太好,是不是需要有个文档来说明各个站点的规则?毕竟也不是所有 info
类的站点都可以用 id
来表示。或者干脆全部用 url
?
info 类或许还能细分一下,可能可以加的站点有 aniDB、MyAnimeList、豆瓣、贴吧、维基(title 直接拼接?)。当然,这些是等有人能 PR 再考虑。
每种类型的站点有哪些字段肯定要有文档说明的。
主要字段可能是统一比较好,然后想了想该统一为 id 还是 url。
其实 id 肯定是有的,同一站点不同番组 url 中变化的部分就可以看作 id;对于某一番组而言,id 一般也是不会变的,我知道变过链接格式的有 AcFun、Bilibili、乐视、PPTV,只有 PPTV 是改了 id 的,但原 id 还是能用,拼接回去的 url 会跳转到新地址。
用 url 的话,如果链接格式改变就要改变所有番组的 url,但使用者就不用改了;用 id 的话,链接格式改变与本项目无关,需要变的是使用者,他要根据新的格式拼回去。上述的「使用者」是假定要使用 url(可能是大多数情况),如果「使用者」的目标是 id(比如我),那 url 就没什么好处了。
一些比较:
讲道理这时候应该优先考虑兼容性选择 url,但作为少数派的挣扎,我提个方案希望不会被打死:
在顶层加一个 urlTemplate
字段,指明某一站点的 url 模板。
{
"urlTemplate": {
"tudou": {
"before": "http://www.tudou.com/albumcover/",
"after": ".html"
},
// or
"tudou": ["http://www.tudou.com/albumcover/", ".html"]
},
"sites": [
{
"type": "onair",
"name": "tudou",
"id": "uGqEOjd4Wd4"
}
]
}
这样要 url 的有固定方法拼接不会有兼容问题,要 id 的不用另行为每一个站点写正则匹配。只是长得有点丑?
如果用这种方案的话,就干脆把站点的 meta data 分出来维护好了。 url 规则就用类似模板的方式去写。
{
"sites": {
"tudou": {
"name": "土豆",
"type": "onair",
"urlTemplate": "http://www.tudou.com/albumcover/{{id}}.html"
},
"saraba1st": {
"name": "S1",
"type": "info",
"urlTemplate": "http://bbs.saraba1st.com/2b/thread-{{id}}-1-1.html"
},
"dmhy": {
"name": "动漫花园",
"type": "resource",
"urlTemplate": "https://share.dmhy.org/topics/list?keyword={{keyword}}"
}
},
"bangumis": [
// ...
]
}
这么一说才发现 type
也算冗余,以后有没有可能出现一个站点有两种类型的情况?比如 S1 的讨论楼 type 为 forum,投票楼为 vote 之类的。
bangumis
字段指的是「番组们」而不是「Bangumi.tv 的数据」吧?罗马字加英文 s 实在是比较少见,况且与 Bangumi.tv 有歧义。不如直接命名为 sites
和 sitesMeta
。
冗余和效率总是难以两全,type
作为最常用的字段,是否应该优先效率?
data.sites.filter(site => site.type === 'onair');
// vs
data.sites.filter(site => data.sitesMeta[site.name].type === 'onair');
不过感觉后者也能接受。
sites
中的 name
是来自域名的代号,sitesMeta
中的 name
是官方表达的名称,是否应该换个字段名防止歧义?
resource
类的主要字段用 keyword
不是又没有统一了么。像 acg.rip 使用的是数字 ID,应当统一为 id
。
模板的字符串替换怕一些奇葩的 url,不过应该不会有。另外主要字段统一为 id
后,{{id}}
中的 id 就不必须了,替换部分只要是个唯一的字符串就行了,替换更方便。
type
不同,干脆就用不同的 name
好了,S1Discussion
S1Vote
之类的。items
和 sites
算了😌title
吧。如果主要字段只用作拼接 url 的话,那没什么问题;如果其他部分也要用到的话,还要先从 urlTemplate 里获取得知哪个字段是主要字段才行。现在暂时也想不出有什么其他用途。
另外腾讯视频的 url 有点特殊,http://v.qq.com/detail/w/wgzklo5zkrgalda.html
中 id 前面会有一个字符,与 id 的第一位相同,这个该怎么处理?直接 w/wgzklo5zkrgalda
作为 id 吗?
还有优酷,http://www.youku.com/show_page/id_z1e13314abec311e38b3f.html
的 id 部分似乎总是以 z
开头的,实际上在优酷的各种 API 中也是以 z
后面的那部分作为 id 的,应该要和官方保持一致吧?
虽然麻烦了点,不过想写正则替换的时候应该还是会瞄一眼字段里有啥字段名的吧。 或者用类似下面这样的函数,就不用去关心字段名是什么了。
urlTemplate.replace(/{{(\w+)}}/g, (match, key) => data.key);
id 规则特殊情况特殊处理。
腾讯视频的话,确实看起来比较难受,但也只能把变化的部分作为 id 了,用 w/wgzklo5zkrgalda
这部份。
优酷也是同样,既然变化的只有 z
之后的部分,而且官方 api 也有规定,那就遵序这个规则好了。
先 repo 建起来文档写起来?
目前 bangumi-list 有相关 API 么?
@weizhenye @CnSimonChan 总之先建了个 repo: https://github.com/bangumi-data/bangumi-data
@GPBeta 不好意思,暂时还没有哦
之前的讨论见 #38
现在的几种方案: