koishi-plugin-bilibili-notify 4.1.2 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/lib/index.cjs +199 -66
- package/lib/index.d.cts +12 -4
- package/lib/index.d.mts +12 -4
- package/lib/index.mjs +199 -66
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7d01398: 修复账号失效时控制台仍显示「已登录」、整天无推送的 bug,并重构登录态管线:
|
|
8
|
+
|
|
9
|
+
- BilibiliAPI 在响应体识别到 code -101 时通过新的 `onAuthLost` 回调通知上层
|
|
10
|
+
(60 秒防抖),cookie 刷新返回 -101 时也走同一路径,不再静默重置 HTTP
|
|
11
|
+
客户端。
|
|
12
|
+
- 新增 `LoginStatusController` 集中管理登录态:所有 14 处 emit 收敛到
|
|
13
|
+
reporter;启动期 `getMyselfInfo` 返回 -101 不再误报 LOGGED_IN;之前静默
|
|
14
|
+
swallow 的异常路径也会上报。控制器只在 `(status, msg, data)` 实际变化
|
|
15
|
+
时 emit,避免心跳带来的 UI 抖动。
|
|
16
|
+
- 新增配置项 `loginHealthCheckMinutes`(默认 30 分钟,范围 5–180),在已
|
|
17
|
+
登录态下定期 probe,运行中失效会立即翻转 UI、广播内部事件
|
|
18
|
+
`bilibili-notify/auth-lost`;恢复后广播 `bilibili-notify/auth-restored`,
|
|
19
|
+
让 dynamic / live 自动重启检测,无需手动重启插件。
|
|
20
|
+
- live 删除手写的 3 次 retry(API 层已 retry 3 次),失败时改为 emit
|
|
21
|
+
`plugin-error` 而非静默 return。
|
|
22
|
+
- 新增调试命令 `bili status auth` 查看当前登录状态。
|
|
23
|
+
- 控制台 UI 删除一闪而过的「登录成功」中转视图(与「已登录」重复)及无
|
|
24
|
+
listener 的「重启插件」按钮。
|
|
25
|
+
- `BiliLoginStatus` 枚举删除 `LOGGING_IN`(从未 emit)与 `LOGIN_SUCCESS`
|
|
26
|
+
(已被 `LOGGED_IN` 取代),故 api 包按 minor 级别 bump。
|
|
27
|
+
- 工具函数 `withLock` 提升到 `@bilibili-notify/internal` 供后续复用。
|
|
28
|
+
- 修复 `auth-restored` 在"运行中失效 → 扫码恢复"路径下不会触发的回归:
|
|
29
|
+
之前用"上一帧 status === NOT_LOGIN"作判据,但失效后用户扫码会经过
|
|
30
|
+
LOGIN_QR / LOGGING_QR 中间态,导致 dynamic / live 永远收不到恢复事件
|
|
31
|
+
无法重启监测;改用 sticky 的 `needsRestore` 标志解决。
|
|
32
|
+
- 修复登录刚成功瞬间 controller 把 LOGIN_QR 留下的 base64 字符串作为
|
|
33
|
+
`data` fallback 传给前端,导致前端访问 `data.card.face` 抛错的小问题;
|
|
34
|
+
现在仅当 `snapshot.data` 形态像 card 时才沿用,前端也加了 `data?.card`
|
|
35
|
+
的安全访问。
|
|
36
|
+
- 整理 `UserCardInfoData` 类型:拆出 `UserCard` / `UserCardSpace` /
|
|
37
|
+
`UserCardInfo` 子类型并补齐控制台 UI 实际使用的 `attention` /
|
|
38
|
+
`vip.vipStatus` / `vip.label.img_label_uri_hans_static` / `space.l_img`
|
|
39
|
+
字段,删除前端 settings.vue 内联的 80+ 行 workaround 类型定义。
|
|
40
|
+
- 收敛 `auth-lost` 事件来源:由 api response interceptor 的
|
|
41
|
+
`onAuthLost` 回调单点广播,dynamic 在 -101 分支不再重复 emit;同时
|
|
42
|
+
删除 dynamic 自己的"账号未登录"私信,避免与 server-manager 节流私
|
|
43
|
+
信内容重复。
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies [7d01398]
|
|
48
|
+
- @bilibili-notify/api@0.1.0
|
|
49
|
+
- @bilibili-notify/internal@0.0.3
|
|
50
|
+
- @bilibili-notify/subscription@1.0.3
|
|
51
|
+
|
|
3
52
|
## 4.1.2
|
|
4
53
|
|
|
5
54
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineComponent as
|
|
1
|
+
import{defineComponent as F,inject as T,ref as u,watch as D,resolveComponent as N,openBlock as i,createElementBlock as o,Fragment as V,createElementVNode as e,toDisplayString as a,createCommentVNode as d,createBlock as q,withCtx as r,createVNode as v,createTextVNode as f,withDirectives as E,vShow as M}from"vue";import{store as S,send as _}from"@koishijs/client";const j={key:0,class:"loading-wrapper"},A={class:"comment"},K={key:0,class:"comment"},L=["src"],O={key:1,class:"comment"},z={class:"comment"},G={class:"comment"},H={style:{display:"flex",gap:"0.5rem"}},J={key:0,class:"loading-wrapper"},P={key:1,class:"logged-in fade-in"},Q={class:"user-bg-wrapper"},R=["src"],U={class:"user-info"},W=["src"],X={class:"name-sign"},Y={class:"user-desc"},Z={class:"user-name"},h=["src"],t1={class:"user-sign"},e1={class:"user-status"},l1=F({__name:"settings",setup(m){const C=T("manager.settings.local"),p=u(""),y=u(""),b=u(""),k=u(""),s=u({}),B=u(false),n=u(""),I=u(false);D(()=>{var l,t;return[(l=S["bilibili-notify"])==null?void 0:l.status,(t=S["bilibili-notify"])==null?void 0:t.msg]},async()=>{if(C.value.name!=="koishi-plugin-bilibili-notify")return;const l=S["bilibili-notify"];if(l)switch(s.value=l,l.status){case 1:n.value="loading";return;case 0:n.value="not_login";return;case 5:{n.value="logged_in";const t=l.data;if(!(t!=null&&t.card))return;const c=setTimeout(()=>{I.value=true},6e4);try{p.value=await _("bilibili-notify/request-cors",t.card.face),y.value=await _("bilibili-notify/request-cors",t.space.l_img),b.value=await _("bilibili-notify/request-cors",t.card.vip.label.img_label_uri_hans_static),B.value=true}finally{clearTimeout(c)}return}case 2:k.value=s.value.data,n.value="logging_qr";return;case 3:n.value="logging_qr";return;case 7:n.value="login_failed";return}},{immediate:true});const g=()=>{_("bilibili-notify/start-login")},$=()=>{_("bilibili-notify/reset-key")},x=l=>l>=1e8?`${(l/1e8).toFixed(1).replace(/\.0$/,"")}亿`:l>=1e4?`${(l/1e4).toFixed(1).replace(/\.0$/,"")}万`:l.toString();return(l,t)=>{const c=N("k-button"),w=N("k-comment");return i(),o(V,null,[n.value==="loading"?(i(),o("div",j,[t[0]||(t[0]=e("div",{class:"spinner"},null,-1)),e("p",null,a(s.value.msg),1)])):d("v-if",true),n.value==="not_login"?(i(),q(w,{key:1,type:"error"},{default:r(()=>[e("div",A,[e("p",null,a(s.value.msg),1),v(c,{onClick:g},{default:r(()=>[...t[1]||(t[1]=[f("登录",-1)])]),_:1})])]),_:1})):d("v-if",true),n.value==="logging_qr"?(i(),q(w,{key:2,type:"warning"},{default:r(()=>[k.value?(i(),o("div",K,[t[2]||(t[2]=e("p",null,"请使用Bilibili App扫码登录",-1)),e("img",{class:"qrcode",src:k.value,alt:"qrcode"},null,8,L),e("p",null,a(s.value.msg),1)])):d("v-if",true),k.value?d("v-if",true):(i(),o("div",O,[t[4]||(t[4]=e("p",null,"二维码显示失败,请重新登录",-1)),v(c,{onClick:g},{default:r(()=>[...t[3]||(t[3]=[f("重新登录",-1)])]),_:1})]))]),_:1})):d("v-if",true),n.value==="login_failed"?(i(),q(w,{key:3,type:"error"},{default:r(()=>[e("div",z,[e("p",null,a(s.value.msg),1),v(c,{onClick:g},{default:r(()=>[...t[5]||(t[5]=[f("重新登录",-1)])]),_:1})])]),_:1})):d("v-if",true),n.value==="logged_in"?(i(),o(V,{key:4},[v(w,{type:"warning",style:{"margin-bottom":"1rem"}},{default:r(()=>[e("div",G,[t[8]||(t[8]=e("p",null,"重新登录:重新触发扫码流程,不清除已有密钥。",-1)),t[9]||(t[9]=e("p",null,"重置密钥:清除已保存的 Cookie 和密钥,需要重新扫码登录。",-1)),e("div",H,[v(c,{onClick:g},{default:r(()=>[...t[6]||(t[6]=[f("重新登录",-1)])]),_:1}),v(c,{onClick:$},{default:r(()=>[...t[7]||(t[7]=[f("重置密钥",-1)])]),_:1})])])]),_:1}),B.value?(i(),o("div",P,[e("div",Q,[e("img",{class:"user-bg",src:y.value,alt:"user-bg"},null,8,R)]),e("div",U,[e("img",{class:"avatar",src:p.value,alt:"avatar"},null,8,W),e("div",X,[e("div",Y,[e("span",Z,a(s.value.data.card.name),1),s.value.data.card.vip.vipStatus===1?(i(),o("img",{key:0,class:"user-vip",src:b.value,alt:"vip"},null,8,h)):d("v-if",true)]),e("span",t1,a(s.value.data.card.sign),1)])]),e("div",e1,[e("div",null,[t[13]||(t[13]=e("span",null,"关注数",-1)),e("span",null,a(x(s.value.data.card.attention)),1)]),e("div",null,[t[14]||(t[14]=e("span",null,"粉丝数",-1)),e("span",null,a(x(s.value.data.card.fans)),1)]),e("div",null,[t[15]||(t[15]=e("span",null,"获赞数",-1)),e("span",null,a(x(s.value.data.like_num)),1)])]),(i(),o("svg",{onClick:g,class:"logo",t:"1645466458357",viewBox:"0 0 2299 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","p-id":"2663",width:"180",style:{fill:"var(--bew-theme-color)"}},[...t[16]||(t[16]=[e("path",{d:"M1775.840814 322.588002c6.0164 1.002733 53.144869-9.525967 55.150336-6.016401 3.0082 4.5123 24.065601 155.92504 18.550567 156.927774s-44.621635 10.027334-44.621635 10.027334c-3.0082-20.556034-28.577901-147.903173-29.079268-160.938707m75.205003-14.539634l20.556034 162.944174c10.5287-0.501367 53.144869-3.509567 57.155803-4.010934-6.0164-61.668103-16.545101-158.933241-16.545101-158.93324-20.054668-4.010934-41.112069-4.010934-61.166736 0m-40.610702 226.116376s92.752838-23.564234 126.344406-12.0328c17.046467 61.668103 48.131202 407.611118 51.139402 421.649386-21.057401 2.506833-90.246004 8.523234-95.761037 10.027333-4.5123-26.071068-81.72277-403.098818-81.722771-419.643919m343.436183-207.565809c5.515034 1.5041 54.648969-5.013667 55.150335-1.5041 1.002733 12.032801 6.0164 157.42914 0.501367 157.930507s-44.621635 4.010934-44.621635 4.010934c-1.002733-20.054668-12.032801-146.90044-11.030067-160.437341m75.70637-4.010933l4.010933 160.938707c10.5287 0 52.643502 2.506833 57.155803 2.005467-1.002733-61.668103 0-158.933241 0-158.933241-20.054668-3.509567-40.610702-5.013667-61.166736-4.010933m-64.676303 216.089043s94.758304-12.534167 126.845772 2.506833c7.019134 72.196803 6.0164 408.613852 7.019134 422.652119-21.558768 0-90.246004 1.002733-95.761038 2.005467-1.002733-26.071068-39.607968-410.619319-38.103868-427.164419m-220.099977-413.627519c54.648969 278.759879 96.262404 755.058234 97.766504 785.641602 0 0 43.117535 1.002733 91.750105 4.010934C2105.740095 614.383415 2070.644427 134.575493 2071.145794 119.033126c-12.032801-13.536901-126.344406 6.0164-126.344406 6.0164m-120.328005 659.297196c-10.5287-78.213204-290.291313-166.955108-447.720454-138.377206 0 0-19.553301-172.470141-27.073801-339.425248-6.517767-143.390873-1.002733-282.770813 0.501366-305.833681-10.5287-7.5205-123.837572 46.627102-185.004308 69.188603 0 0 73.199537 309.844614 126.344406 952.59671 0 0 84.730971 9.0246 230.12731-19.051934s317.365114-115.815705 302.825481-219.097244m-341.932083 140.88404l-24.566967-176.982441c6.0164-3.0082 156.927774 53.144869 172.971507 63.172203-2.506833 11.030067-148.40454 113.810238-148.40454 113.810238M610.664628 322.588002c6.0164 1.002733 53.144869-9.525967 55.150335-6.016401 3.0082 4.5123 24.065601 155.92504 18.550568 156.927774s-44.621635 10.027334-44.621635 10.027334c-3.0082-20.556034-28.577901-147.903173-29.079268-160.938707m75.205003-14.539634l20.556034 162.944174c10.5287-0.501367 53.144869-3.509567 57.155803-4.010934-6.517767-61.668103-16.545101-158.933241-16.545101-158.93324-20.054668-4.010934-41.112069-4.010934-61.166736 0m-40.610702 226.116376s92.752838-23.564234 126.344406-12.0328c17.046467 61.668103 48.131202 407.611118 51.139402 421.649386-21.057401 2.506833-90.246004 8.523234-95.761037 10.027333-4.5123-26.071068-81.72277-403.098818-81.722771-419.643919m343.436182-207.565809c5.515034 1.5041 54.648969-5.013667 55.150336-1.5041 1.002733 12.032801 6.0164 157.42914 0.501367 157.930507s-44.621635 4.010934-44.621635 4.010934c-1.002733-20.054668-11.531434-146.90044-11.030068-160.437341m75.706371-4.010933l4.010933 160.938707c10.5287 0 52.643502 2.506833 57.155803 2.005467-1.002733-61.668103 0-158.933241 0-158.933241-20.054668-3.509567-40.610702-4.5123-61.166736-4.010933m-64.676303 216.089043s94.758304-12.534167 126.845772 2.506833c7.019134 72.196803 6.0164 408.613852 7.019134 422.652119-21.558768 0-90.246004 1.002733-95.761038 2.005467-0.501367-26.071068-39.607968-410.619319-38.103868-427.164419m-220.099977-413.627519c54.648969 278.759879 96.262404 755.058234 97.766504 785.641602 0 0 43.117535 1.002733 91.750105 4.010934-28.577901-300.318647-63.67357-780.126569-63.172203-796.170303-12.032801-13.035534-126.344406 6.517767-126.344406 6.517767m-120.328005 659.297196c-10.5287-78.213204-290.291313-166.955108-447.720454-138.377206 0 0-19.553301-172.470141-27.073801-339.425248-6.517767-143.390873-1.002733-282.770813 0.501366-305.833681C174.475608-6.308547 61.166736 47.337689 0 69.89919c0 0 73.199537 309.844614 126.344406 952.59671 0 0 84.730971 9.0246 230.12731-19.051934s317.365114-115.815705 302.825481-219.097244m-341.932083 140.88404l-24.566967-176.982441c6.0164-3.0082 156.927774 53.144869 172.971507 63.172203-2.506833 11.030067-148.40454 113.810238-148.40454 113.810238","p-id":"2664"},null,-1)])]))])):(i(),o("div",J,[t[11]||(t[11]=e("div",{class:"spinner"},null,-1)),t[12]||(t[12]=e("p",null,"正在加载登录账号信息中...",-1)),E(e("div",null,[...t[10]||(t[10]=[e("span",null,"加载太久?可能是网络错误,可以尝试切换到其他插件页再切回来;加载不出来也不影响使用哦~",-1)])],512),[[M,I.value]])]))],64)):d("v-if",true)],64)}}}),s1=(m,C)=>{const p=m.__vccOpts||m;for(const[y,b]of C)p[y]=b;return p},i1=s1(l1,[["__scopeId","data-v-d2414804"]]),a1=m=>{m.slot({type:"plugin-details",component:i1,order:0})};export{a1 as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bew-theme-color: #FB7299}.comment[data-v-
|
|
1
|
+
:root{--bew-theme-color: #FB7299}.comment[data-v-d2414804]{margin-bottom:1rem}.qrcode[data-v-d2414804]{width:10rem;height:10rem}.loading-wrapper[data-v-d2414804]{display:flex;flex-direction:column;align-items:center;justify-content:center;height:200px;color:#888}.loading-wrapper .spinner[data-v-d2414804]{width:40px;height:40px;border:4px solid #ccc;border-top-color:var(--bew-theme-color);border-radius:50%;animation:spin-d2414804 1s linear infinite;margin-bottom:10px}.fade-in[data-v-d2414804]{opacity:0;transform:translateY(10px);animation:fadeIn-d2414804 .5s forwards}.logged-in[data-v-d2414804]{position:relative;display:flex;flex-direction:column;justify-content:space-between;width:30rem;height:8rem;border-radius:1rem;padding:1rem;margin-top:1rem;margin-bottom:1rem;overflow:hidden;box-shadow:0 4px 8px #00000026;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.logged-in .user-bg-wrapper[data-v-d2414804]{position:absolute;left:0;top:0;width:100%;height:10rem;overflow:hidden;z-index:-1}.logged-in .user-bg[data-v-d2414804]{width:100%;height:100%;object-fit:cover}.logged-in .user-bg-wrapper[data-v-d2414804]:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:linear-gradient(to bottom,#0003,#0000);pointer-events:none}.logged-in .user-bg[data-v-d2414804]:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:linear-gradient(to top,#00000080,#0000);pointer-events:none;z-index:1}.logged-in .user-info[data-v-d2414804]{display:flex;gap:1rem}.logged-in .user-info .avatar[data-v-d2414804]{width:5rem;height:5rem;border-radius:50%;border:2px solid white}.logged-in .user-info .name-sign[data-v-d2414804]{display:flex;flex-direction:column;margin-top:.3rem;gap:.2rem;color:#fff;text-shadow:3px 3px 5px rgba(0,0,0,.7)}.logged-in .user-info .name-sign .user-desc[data-v-d2414804]{display:flex;align-items:center;gap:.5rem}.logged-in .user-info .name-sign .user-desc .user-name[data-v-d2414804]{font-weight:700;font-size:1.7rem}.logged-in .user-info .name-sign .user-desc .user-vip[data-v-d2414804]{width:90px}.logged-in .user-info .name-sign .user-sign[data-v-d2414804]{font-weight:700;font-size:.7rem}.logged-in .user-status[data-v-d2414804]{display:flex;gap:1rem;margin-top:1rem;color:#fff;font-size:12px;font-weight:700;text-shadow:3px 3px 5px rgba(0,0,0,.7)}.logged-in .user-status div[data-v-d2414804]{display:flex;flex-direction:column;align-items:center;gap:2px}.logged-in .logo[data-v-d2414804]{position:absolute;right:1rem;bottom:.7rem;width:5rem;box-shadow:0 4px 8px #00000026}@keyframes spin-d2414804{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes fadeIn-d2414804{to{opacity:1;transform:translateY(0)}}
|
package/lib/index.cjs
CHANGED
|
@@ -54,6 +54,7 @@ const BilibiliNotifyConfigSchema = koishi.Schema.object({
|
|
|
54
54
|
})).role("table").description("在这里填写主人的订阅信息~UP 昵称、UID、roomid、平台、群号都要填正确,不然女仆会迷路哒 (;>_<)如果多个群聊/频道,请用英文逗号分隔哦~女仆会努力送到每一个地方的!"),
|
|
55
55
|
logLevel: koishi.Schema.number().min(1).max(3).step(1).default(1).description("这里可以设置日志等级喔~3 是最详细的调试信息,1 是只显示错误信息。主人可以根据需要选择合适的等级,让女仆更好地为您服务 (๑•̀ㅂ•́)و✧"),
|
|
56
56
|
userAgent: koishi.Schema.string().description("这里可以设置请求头的 User-Agent 哦~如果请求出现了 -352 的奇怪错误,主人可以试着在这里换一个看看 (;>_<)"),
|
|
57
|
+
loginHealthCheckMinutes: koishi.Schema.number().min(5).max(180).step(1).default(30).description("登录状态周期检测的间隔(分钟)。女仆会按这个频率悄悄帮主人确认账号还在线哦~如果发现失效会立刻汇报呢 (๑•̀ㅂ•́)و✧"),
|
|
57
58
|
master: koishi.Schema.intersect([koishi.Schema.object({ enable: koishi.Schema.boolean().default(false).description("要不要让笨笨女仆开启主人账号功能呢?(>﹏<)如果机器人遭遇了奇怪的小错误,女仆会立刻跑来向主人报告的!不、不过……如果没有私聊权限的话,女仆就联系不到主人了……请不要打开这个开关喔 (;´д`)ゞ") }).description("主人的特别区域……女仆会乖乖侍奉的!(>///<)"), koishi.Schema.union([koishi.Schema.object({
|
|
58
59
|
enable: koishi.Schema.const(true).required(),
|
|
59
60
|
platform: koishi.Schema.union([
|
|
@@ -407,6 +408,10 @@ function biliCommands() {
|
|
|
407
408
|
//#region src/commands/status.ts
|
|
408
409
|
function statusCommands() {
|
|
409
410
|
const statusCom = this.ctx.command("status", "插件状态相关指令", { permissions: ["authority:5"] });
|
|
411
|
+
statusCom.subcommand(".auth", "查看登录状态").usage("查看登录状态").example("status auth").action(() => {
|
|
412
|
+
const snap = this.getAuthSnapshot();
|
|
413
|
+
return `登录状态:${_bilibili_notify_api.BiliLoginStatus[snap.status] ?? `unknown(${snap.status})`}\n信息:${snap.msg || "(无)"}`;
|
|
414
|
+
});
|
|
410
415
|
statusCom.subcommand(".dyn", "查看动态监测运行状态").usage("查看动态监测运行状态").example("status dyn").action(() => {
|
|
411
416
|
if (this.ctx.get("bilibili-notify-dynamic")) return "动态监测正在运行";
|
|
412
417
|
return "动态插件未运行(请检查是否已安装并启用 koishi-plugin-bilibili-notify-dynamic)";
|
|
@@ -451,6 +456,136 @@ function sysCommands() {
|
|
|
451
456
|
});
|
|
452
457
|
}
|
|
453
458
|
//#endregion
|
|
459
|
+
//#region src/login-status.ts
|
|
460
|
+
const MESSAGES = {
|
|
461
|
+
loading: "正在加载登录信息...",
|
|
462
|
+
notLogin: "账号未登录,请点击「扫码登录」",
|
|
463
|
+
keyReset: "密钥已重置,cookie 已清除,请重新扫码登录",
|
|
464
|
+
authLost: "账号登录已失效,请在控制台重新扫码登录",
|
|
465
|
+
loggedIn: "已登录",
|
|
466
|
+
loginJustSucceeded: "登录成功,正在加载订阅...",
|
|
467
|
+
fetchAccountFailed: "账号已登录,但获取个人信息失败,请检查",
|
|
468
|
+
waitScan: "尚未扫码,请扫码",
|
|
469
|
+
waitConfirm: "已扫码,但尚未确认,请确认",
|
|
470
|
+
qrFetchFailed: "获取二维码失败,请重试",
|
|
471
|
+
qrRenderFailed: "生成二维码失败",
|
|
472
|
+
qrExpired: "二维码已超时(3分钟),请重新登录",
|
|
473
|
+
qrInvalidated: "二维码已失效,请重新登录",
|
|
474
|
+
noCookieAfterLogin: "登录成功但未获取到 cookie,请重试",
|
|
475
|
+
genericLoginFail: "登录失败,请重试"
|
|
476
|
+
};
|
|
477
|
+
/** 类型守卫:snapshot.data 是否长得像 UserCardInfo。 */
|
|
478
|
+
function looksLikeCardData(data) {
|
|
479
|
+
return typeof data === "object" && data !== null && "card" in data;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* 集中管理登录态:所有变更都经过这里,再以 `bilibili-notify/login-status-report`
|
|
483
|
+
* 推到前端。心跳定时器在登录态下定期 probe,发现失效会同时广播
|
|
484
|
+
* `bilibili-notify/auth-lost`,恢复时广播 `bilibili-notify/auth-restored`。
|
|
485
|
+
*/
|
|
486
|
+
var LoginStatusController = class {
|
|
487
|
+
snapshot = {
|
|
488
|
+
status: _bilibili_notify_api.BiliLoginStatus.LOADING_LOGIN_INFO,
|
|
489
|
+
msg: MESSAGES.loading
|
|
490
|
+
};
|
|
491
|
+
healthTimer;
|
|
492
|
+
/**
|
|
493
|
+
* 标记"曾从已登录态掉线",下一次成功登录时翻转为已登录后才发 auth-restored。
|
|
494
|
+
* 之所以不再用"上一帧 status === NOT_LOGIN"判断:失效后用户走扫码流程,会经过
|
|
495
|
+
* LOGIN_QR / LOGGING_QR 等中间态,直接基于上一帧会漏掉这条恢复路径。
|
|
496
|
+
*/
|
|
497
|
+
needsRestore = false;
|
|
498
|
+
constructor(ctx, options) {
|
|
499
|
+
this.ctx = ctx;
|
|
500
|
+
this.options = options;
|
|
501
|
+
}
|
|
502
|
+
current() {
|
|
503
|
+
return { ...this.snapshot };
|
|
504
|
+
}
|
|
505
|
+
attachHealthCheck() {
|
|
506
|
+
this.detachHealthCheck();
|
|
507
|
+
if (this.options.healthCheckMs <= 0) return;
|
|
508
|
+
this.healthTimer = this.ctx.setInterval(() => void this.runHealthCheck(), this.options.healthCheckMs);
|
|
509
|
+
}
|
|
510
|
+
detachHealthCheck() {
|
|
511
|
+
this.healthTimer?.();
|
|
512
|
+
this.healthTimer = void 0;
|
|
513
|
+
}
|
|
514
|
+
reportLoggedIn(card, reasonKey = "loggedIn") {
|
|
515
|
+
const wasLoggedIn = this.snapshot.status === _bilibili_notify_api.BiliLoginStatus.LOGGED_IN;
|
|
516
|
+
const fallback = looksLikeCardData(this.snapshot.data) ? this.snapshot.data : void 0;
|
|
517
|
+
this.transition({
|
|
518
|
+
status: _bilibili_notify_api.BiliLoginStatus.LOGGED_IN,
|
|
519
|
+
msg: MESSAGES[reasonKey],
|
|
520
|
+
data: card ?? fallback
|
|
521
|
+
});
|
|
522
|
+
if (!wasLoggedIn && this.needsRestore) {
|
|
523
|
+
this.needsRestore = false;
|
|
524
|
+
this.ctx.emit("bilibili-notify/auth-restored");
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
reportLoggedOut(reasonKey = "notLogin") {
|
|
528
|
+
const wasLoggedIn = this.snapshot.status === _bilibili_notify_api.BiliLoginStatus.LOGGED_IN;
|
|
529
|
+
this.transition({
|
|
530
|
+
status: _bilibili_notify_api.BiliLoginStatus.NOT_LOGIN,
|
|
531
|
+
msg: MESSAGES[reasonKey]
|
|
532
|
+
});
|
|
533
|
+
if (wasLoggedIn) {
|
|
534
|
+
this.needsRestore = true;
|
|
535
|
+
this.ctx.emit("bilibili-notify/auth-lost");
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/** Dispatch on `getMyselfInfo` result code. */
|
|
539
|
+
reportLoginCheck(code, card) {
|
|
540
|
+
if (code === 0) this.reportLoggedIn(card);
|
|
541
|
+
else if (code === -101) this.reportLoggedOut("authLost");
|
|
542
|
+
else this.reportTransientFailure(`code=${code}`);
|
|
543
|
+
}
|
|
544
|
+
/** Keep current status, only refresh msg. Logs at warn level. */
|
|
545
|
+
reportTransientFailure(detail) {
|
|
546
|
+
this.options.logger.warn(`[auth] 瞬时失败:${detail}`);
|
|
547
|
+
if (this.snapshot.status !== _bilibili_notify_api.BiliLoginStatus.LOGGED_IN) return;
|
|
548
|
+
this.transition({
|
|
549
|
+
...this.snapshot,
|
|
550
|
+
msg: MESSAGES.fetchAccountFailed
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
reportQrReady(base64) {
|
|
554
|
+
this.transition({
|
|
555
|
+
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_QR,
|
|
556
|
+
msg: "",
|
|
557
|
+
data: base64
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
reportQrPending(reasonKey) {
|
|
561
|
+
this.transition({
|
|
562
|
+
status: _bilibili_notify_api.BiliLoginStatus.LOGGING_QR,
|
|
563
|
+
msg: MESSAGES[reasonKey]
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
reportQrFailure(reasonKey) {
|
|
567
|
+
this.transition({
|
|
568
|
+
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
569
|
+
msg: MESSAGES[reasonKey]
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
/** Emit only when (status, msg, data) changes. */
|
|
573
|
+
transition(next) {
|
|
574
|
+
if (this.snapshot.status === next.status && this.snapshot.msg === next.msg && this.snapshot.data === next.data) return;
|
|
575
|
+
this.snapshot = next;
|
|
576
|
+
this.ctx.emit("bilibili-notify/login-status-report", next);
|
|
577
|
+
}
|
|
578
|
+
async runHealthCheck() {
|
|
579
|
+
if (this.snapshot.status === _bilibili_notify_api.BiliLoginStatus.LOGIN_QR || this.snapshot.status === _bilibili_notify_api.BiliLoginStatus.LOGGING_QR || this.snapshot.status === _bilibili_notify_api.BiliLoginStatus.NOT_LOGIN) return;
|
|
580
|
+
try {
|
|
581
|
+
const res = await this.options.probe();
|
|
582
|
+
this.reportLoginCheck(res.code);
|
|
583
|
+
} catch (e) {
|
|
584
|
+
this.options.logger.warn(`[auth] 心跳异常(保持当前状态):${e}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
//#endregion
|
|
454
589
|
//#region src/server-manager.ts
|
|
455
590
|
const SERVICE_NAME = "bilibili-notify";
|
|
456
591
|
const LIVE_MASTER_KEYS = [
|
|
@@ -502,6 +637,8 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
502
637
|
running = false;
|
|
503
638
|
storageMgr;
|
|
504
639
|
currentSubs = null;
|
|
640
|
+
auth;
|
|
641
|
+
authLostNotifiedAt = 0;
|
|
505
642
|
constructor(ctx, config) {
|
|
506
643
|
super(ctx, SERVICE_NAME);
|
|
507
644
|
this.selfCtx = ctx;
|
|
@@ -512,6 +649,10 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
512
649
|
get subManager() {
|
|
513
650
|
return this.subMgr?.subManager ?? /* @__PURE__ */ new Map();
|
|
514
651
|
}
|
|
652
|
+
/** For commands: read the current login snapshot. */
|
|
653
|
+
getAuthSnapshot() {
|
|
654
|
+
return this.auth.current();
|
|
655
|
+
}
|
|
515
656
|
subList() {
|
|
516
657
|
const map = this.subManager;
|
|
517
658
|
if (!map.size) return "没有订阅任何UP";
|
|
@@ -526,6 +667,14 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
526
667
|
this.serverLogger.info("[start] 正在启动中...");
|
|
527
668
|
this.storageMgr = new _bilibili_notify_storage.StorageManager(this.ctx.baseDir, this.ctx);
|
|
528
669
|
await this.storageMgr.init();
|
|
670
|
+
this.auth = new LoginStatusController(this.selfCtx, {
|
|
671
|
+
healthCheckMs: this.config.loginHealthCheckMinutes * 6e4,
|
|
672
|
+
logger: this.serverLogger,
|
|
673
|
+
probe: () => {
|
|
674
|
+
if (!this.api) throw new Error("api not initialized");
|
|
675
|
+
return this.api.getMyselfInfo();
|
|
676
|
+
}
|
|
677
|
+
});
|
|
529
678
|
this.ctx.on("bilibili-notify/cookies-refreshed", async (data) => {
|
|
530
679
|
try {
|
|
531
680
|
await this.storageMgr.cookieStore.save(data);
|
|
@@ -701,8 +850,13 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
701
850
|
this.api = new _bilibili_notify_api.BilibiliAPI(this.selfCtx, {
|
|
702
851
|
logLevel: this.config.logLevel,
|
|
703
852
|
userAgent: this.config.userAgent
|
|
704
|
-
},
|
|
705
|
-
|
|
853
|
+
}, {
|
|
854
|
+
onCookiesRefreshed: (data) => {
|
|
855
|
+
this.selfCtx.emit("bilibili-notify/cookies-refreshed", data);
|
|
856
|
+
},
|
|
857
|
+
onAuthLost: () => {
|
|
858
|
+
this.handleAuthLost();
|
|
859
|
+
}
|
|
706
860
|
});
|
|
707
861
|
this.push = new _bilibili_notify_push.BilibiliPush(this.selfCtx, {
|
|
708
862
|
logLevel: this.config.logLevel,
|
|
@@ -721,10 +875,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
721
875
|
this.serverLogger.debug(`[cookie] Cookie 加载完成,登录状态:${this.isLoggedIn() ? "已登录" : "未登录"}`);
|
|
722
876
|
if (!this.isLoggedIn()) {
|
|
723
877
|
this.serverLogger.info("[login] 账号未登录,请在控制台扫码登录");
|
|
724
|
-
this.
|
|
725
|
-
status: _bilibili_notify_api.BiliLoginStatus.NOT_LOGIN,
|
|
726
|
-
msg: "账号未登录,请点击「扫码登录」"
|
|
727
|
-
});
|
|
878
|
+
this.auth.reportLoggedOut("notLogin");
|
|
728
879
|
return true;
|
|
729
880
|
}
|
|
730
881
|
await this.reportAccountInfo();
|
|
@@ -740,6 +891,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
740
891
|
this.serverLogger.debug("[stop] 正在清理插件资源...");
|
|
741
892
|
this.running = false;
|
|
742
893
|
this.clearLoginTimer();
|
|
894
|
+
this.auth?.detachHealthCheck();
|
|
743
895
|
if (this.subNotifier) {
|
|
744
896
|
this.subNotifier.dispose();
|
|
745
897
|
this.subNotifier = void 0;
|
|
@@ -802,23 +954,38 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
802
954
|
}
|
|
803
955
|
async reportAccountInfo() {
|
|
804
956
|
if (!this.api) return;
|
|
957
|
+
let personalInfo;
|
|
805
958
|
try {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
this.
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
959
|
+
personalInfo = await this.api.getMyselfInfo();
|
|
960
|
+
} catch (e) {
|
|
961
|
+
this.serverLogger.warn(`[account] 获取个人信息异常: ${e}`);
|
|
962
|
+
this.auth.reportTransientFailure(e);
|
|
963
|
+
this.auth.attachHealthCheck();
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (personalInfo.code !== 0) {
|
|
967
|
+
this.auth.reportLoginCheck(personalInfo.code);
|
|
968
|
+
if (personalInfo.code !== -101) this.auth.attachHealthCheck();
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
let card;
|
|
972
|
+
try {
|
|
973
|
+
card = (await this.api.getUserCardInfo(personalInfo.data.mid.toString(), true)).data;
|
|
820
974
|
} catch (e) {
|
|
821
|
-
this.serverLogger.warn(`[account]
|
|
975
|
+
this.serverLogger.warn(`[account] 获取用户卡片失败: ${e}`);
|
|
976
|
+
}
|
|
977
|
+
this.auth.reportLoggedIn(card);
|
|
978
|
+
this.auth.attachHealthCheck();
|
|
979
|
+
}
|
|
980
|
+
async handleAuthLost() {
|
|
981
|
+
this.auth.reportLoggedOut("authLost");
|
|
982
|
+
const now = Date.now();
|
|
983
|
+
if (now - this.authLostNotifiedAt < 6e4) return;
|
|
984
|
+
this.authLostNotifiedAt = now;
|
|
985
|
+
try {
|
|
986
|
+
await this.push?.sendPrivateMsg("账号登录已失效,请在控制台重新扫码登录");
|
|
987
|
+
} catch (e) {
|
|
988
|
+
this.serverLogger.warn(`[auth] 失效通知私信失败:${e}`);
|
|
822
989
|
}
|
|
823
990
|
}
|
|
824
991
|
async loadInitialSubscriptions() {
|
|
@@ -863,10 +1030,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
863
1030
|
this.serverLogger.info("[login] 触发重置密钥事件");
|
|
864
1031
|
try {
|
|
865
1032
|
await this.storageMgr.cookieStore.resetKey();
|
|
866
|
-
this.
|
|
867
|
-
status: _bilibili_notify_api.BiliLoginStatus.NOT_LOGIN,
|
|
868
|
-
msg: "密钥已重置,cookie 已清除,请重新扫码登录"
|
|
869
|
-
});
|
|
1033
|
+
this.auth.reportLoggedOut("keyReset");
|
|
870
1034
|
} catch (e) {
|
|
871
1035
|
this.serverLogger.error(`[login] 重置密钥失败:${e}`);
|
|
872
1036
|
}
|
|
@@ -908,10 +1072,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
908
1072
|
return;
|
|
909
1073
|
}
|
|
910
1074
|
if (qrContent.code !== 0) {
|
|
911
|
-
this.
|
|
912
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
913
|
-
msg: "获取二维码失败,请重试"
|
|
914
|
-
});
|
|
1075
|
+
this.auth.reportQrFailure("qrFetchFailed");
|
|
915
1076
|
return;
|
|
916
1077
|
}
|
|
917
1078
|
qrcode.default.toBuffer(qrContent.data.url, {
|
|
@@ -925,17 +1086,10 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
925
1086
|
}, (err, buffer) => {
|
|
926
1087
|
if (err) {
|
|
927
1088
|
this.serverLogger.error(`[login] 生成二维码失败:${err}`);
|
|
928
|
-
this.
|
|
929
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
930
|
-
msg: "生成二维码失败"
|
|
931
|
-
});
|
|
1089
|
+
this.auth.reportQrFailure("qrRenderFailed");
|
|
932
1090
|
return;
|
|
933
1091
|
}
|
|
934
|
-
this.
|
|
935
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_QR,
|
|
936
|
-
msg: "",
|
|
937
|
-
data: `data:image/png;base64,${Buffer.from(buffer).toString("base64")}`
|
|
938
|
-
});
|
|
1092
|
+
this.auth.reportQrReady(`data:image/png;base64,${Buffer.from(buffer).toString("base64")}`);
|
|
939
1093
|
});
|
|
940
1094
|
this.clearLoginTimer();
|
|
941
1095
|
let polling = true;
|
|
@@ -951,10 +1105,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
951
1105
|
this.selfCtx.setTimeout(() => {
|
|
952
1106
|
if (!this.loginTimer) return;
|
|
953
1107
|
this.clearLoginTimer();
|
|
954
|
-
this.
|
|
955
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
956
|
-
msg: "二维码已超时(3分钟),请重新登录"
|
|
957
|
-
});
|
|
1108
|
+
this.auth.reportQrFailure("qrExpired");
|
|
958
1109
|
}, 180 * 1e3);
|
|
959
1110
|
}
|
|
960
1111
|
async pollLoginStatus(qrcodeKey) {
|
|
@@ -968,25 +1119,16 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
968
1119
|
}
|
|
969
1120
|
const code = loginContent?.data?.code;
|
|
970
1121
|
if (code === 86101) {
|
|
971
|
-
this.
|
|
972
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGGING_QR,
|
|
973
|
-
msg: "尚未扫码,请扫码"
|
|
974
|
-
});
|
|
1122
|
+
this.auth.reportQrPending("waitScan");
|
|
975
1123
|
return;
|
|
976
1124
|
}
|
|
977
1125
|
if (code === 86090) {
|
|
978
|
-
this.
|
|
979
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGGING_QR,
|
|
980
|
-
msg: "已扫码,但尚未确认,请确认"
|
|
981
|
-
});
|
|
1126
|
+
this.auth.reportQrPending("waitConfirm");
|
|
982
1127
|
return;
|
|
983
1128
|
}
|
|
984
1129
|
if (code === 86038) {
|
|
985
1130
|
this.clearLoginTimer();
|
|
986
|
-
this.
|
|
987
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
988
|
-
msg: "二维码已失效,请重新登录"
|
|
989
|
-
});
|
|
1131
|
+
this.auth.reportQrFailure("qrInvalidated");
|
|
990
1132
|
return;
|
|
991
1133
|
}
|
|
992
1134
|
if (code === 0) {
|
|
@@ -994,10 +1136,7 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
994
1136
|
const cookiesJson = this.api.getCookiesJson();
|
|
995
1137
|
if (!cookiesJson || cookiesJson === "[]") {
|
|
996
1138
|
this.serverLogger.error("[login] 登录成功但未获取到任何 cookie,放弃保存");
|
|
997
|
-
this.
|
|
998
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
999
|
-
msg: "登录成功但未获取到 cookie,请重试"
|
|
1000
|
-
});
|
|
1139
|
+
this.auth.reportQrFailure("noCookieAfterLogin");
|
|
1001
1140
|
return;
|
|
1002
1141
|
}
|
|
1003
1142
|
try {
|
|
@@ -1009,20 +1148,14 @@ var BilibiliNotifyServerManager = class extends koishi.Service {
|
|
|
1009
1148
|
} catch (e) {
|
|
1010
1149
|
this.serverLogger.error(`[login] 保存 cookie 失败:${e}`);
|
|
1011
1150
|
}
|
|
1012
|
-
this.
|
|
1013
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_SUCCESS,
|
|
1014
|
-
msg: "登录成功,正在加载订阅..."
|
|
1015
|
-
});
|
|
1151
|
+
this.auth.reportLoggedIn(void 0, "loginJustSucceeded");
|
|
1016
1152
|
await this.reportAccountInfo();
|
|
1017
1153
|
await this.loadInitialSubscriptions();
|
|
1018
1154
|
return;
|
|
1019
1155
|
}
|
|
1020
1156
|
if (loginContent?.code !== 0) {
|
|
1021
1157
|
this.clearLoginTimer();
|
|
1022
|
-
this.
|
|
1023
|
-
status: _bilibili_notify_api.BiliLoginStatus.LOGIN_FAILED,
|
|
1024
|
-
msg: "登录失败,请重试"
|
|
1025
|
-
});
|
|
1158
|
+
this.auth.reportQrFailure("genericLoginFail");
|
|
1026
1159
|
}
|
|
1027
1160
|
}
|
|
1028
1161
|
async warnMissingPlugins(subs) {
|
package/lib/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BiliDataServer, BilibiliAPI } from "@bilibili-notify/api";
|
|
1
|
+
import { BiliDataServer as BiliDataServer$1, BilibiliAPI } from "@bilibili-notify/api";
|
|
2
2
|
import { BilibiliPush, SubItem, Subscriptions } from "@bilibili-notify/push";
|
|
3
3
|
import { CookieData, StorageManager } from "@bilibili-notify/storage";
|
|
4
4
|
import { Awaitable, Context, Schema, Service } from "koishi";
|
|
@@ -11,6 +11,7 @@ interface BilibiliNotifyConfig {
|
|
|
11
11
|
subs: FlatSubConfigItem[];
|
|
12
12
|
logLevel: number;
|
|
13
13
|
userAgent?: string;
|
|
14
|
+
loginHealthCheckMinutes: number;
|
|
14
15
|
master: {
|
|
15
16
|
enable: boolean;
|
|
16
17
|
platform?: string;
|
|
@@ -21,10 +22,10 @@ interface BilibiliNotifyConfig {
|
|
|
21
22
|
declare const BilibiliNotifyConfigSchema: Schema<BilibiliNotifyConfig>;
|
|
22
23
|
//#endregion
|
|
23
24
|
//#region src/data-server.d.ts
|
|
24
|
-
declare class BilibiliNotifyDataServer extends DataService<BiliDataServer> {
|
|
25
|
+
declare class BilibiliNotifyDataServer extends DataService<BiliDataServer$1> {
|
|
25
26
|
private biliData;
|
|
26
27
|
constructor(ctx: Context);
|
|
27
|
-
get(): Promise<BiliDataServer>;
|
|
28
|
+
get(): Promise<BiliDataServer$1>;
|
|
28
29
|
}
|
|
29
30
|
//#endregion
|
|
30
31
|
//#region src/server-manager.d.ts
|
|
@@ -40,9 +41,13 @@ declare class BilibiliNotifyServerManager extends Service<BilibiliNotifyConfig>
|
|
|
40
41
|
private running;
|
|
41
42
|
storageMgr: StorageManager;
|
|
42
43
|
private currentSubs;
|
|
44
|
+
private auth;
|
|
45
|
+
private authLostNotifiedAt;
|
|
43
46
|
constructor(ctx: Context, config: BilibiliNotifyConfig);
|
|
44
47
|
/** For commands */
|
|
45
48
|
get subManager(): any;
|
|
49
|
+
/** For commands: read the current login snapshot. */
|
|
50
|
+
getAuthSnapshot(): BiliDataServer;
|
|
46
51
|
subList(): string;
|
|
47
52
|
protected start(): Promise<void>;
|
|
48
53
|
protected stop(): Awaitable<void>;
|
|
@@ -97,6 +102,7 @@ declare class BilibiliNotifyServerManager extends Service<BilibiliNotifyConfig>
|
|
|
97
102
|
private isLoggedIn;
|
|
98
103
|
private clearLoginTimer;
|
|
99
104
|
private reportAccountInfo;
|
|
105
|
+
private handleAuthLost;
|
|
100
106
|
private loadInitialSubscriptions;
|
|
101
107
|
private updateSubNotifier;
|
|
102
108
|
private registerConsoleEvents;
|
|
@@ -135,7 +141,9 @@ declare module "koishi" {
|
|
|
135
141
|
"bilibili-notify": BilibiliNotifyServerManager;
|
|
136
142
|
}
|
|
137
143
|
interface Events {
|
|
138
|
-
"bilibili-notify/login-status-report"(data: BiliDataServer): void;
|
|
144
|
+
"bilibili-notify/login-status-report"(data: BiliDataServer$1): void;
|
|
145
|
+
"bilibili-notify/auth-lost"(): void;
|
|
146
|
+
"bilibili-notify/auth-restored"(): void;
|
|
139
147
|
"bilibili-notify/advanced-sub"(subs: Subscriptions): void;
|
|
140
148
|
"bilibili-notify/ready-to-receive"(): void;
|
|
141
149
|
"bilibili-notify/cookies-refreshed"(data: CookieData): void;
|
package/lib/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DataService } from "@koishijs/plugin-console";
|
|
2
2
|
import { Awaitable, Context, Schema, Service } from "koishi";
|
|
3
|
-
import { BiliDataServer, BilibiliAPI } from "@bilibili-notify/api";
|
|
3
|
+
import { BiliDataServer as BiliDataServer$1, BilibiliAPI } from "@bilibili-notify/api";
|
|
4
4
|
import { BilibiliPush, SubItem, Subscriptions } from "@bilibili-notify/push";
|
|
5
5
|
import { CookieData, StorageManager } from "@bilibili-notify/storage";
|
|
6
6
|
import { FlatSubConfigItem } from "@bilibili-notify/subscription";
|
|
@@ -11,6 +11,7 @@ interface BilibiliNotifyConfig {
|
|
|
11
11
|
subs: FlatSubConfigItem[];
|
|
12
12
|
logLevel: number;
|
|
13
13
|
userAgent?: string;
|
|
14
|
+
loginHealthCheckMinutes: number;
|
|
14
15
|
master: {
|
|
15
16
|
enable: boolean;
|
|
16
17
|
platform?: string;
|
|
@@ -21,10 +22,10 @@ interface BilibiliNotifyConfig {
|
|
|
21
22
|
declare const BilibiliNotifyConfigSchema: Schema<BilibiliNotifyConfig>;
|
|
22
23
|
//#endregion
|
|
23
24
|
//#region src/data-server.d.ts
|
|
24
|
-
declare class BilibiliNotifyDataServer extends DataService<BiliDataServer> {
|
|
25
|
+
declare class BilibiliNotifyDataServer extends DataService<BiliDataServer$1> {
|
|
25
26
|
private biliData;
|
|
26
27
|
constructor(ctx: Context);
|
|
27
|
-
get(): Promise<BiliDataServer>;
|
|
28
|
+
get(): Promise<BiliDataServer$1>;
|
|
28
29
|
}
|
|
29
30
|
//#endregion
|
|
30
31
|
//#region src/server-manager.d.ts
|
|
@@ -40,9 +41,13 @@ declare class BilibiliNotifyServerManager extends Service<BilibiliNotifyConfig>
|
|
|
40
41
|
private running;
|
|
41
42
|
storageMgr: StorageManager;
|
|
42
43
|
private currentSubs;
|
|
44
|
+
private auth;
|
|
45
|
+
private authLostNotifiedAt;
|
|
43
46
|
constructor(ctx: Context, config: BilibiliNotifyConfig);
|
|
44
47
|
/** For commands */
|
|
45
48
|
get subManager(): any;
|
|
49
|
+
/** For commands: read the current login snapshot. */
|
|
50
|
+
getAuthSnapshot(): BiliDataServer;
|
|
46
51
|
subList(): string;
|
|
47
52
|
protected start(): Promise<void>;
|
|
48
53
|
protected stop(): Awaitable<void>;
|
|
@@ -97,6 +102,7 @@ declare class BilibiliNotifyServerManager extends Service<BilibiliNotifyConfig>
|
|
|
97
102
|
private isLoggedIn;
|
|
98
103
|
private clearLoginTimer;
|
|
99
104
|
private reportAccountInfo;
|
|
105
|
+
private handleAuthLost;
|
|
100
106
|
private loadInitialSubscriptions;
|
|
101
107
|
private updateSubNotifier;
|
|
102
108
|
private registerConsoleEvents;
|
|
@@ -135,7 +141,9 @@ declare module "koishi" {
|
|
|
135
141
|
"bilibili-notify": BilibiliNotifyServerManager;
|
|
136
142
|
}
|
|
137
143
|
interface Events {
|
|
138
|
-
"bilibili-notify/login-status-report"(data: BiliDataServer): void;
|
|
144
|
+
"bilibili-notify/login-status-report"(data: BiliDataServer$1): void;
|
|
145
|
+
"bilibili-notify/auth-lost"(): void;
|
|
146
|
+
"bilibili-notify/auth-restored"(): void;
|
|
139
147
|
"bilibili-notify/advanced-sub"(subs: Subscriptions): void;
|
|
140
148
|
"bilibili-notify/ready-to-receive"(): void;
|
|
141
149
|
"bilibili-notify/cookies-refreshed"(data: CookieData): void;
|
package/lib/index.mjs
CHANGED
|
@@ -34,6 +34,7 @@ const BilibiliNotifyConfigSchema = Schema.object({
|
|
|
34
34
|
})).role("table").description("在这里填写主人的订阅信息~UP 昵称、UID、roomid、平台、群号都要填正确,不然女仆会迷路哒 (;>_<)如果多个群聊/频道,请用英文逗号分隔哦~女仆会努力送到每一个地方的!"),
|
|
35
35
|
logLevel: Schema.number().min(1).max(3).step(1).default(1).description("这里可以设置日志等级喔~3 是最详细的调试信息,1 是只显示错误信息。主人可以根据需要选择合适的等级,让女仆更好地为您服务 (๑•̀ㅂ•́)و✧"),
|
|
36
36
|
userAgent: Schema.string().description("这里可以设置请求头的 User-Agent 哦~如果请求出现了 -352 的奇怪错误,主人可以试着在这里换一个看看 (;>_<)"),
|
|
37
|
+
loginHealthCheckMinutes: Schema.number().min(5).max(180).step(1).default(30).description("登录状态周期检测的间隔(分钟)。女仆会按这个频率悄悄帮主人确认账号还在线哦~如果发现失效会立刻汇报呢 (๑•̀ㅂ•́)و✧"),
|
|
37
38
|
master: Schema.intersect([Schema.object({ enable: Schema.boolean().default(false).description("要不要让笨笨女仆开启主人账号功能呢?(>﹏<)如果机器人遭遇了奇怪的小错误,女仆会立刻跑来向主人报告的!不、不过……如果没有私聊权限的话,女仆就联系不到主人了……请不要打开这个开关喔 (;´д`)ゞ") }).description("主人的特别区域……女仆会乖乖侍奉的!(>///<)"), Schema.union([Schema.object({
|
|
38
39
|
enable: Schema.const(true).required(),
|
|
39
40
|
platform: Schema.union([
|
|
@@ -387,6 +388,10 @@ function biliCommands() {
|
|
|
387
388
|
//#region src/commands/status.ts
|
|
388
389
|
function statusCommands() {
|
|
389
390
|
const statusCom = this.ctx.command("status", "插件状态相关指令", { permissions: ["authority:5"] });
|
|
391
|
+
statusCom.subcommand(".auth", "查看登录状态").usage("查看登录状态").example("status auth").action(() => {
|
|
392
|
+
const snap = this.getAuthSnapshot();
|
|
393
|
+
return `登录状态:${BiliLoginStatus[snap.status] ?? `unknown(${snap.status})`}\n信息:${snap.msg || "(无)"}`;
|
|
394
|
+
});
|
|
390
395
|
statusCom.subcommand(".dyn", "查看动态监测运行状态").usage("查看动态监测运行状态").example("status dyn").action(() => {
|
|
391
396
|
if (this.ctx.get("bilibili-notify-dynamic")) return "动态监测正在运行";
|
|
392
397
|
return "动态插件未运行(请检查是否已安装并启用 koishi-plugin-bilibili-notify-dynamic)";
|
|
@@ -431,6 +436,136 @@ function sysCommands() {
|
|
|
431
436
|
});
|
|
432
437
|
}
|
|
433
438
|
//#endregion
|
|
439
|
+
//#region src/login-status.ts
|
|
440
|
+
const MESSAGES = {
|
|
441
|
+
loading: "正在加载登录信息...",
|
|
442
|
+
notLogin: "账号未登录,请点击「扫码登录」",
|
|
443
|
+
keyReset: "密钥已重置,cookie 已清除,请重新扫码登录",
|
|
444
|
+
authLost: "账号登录已失效,请在控制台重新扫码登录",
|
|
445
|
+
loggedIn: "已登录",
|
|
446
|
+
loginJustSucceeded: "登录成功,正在加载订阅...",
|
|
447
|
+
fetchAccountFailed: "账号已登录,但获取个人信息失败,请检查",
|
|
448
|
+
waitScan: "尚未扫码,请扫码",
|
|
449
|
+
waitConfirm: "已扫码,但尚未确认,请确认",
|
|
450
|
+
qrFetchFailed: "获取二维码失败,请重试",
|
|
451
|
+
qrRenderFailed: "生成二维码失败",
|
|
452
|
+
qrExpired: "二维码已超时(3分钟),请重新登录",
|
|
453
|
+
qrInvalidated: "二维码已失效,请重新登录",
|
|
454
|
+
noCookieAfterLogin: "登录成功但未获取到 cookie,请重试",
|
|
455
|
+
genericLoginFail: "登录失败,请重试"
|
|
456
|
+
};
|
|
457
|
+
/** 类型守卫:snapshot.data 是否长得像 UserCardInfo。 */
|
|
458
|
+
function looksLikeCardData(data) {
|
|
459
|
+
return typeof data === "object" && data !== null && "card" in data;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* 集中管理登录态:所有变更都经过这里,再以 `bilibili-notify/login-status-report`
|
|
463
|
+
* 推到前端。心跳定时器在登录态下定期 probe,发现失效会同时广播
|
|
464
|
+
* `bilibili-notify/auth-lost`,恢复时广播 `bilibili-notify/auth-restored`。
|
|
465
|
+
*/
|
|
466
|
+
var LoginStatusController = class {
|
|
467
|
+
snapshot = {
|
|
468
|
+
status: BiliLoginStatus.LOADING_LOGIN_INFO,
|
|
469
|
+
msg: MESSAGES.loading
|
|
470
|
+
};
|
|
471
|
+
healthTimer;
|
|
472
|
+
/**
|
|
473
|
+
* 标记"曾从已登录态掉线",下一次成功登录时翻转为已登录后才发 auth-restored。
|
|
474
|
+
* 之所以不再用"上一帧 status === NOT_LOGIN"判断:失效后用户走扫码流程,会经过
|
|
475
|
+
* LOGIN_QR / LOGGING_QR 等中间态,直接基于上一帧会漏掉这条恢复路径。
|
|
476
|
+
*/
|
|
477
|
+
needsRestore = false;
|
|
478
|
+
constructor(ctx, options) {
|
|
479
|
+
this.ctx = ctx;
|
|
480
|
+
this.options = options;
|
|
481
|
+
}
|
|
482
|
+
current() {
|
|
483
|
+
return { ...this.snapshot };
|
|
484
|
+
}
|
|
485
|
+
attachHealthCheck() {
|
|
486
|
+
this.detachHealthCheck();
|
|
487
|
+
if (this.options.healthCheckMs <= 0) return;
|
|
488
|
+
this.healthTimer = this.ctx.setInterval(() => void this.runHealthCheck(), this.options.healthCheckMs);
|
|
489
|
+
}
|
|
490
|
+
detachHealthCheck() {
|
|
491
|
+
this.healthTimer?.();
|
|
492
|
+
this.healthTimer = void 0;
|
|
493
|
+
}
|
|
494
|
+
reportLoggedIn(card, reasonKey = "loggedIn") {
|
|
495
|
+
const wasLoggedIn = this.snapshot.status === BiliLoginStatus.LOGGED_IN;
|
|
496
|
+
const fallback = looksLikeCardData(this.snapshot.data) ? this.snapshot.data : void 0;
|
|
497
|
+
this.transition({
|
|
498
|
+
status: BiliLoginStatus.LOGGED_IN,
|
|
499
|
+
msg: MESSAGES[reasonKey],
|
|
500
|
+
data: card ?? fallback
|
|
501
|
+
});
|
|
502
|
+
if (!wasLoggedIn && this.needsRestore) {
|
|
503
|
+
this.needsRestore = false;
|
|
504
|
+
this.ctx.emit("bilibili-notify/auth-restored");
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
reportLoggedOut(reasonKey = "notLogin") {
|
|
508
|
+
const wasLoggedIn = this.snapshot.status === BiliLoginStatus.LOGGED_IN;
|
|
509
|
+
this.transition({
|
|
510
|
+
status: BiliLoginStatus.NOT_LOGIN,
|
|
511
|
+
msg: MESSAGES[reasonKey]
|
|
512
|
+
});
|
|
513
|
+
if (wasLoggedIn) {
|
|
514
|
+
this.needsRestore = true;
|
|
515
|
+
this.ctx.emit("bilibili-notify/auth-lost");
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/** Dispatch on `getMyselfInfo` result code. */
|
|
519
|
+
reportLoginCheck(code, card) {
|
|
520
|
+
if (code === 0) this.reportLoggedIn(card);
|
|
521
|
+
else if (code === -101) this.reportLoggedOut("authLost");
|
|
522
|
+
else this.reportTransientFailure(`code=${code}`);
|
|
523
|
+
}
|
|
524
|
+
/** Keep current status, only refresh msg. Logs at warn level. */
|
|
525
|
+
reportTransientFailure(detail) {
|
|
526
|
+
this.options.logger.warn(`[auth] 瞬时失败:${detail}`);
|
|
527
|
+
if (this.snapshot.status !== BiliLoginStatus.LOGGED_IN) return;
|
|
528
|
+
this.transition({
|
|
529
|
+
...this.snapshot,
|
|
530
|
+
msg: MESSAGES.fetchAccountFailed
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
reportQrReady(base64) {
|
|
534
|
+
this.transition({
|
|
535
|
+
status: BiliLoginStatus.LOGIN_QR,
|
|
536
|
+
msg: "",
|
|
537
|
+
data: base64
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
reportQrPending(reasonKey) {
|
|
541
|
+
this.transition({
|
|
542
|
+
status: BiliLoginStatus.LOGGING_QR,
|
|
543
|
+
msg: MESSAGES[reasonKey]
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
reportQrFailure(reasonKey) {
|
|
547
|
+
this.transition({
|
|
548
|
+
status: BiliLoginStatus.LOGIN_FAILED,
|
|
549
|
+
msg: MESSAGES[reasonKey]
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/** Emit only when (status, msg, data) changes. */
|
|
553
|
+
transition(next) {
|
|
554
|
+
if (this.snapshot.status === next.status && this.snapshot.msg === next.msg && this.snapshot.data === next.data) return;
|
|
555
|
+
this.snapshot = next;
|
|
556
|
+
this.ctx.emit("bilibili-notify/login-status-report", next);
|
|
557
|
+
}
|
|
558
|
+
async runHealthCheck() {
|
|
559
|
+
if (this.snapshot.status === BiliLoginStatus.LOGIN_QR || this.snapshot.status === BiliLoginStatus.LOGGING_QR || this.snapshot.status === BiliLoginStatus.NOT_LOGIN) return;
|
|
560
|
+
try {
|
|
561
|
+
const res = await this.options.probe();
|
|
562
|
+
this.reportLoginCheck(res.code);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
this.options.logger.warn(`[auth] 心跳异常(保持当前状态):${e}`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
//#endregion
|
|
434
569
|
//#region src/server-manager.ts
|
|
435
570
|
const SERVICE_NAME = "bilibili-notify";
|
|
436
571
|
const LIVE_MASTER_KEYS = [
|
|
@@ -482,6 +617,8 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
482
617
|
running = false;
|
|
483
618
|
storageMgr;
|
|
484
619
|
currentSubs = null;
|
|
620
|
+
auth;
|
|
621
|
+
authLostNotifiedAt = 0;
|
|
485
622
|
constructor(ctx, config) {
|
|
486
623
|
super(ctx, SERVICE_NAME);
|
|
487
624
|
this.selfCtx = ctx;
|
|
@@ -492,6 +629,10 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
492
629
|
get subManager() {
|
|
493
630
|
return this.subMgr?.subManager ?? /* @__PURE__ */ new Map();
|
|
494
631
|
}
|
|
632
|
+
/** For commands: read the current login snapshot. */
|
|
633
|
+
getAuthSnapshot() {
|
|
634
|
+
return this.auth.current();
|
|
635
|
+
}
|
|
495
636
|
subList() {
|
|
496
637
|
const map = this.subManager;
|
|
497
638
|
if (!map.size) return "没有订阅任何UP";
|
|
@@ -506,6 +647,14 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
506
647
|
this.serverLogger.info("[start] 正在启动中...");
|
|
507
648
|
this.storageMgr = new StorageManager(this.ctx.baseDir, this.ctx);
|
|
508
649
|
await this.storageMgr.init();
|
|
650
|
+
this.auth = new LoginStatusController(this.selfCtx, {
|
|
651
|
+
healthCheckMs: this.config.loginHealthCheckMinutes * 6e4,
|
|
652
|
+
logger: this.serverLogger,
|
|
653
|
+
probe: () => {
|
|
654
|
+
if (!this.api) throw new Error("api not initialized");
|
|
655
|
+
return this.api.getMyselfInfo();
|
|
656
|
+
}
|
|
657
|
+
});
|
|
509
658
|
this.ctx.on("bilibili-notify/cookies-refreshed", async (data) => {
|
|
510
659
|
try {
|
|
511
660
|
await this.storageMgr.cookieStore.save(data);
|
|
@@ -681,8 +830,13 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
681
830
|
this.api = new BilibiliAPI(this.selfCtx, {
|
|
682
831
|
logLevel: this.config.logLevel,
|
|
683
832
|
userAgent: this.config.userAgent
|
|
684
|
-
},
|
|
685
|
-
|
|
833
|
+
}, {
|
|
834
|
+
onCookiesRefreshed: (data) => {
|
|
835
|
+
this.selfCtx.emit("bilibili-notify/cookies-refreshed", data);
|
|
836
|
+
},
|
|
837
|
+
onAuthLost: () => {
|
|
838
|
+
this.handleAuthLost();
|
|
839
|
+
}
|
|
686
840
|
});
|
|
687
841
|
this.push = new BilibiliPush(this.selfCtx, {
|
|
688
842
|
logLevel: this.config.logLevel,
|
|
@@ -701,10 +855,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
701
855
|
this.serverLogger.debug(`[cookie] Cookie 加载完成,登录状态:${this.isLoggedIn() ? "已登录" : "未登录"}`);
|
|
702
856
|
if (!this.isLoggedIn()) {
|
|
703
857
|
this.serverLogger.info("[login] 账号未登录,请在控制台扫码登录");
|
|
704
|
-
this.
|
|
705
|
-
status: BiliLoginStatus.NOT_LOGIN,
|
|
706
|
-
msg: "账号未登录,请点击「扫码登录」"
|
|
707
|
-
});
|
|
858
|
+
this.auth.reportLoggedOut("notLogin");
|
|
708
859
|
return true;
|
|
709
860
|
}
|
|
710
861
|
await this.reportAccountInfo();
|
|
@@ -720,6 +871,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
720
871
|
this.serverLogger.debug("[stop] 正在清理插件资源...");
|
|
721
872
|
this.running = false;
|
|
722
873
|
this.clearLoginTimer();
|
|
874
|
+
this.auth?.detachHealthCheck();
|
|
723
875
|
if (this.subNotifier) {
|
|
724
876
|
this.subNotifier.dispose();
|
|
725
877
|
this.subNotifier = void 0;
|
|
@@ -782,23 +934,38 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
782
934
|
}
|
|
783
935
|
async reportAccountInfo() {
|
|
784
936
|
if (!this.api) return;
|
|
937
|
+
let personalInfo;
|
|
785
938
|
try {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
this.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
939
|
+
personalInfo = await this.api.getMyselfInfo();
|
|
940
|
+
} catch (e) {
|
|
941
|
+
this.serverLogger.warn(`[account] 获取个人信息异常: ${e}`);
|
|
942
|
+
this.auth.reportTransientFailure(e);
|
|
943
|
+
this.auth.attachHealthCheck();
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (personalInfo.code !== 0) {
|
|
947
|
+
this.auth.reportLoginCheck(personalInfo.code);
|
|
948
|
+
if (personalInfo.code !== -101) this.auth.attachHealthCheck();
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
let card;
|
|
952
|
+
try {
|
|
953
|
+
card = (await this.api.getUserCardInfo(personalInfo.data.mid.toString(), true)).data;
|
|
800
954
|
} catch (e) {
|
|
801
|
-
this.serverLogger.warn(`[account]
|
|
955
|
+
this.serverLogger.warn(`[account] 获取用户卡片失败: ${e}`);
|
|
956
|
+
}
|
|
957
|
+
this.auth.reportLoggedIn(card);
|
|
958
|
+
this.auth.attachHealthCheck();
|
|
959
|
+
}
|
|
960
|
+
async handleAuthLost() {
|
|
961
|
+
this.auth.reportLoggedOut("authLost");
|
|
962
|
+
const now = Date.now();
|
|
963
|
+
if (now - this.authLostNotifiedAt < 6e4) return;
|
|
964
|
+
this.authLostNotifiedAt = now;
|
|
965
|
+
try {
|
|
966
|
+
await this.push?.sendPrivateMsg("账号登录已失效,请在控制台重新扫码登录");
|
|
967
|
+
} catch (e) {
|
|
968
|
+
this.serverLogger.warn(`[auth] 失效通知私信失败:${e}`);
|
|
802
969
|
}
|
|
803
970
|
}
|
|
804
971
|
async loadInitialSubscriptions() {
|
|
@@ -843,10 +1010,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
843
1010
|
this.serverLogger.info("[login] 触发重置密钥事件");
|
|
844
1011
|
try {
|
|
845
1012
|
await this.storageMgr.cookieStore.resetKey();
|
|
846
|
-
this.
|
|
847
|
-
status: BiliLoginStatus.NOT_LOGIN,
|
|
848
|
-
msg: "密钥已重置,cookie 已清除,请重新扫码登录"
|
|
849
|
-
});
|
|
1013
|
+
this.auth.reportLoggedOut("keyReset");
|
|
850
1014
|
} catch (e) {
|
|
851
1015
|
this.serverLogger.error(`[login] 重置密钥失败:${e}`);
|
|
852
1016
|
}
|
|
@@ -888,10 +1052,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
888
1052
|
return;
|
|
889
1053
|
}
|
|
890
1054
|
if (qrContent.code !== 0) {
|
|
891
|
-
this.
|
|
892
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
893
|
-
msg: "获取二维码失败,请重试"
|
|
894
|
-
});
|
|
1055
|
+
this.auth.reportQrFailure("qrFetchFailed");
|
|
895
1056
|
return;
|
|
896
1057
|
}
|
|
897
1058
|
QRCode.toBuffer(qrContent.data.url, {
|
|
@@ -905,17 +1066,10 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
905
1066
|
}, (err, buffer) => {
|
|
906
1067
|
if (err) {
|
|
907
1068
|
this.serverLogger.error(`[login] 生成二维码失败:${err}`);
|
|
908
|
-
this.
|
|
909
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
910
|
-
msg: "生成二维码失败"
|
|
911
|
-
});
|
|
1069
|
+
this.auth.reportQrFailure("qrRenderFailed");
|
|
912
1070
|
return;
|
|
913
1071
|
}
|
|
914
|
-
this.
|
|
915
|
-
status: BiliLoginStatus.LOGIN_QR,
|
|
916
|
-
msg: "",
|
|
917
|
-
data: `data:image/png;base64,${Buffer.from(buffer).toString("base64")}`
|
|
918
|
-
});
|
|
1072
|
+
this.auth.reportQrReady(`data:image/png;base64,${Buffer.from(buffer).toString("base64")}`);
|
|
919
1073
|
});
|
|
920
1074
|
this.clearLoginTimer();
|
|
921
1075
|
let polling = true;
|
|
@@ -931,10 +1085,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
931
1085
|
this.selfCtx.setTimeout(() => {
|
|
932
1086
|
if (!this.loginTimer) return;
|
|
933
1087
|
this.clearLoginTimer();
|
|
934
|
-
this.
|
|
935
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
936
|
-
msg: "二维码已超时(3分钟),请重新登录"
|
|
937
|
-
});
|
|
1088
|
+
this.auth.reportQrFailure("qrExpired");
|
|
938
1089
|
}, 180 * 1e3);
|
|
939
1090
|
}
|
|
940
1091
|
async pollLoginStatus(qrcodeKey) {
|
|
@@ -948,25 +1099,16 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
948
1099
|
}
|
|
949
1100
|
const code = loginContent?.data?.code;
|
|
950
1101
|
if (code === 86101) {
|
|
951
|
-
this.
|
|
952
|
-
status: BiliLoginStatus.LOGGING_QR,
|
|
953
|
-
msg: "尚未扫码,请扫码"
|
|
954
|
-
});
|
|
1102
|
+
this.auth.reportQrPending("waitScan");
|
|
955
1103
|
return;
|
|
956
1104
|
}
|
|
957
1105
|
if (code === 86090) {
|
|
958
|
-
this.
|
|
959
|
-
status: BiliLoginStatus.LOGGING_QR,
|
|
960
|
-
msg: "已扫码,但尚未确认,请确认"
|
|
961
|
-
});
|
|
1106
|
+
this.auth.reportQrPending("waitConfirm");
|
|
962
1107
|
return;
|
|
963
1108
|
}
|
|
964
1109
|
if (code === 86038) {
|
|
965
1110
|
this.clearLoginTimer();
|
|
966
|
-
this.
|
|
967
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
968
|
-
msg: "二维码已失效,请重新登录"
|
|
969
|
-
});
|
|
1111
|
+
this.auth.reportQrFailure("qrInvalidated");
|
|
970
1112
|
return;
|
|
971
1113
|
}
|
|
972
1114
|
if (code === 0) {
|
|
@@ -974,10 +1116,7 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
974
1116
|
const cookiesJson = this.api.getCookiesJson();
|
|
975
1117
|
if (!cookiesJson || cookiesJson === "[]") {
|
|
976
1118
|
this.serverLogger.error("[login] 登录成功但未获取到任何 cookie,放弃保存");
|
|
977
|
-
this.
|
|
978
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
979
|
-
msg: "登录成功但未获取到 cookie,请重试"
|
|
980
|
-
});
|
|
1119
|
+
this.auth.reportQrFailure("noCookieAfterLogin");
|
|
981
1120
|
return;
|
|
982
1121
|
}
|
|
983
1122
|
try {
|
|
@@ -989,20 +1128,14 @@ var BilibiliNotifyServerManager = class extends Service {
|
|
|
989
1128
|
} catch (e) {
|
|
990
1129
|
this.serverLogger.error(`[login] 保存 cookie 失败:${e}`);
|
|
991
1130
|
}
|
|
992
|
-
this.
|
|
993
|
-
status: BiliLoginStatus.LOGIN_SUCCESS,
|
|
994
|
-
msg: "登录成功,正在加载订阅..."
|
|
995
|
-
});
|
|
1131
|
+
this.auth.reportLoggedIn(void 0, "loginJustSucceeded");
|
|
996
1132
|
await this.reportAccountInfo();
|
|
997
1133
|
await this.loadInitialSubscriptions();
|
|
998
1134
|
return;
|
|
999
1135
|
}
|
|
1000
1136
|
if (loginContent?.code !== 0) {
|
|
1001
1137
|
this.clearLoginTimer();
|
|
1002
|
-
this.
|
|
1003
|
-
status: BiliLoginStatus.LOGIN_FAILED,
|
|
1004
|
-
msg: "登录失败,请重试"
|
|
1005
|
-
});
|
|
1138
|
+
this.auth.reportQrFailure("genericLoginFail");
|
|
1006
1139
|
}
|
|
1007
1140
|
}
|
|
1008
1141
|
async warnMissingPlugins(subs) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-bilibili-notify",
|
|
3
3
|
"description": "Bilibili 动态推送、直播通知 Koishi 插件",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/Akokk0/bilibili-notify"
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"typecheck": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@bilibili-notify/api": "^0.0
|
|
43
|
-
"@bilibili-notify/internal": "^0.0.
|
|
42
|
+
"@bilibili-notify/api": "^0.1.0",
|
|
43
|
+
"@bilibili-notify/internal": "^0.0.3",
|
|
44
44
|
"@bilibili-notify/push": "^1.0.2",
|
|
45
45
|
"@bilibili-notify/storage": "^0.0.2",
|
|
46
|
-
"@bilibili-notify/subscription": "^1.0.
|
|
46
|
+
"@bilibili-notify/subscription": "^1.0.3",
|
|
47
47
|
"qrcode": "^1.5.4"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|