koishi-plugin-kkk 2.0.0 → 2.0.1-beta.1

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # 更新日志
2
2
 
3
+ ## 2.0.1-beta.1(预览版)
4
+
5
+ > 这是一个**预览版**(npm 上的 `beta` 标签),装着还没正式发布的一批改动。
6
+ > 正式版仍请用 `latest`(当前 **2.0.0**)。预览版建议先在小范围群里试,遇到问题把日志发我。
7
+ >
8
+ > 这一版只动了一处:把「短时间内不重复解析」从写死的 20 秒变成**可开关 + 可自定义分钟数**。
9
+
10
+ ### 新增
11
+ - **通用 →「短时间不重复解析」**(默认开启):同一条链接在一段时间内只解析一次。
12
+ QQ 的指令按钮是「发一条消息 + 再发一个交互事件」,用户连点、客户端重发也会把同一条链接投递两遍,
13
+ 跑两遍就是两次「开始解析」、两次下载、两次发送(第二次还常因为缓存已被清理而失败)。
14
+ 去重键包含会话、作品 ID、画质与弹幕开关 —— 换画质、换作品、换群都不会被误伤。
15
+ 关掉这个开关后**每条消息都会解析**,需要反复调试同一条链接时可以临时关掉。
16
+ - **通用 →「重复解析间隔(分钟)」**(默认 1,可填 1 ~ 60):上面那个开关打开时才生效,
17
+ 用来决定「多长时间内算重复」;开关关掉时这一项会变灰不可改。填得越大越省事,
18
+ 但也意味着这段时间里你手动再发一次同一条链接会被忽略(想立刻重解析就把开关关掉)。
19
+ 填歪了会自动兜底:超出范围夹到最近的边界(填 0 → 1 分钟,填 90 → 60 分钟),非数字按默认 1 分钟。
20
+ - 去重覆盖面从「抖音 / B站」扩到 **快手 / 小红书**:这两条链路以前完全没有去重,
21
+ 同一条链接被重复投递(连点、客户端重发)会跑两遍;现在四个平台共用同一把锁、同一个开关。
22
+
3
23
  ## 2.0.0
4
24
 
5
25
  > 这是 Koishi 移植版从 **1.0.0 到 2.0.0** 的一次总更新(把此前 `1.2.0-beta.1` 的全部内容也并了进来)。
@@ -44,4 +44,4 @@ Please change the parent <Route path="${e}"> to <Route path="${e===`/`?`*`:`${e}
44
44
  style="stroke: #88f; stroke-width: 2px; fill: none; stroke-opacity: 0.5; marker-end: url(#markerArrow);"
45
45
  ></path>
46
46
  </svg>
47
- </div>`),e.hasArrows=!0}format_textdiff(e,t){e.out(`<div class="jsondiffpatch-value">`),this.formatTextDiffString(e,t[0]),e.out(`</div>`)}};function sL(e){if(typeof e==`number`)return e;let t=String(e);for(let e of[[/&/g,`&amp;`],[/</g,`&lt;`],[/>/g,`&gt;`],[/'/g,`&apos;`],[/"/g,`&quot;`]])t=t.replace(e[0],e[1]);return t}var cL=function(e){let t=e||document,n=({textContent:e,innerText:t})=>e||t,r=(e,t,n)=>{let r=e.querySelectorAll(t);for(let e=0,t=r.length;e<t;e++)n(r[e])},i=({children:e},t)=>{for(let n=0,r=e.length;n<r;n++){let r=e[n];r&&t(r,n)}};r(t,`.jsondiffpatch-arrow`,({parentNode:e,children:t,style:r})=>{let a=e,o=t[0],s=o.children[1];o.style.display=`none`;let c=a.querySelector(`.jsondiffpatch-moved-destination`);if(!(c instanceof HTMLElement))return;let l=n(c),u=a.parentNode;if(!u)return;let d;if(i(u,e=>{e.getAttribute(`data-key`)===l&&(d=e)}),d)try{let e=d.offsetTop-a.offsetTop;o.setAttribute(`height`,`${Math.abs(e)+6}`),r.top=`${-8+(e>0?0:e)}px`;let t=e>0?`M30,0 Q-10,${Math.round(e/2)} 26,${e-4}`:`M30,${-e} Q-10,${Math.round(-e/2)} 26,4`;s.setAttribute(`d`,t),o.style.display=``}catch(e){console.debug(`[jsondiffpatch] error adjusting arrows: ${e}`)}})},lL=(e,t,n)=>{let r=t||document.body,i=`jsondiffpatch-unchanged-`,a={showing:`${i}showing`,hiding:`${i}hiding`,visible:`${i}visible`,hidden:`${i}hidden`},o=r.classList;if(!o)return;if(!n){o.remove(a.showing),o.remove(a.hiding),o.remove(a.visible),o.remove(a.hidden),e===!1&&o.add(a.hidden);return}e===!1?(o.remove(a.showing),o.add(a.visible),setTimeout(()=>{o.add(a.hiding)},10)):(o.remove(a.hiding),o.add(a.showing),o.remove(a.hidden));let s=setInterval(()=>{cL(r)},100);setTimeout(()=>{o.remove(a.showing),o.remove(a.hiding),e===!1?(o.add(a.hidden),o.remove(a.visible)):(o.add(a.visible),o.remove(a.hidden)),setTimeout(()=>{o.remove(a.visible),clearInterval(s)},n+400)},n)},uL=(e,t)=>lL(!1,e,t),dL;function fL(e,t){return dL||=new oL,dL.format(e,t)}var pL=e=>e.join(`.`),mL=e=>!!(e&&typeof e==`object`),Q=(e,t,n)=>e?t.reduce((e,t)=>{if(mL(e))return e[t]},e)??n:n,hL=(e,t,n)=>{let r=structuredClone(e),i=r;for(let e=0;e<t.length-1;e++){let n=t[e],r=i[n];mL(r)||(i[n]={}),i=i[n]}return i[t[t.length-1]]=n,r},gL=(e,t)=>{let n=Number(e);return Number.isFinite(n)?n:t},_L=(e,t)=>Array.isArray(e)&&e.includes(t),vL=e=>!!(e&&typeof e==`object`&&`description`in e),yL=e=>{if(!e||typeof e!=`object`)return e;let t=structuredClone(e);for(let{path:e,options:n}of[{path:[`bilibili`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`bilibili`,`displayContent`],options:[`cover`,`title`,`author`,`stats`,`desc`]},{path:[`bilibili`,`push`,`parseDynamicTypes`],options:[`DYNAMIC_TYPE_AV`,`DYNAMIC_TYPE_DRAW`,`DYNAMIC_TYPE_ARTICLE`]},{path:[`douyin`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`xiaohongshu`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`kuaishou`,`sendContent`],options:[`info`,`comment`,`video`,`image`]}]){let r=Q(t,e,null);if(!Array.isArray(r))continue;let i=n.filter(e=>r.includes(e)),a=t;for(let t=0;t<e.length-1;t++){let n=e[t];mL(a[n])||(a[n]={}),a=a[n]}a[e[e.length-1]]=i}return t},bL=e=>typeof e==`object`&&!!e,xL=e=>{let t={added:0,modified:0,deleted:0},n=e=>{if(bL(e)){if(Array.isArray(e)){e.length===1?t.added+=1:e.length===2?t.modified+=1:e.length===3&&e[2]===0&&(t.deleted+=1);return}for(let[t,r]of Object.entries(e))t!==`_t`&&n(r)}};return n(e),t},SL=({original:e,current:t,showUnchanged:n=!1})=>{let r=(0,v.useRef)(null),i=(0,v.useMemo)(()=>{if(!(!e||!t))return iL(yL(e),yL(t))},[e,t]),a=(0,v.useMemo)(()=>e?yL(e):void 0,[e]),o=(0,v.useMemo)(()=>{if(i)return fL(i,a)},[i,a]),s=(0,v.useMemo)(()=>xL(i),[i]);return(0,v.useEffect)(()=>{r.current&&(o?(r.current.innerHTML=o,n?lL(!0,r.current):uL(r.current)):r.current.innerHTML=``)},[o,n]),o?(0,U.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,U.jsx)(v_,{size:`sm`,color:`success`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`+ `,s.added,` 新增`]})}),(0,U.jsx)(v_,{size:`sm`,color:`warning`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`~ `,s.modified,` 修改`]})}),(0,U.jsx)(v_,{size:`sm`,color:`danger`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`- `,s.deleted,` 删除`]})})]}),(0,U.jsx)(`div`,{className:`max-h-[60vh] overflow-auto rounded-xl border border-default-200 bg-surface p-4`,children:(0,U.jsx)(`div`,{ref:r,className:`min-w-fit`})})]}):(0,U.jsx)(`div`,{className:`flex flex-col items-center justify-center gap-2 py-10 text-center`,children:(0,U.jsx)(px,{className:`text-sm text-muted`,children:`当前没有检测到配置变更`})})},CL=`变更预览`,wL=`绿色 = 新增/改后的内容,红色 = 删除/改前的内容,灰色 = 没变化的内容。`,TL=({device:e,original:t,current:n,isOpen:r,onOpenChange:i})=>{let[a,o]=(0,v.useState)(!1),s=(0,U.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,U.jsx)(px,{className:`text-xs text-muted`,children:wL}),(0,U.jsx)(ob,{size:`sm`,isSelected:a,onChange:o,"aria-label":`显示未变更字段`,children:(0,U.jsxs)(ob.Content,{children:[(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})}),`显示未变更`]})})]}),(0,U.jsx)(SL,{original:t,current:n,showUnchanged:a})]}),c=(0,U.jsx)(Vg,{slot:`close`,size:`sm`,variant:`secondary`,children:`关闭`});return e===`mobile`?(0,U.jsx)(pv,{children:(0,U.jsx)(pv.Backdrop,{isOpen:r,onOpenChange:i,children:(0,U.jsx)(pv.Content,{placement:`bottom`,children:(0,U.jsxs)(pv.Dialog,{className:`h-[85vh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsx)(pv.Header,{children:(0,U.jsx)(pv.Heading,{children:CL})}),(0,U.jsx)(pv.Body,{children:s}),(0,U.jsx)(pv.Footer,{children:c})]})})})}):(0,U.jsx)(Dx,{children:(0,U.jsx)(Dx.Backdrop,{isOpen:r,onOpenChange:i,children:(0,U.jsx)(Dx.Container,{scroll:`inside`,size:`lg`,children:(0,U.jsxs)(Dx.Dialog,{className:`w-full max-w-4xl`,children:[(0,U.jsx)(Dx.CloseTrigger,{}),(0,U.jsxs)(Dx.Header,{children:[(0,U.jsx)(Dx.Icon,{className:`bg-accent-soft text-accent-soft-foreground`,children:(0,U.jsx)(Lj,{className:`size-5`})}),(0,U.jsx)(Dx.Heading,{children:CL})]}),(0,U.jsx)(Dx.Body,{children:s}),(0,U.jsx)(Dx.Footer,{children:c})]})})})})},EL=e=>!!(e&&typeof e==`object`),$=(e,t,n)=>e?t.reduce((e,t)=>{if(EL(e))return e[t]},e)??n:n,DL=(e,t)=>Array.isArray(e)&&e.includes(t),OL=[{path:[`app`,`priority`],rules:[{condition:e=>$(e,[`app`,`videoTool`],!0),message:`修改此配置项需要先将「默认解析优先级」关闭`}]},{path:[`app`,`multiPageHeight`],rules:[{condition:e=>!$(e,[`app`,`multiPageRender`],!0),message:`修改此配置项需要先将「分页渲染」打开`}]},{path:[`app`,`livePhotoSystem`],rules:[{condition:e=>$(e,[`app`,`livePhotoMode`],`video_and_livephoto`)===`video_only`,message:`修改此配置项需要先将「Live Photo 处理和发送方式」改为非「仅视频」模式`}]},{path:[`amagi`,`APIServerMount`],rules:[{condition:e=>!$(e,[`amagi`,`APIServer`],!1),message:`修改此配置项需要先将「API 服务」打开`}]},{path:[`amagi`,`APIServerPort`],rules:[{condition:e=>$(e,[`amagi`,`APIServerMount`],!0),message:`修改此配置项需要先将「挂载到 Koishi」关闭`}]},{path:[`app`,`qrLoginExternalAddr`],rules:[{condition:e=>$(e,[`app`,`qrLoginAddrType`],`lan`)!==`external`,message:`修改此配置项需要先将「扫码登录地址」改为「外部地址」`}]},{path:[`app`,`videoSendMode`],rules:[{condition:e=>$(e,[`app`,`usegroupfile`],!1),message:`修改此配置项需要先将「群文件上传」关闭`}]},{path:[`app`,`usegroupfile`],rules:[{condition:e=>$(e,[`app`,`videoSendMode`],`file`)===`base64`,message:`修改此配置项需要先将「本地视频发送方式」改为「File 协议」`}]},{path:[`app`,`groupfilevalue`],rules:[{condition:e=>!$(e,[`app`,`usegroupfile`],!1),message:`修改此配置项需要先将「群文件上传」打开`},{condition:e=>$(e,[`app`,`videoSendMode`],`file`)===`base64`,message:`修改此配置项需要先将「本地视频发送方式」改为「File 协议」`}]},{path:[`app`,`filelimit`],rules:[{condition:e=>!$(e,[`app`,`usefilelimit`],!1),message:`修改此配置项需要先将「视频上传拦截」打开`}]},{path:[`app`,`compresstrigger`],rules:[{condition:e=>!$(e,[`app`,`compress`],!1),message:`修改此配置项需要先将「压缩视频」打开`}]},{path:[`app`,`compressvalue`],rules:[{condition:e=>!$(e,[`app`,`compress`],!1),message:`修改此配置项需要先将「压缩视频」打开`}]},{path:[`app`,`downloadMaxSpeed`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`}]},{path:[`app`,`downloadAutoReduce`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`}]},{path:[`app`,`downloadMinSpeed`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`},{condition:e=>!$(e,[`app`,`downloadAutoReduce`],!1),message:`修改此配置项需要先将「断流自动降速」打开`}]},{path:[`amagi`,`proxy`,`protocol`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`host`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`port`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`auth`,`username`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`auth`,`password`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`douyin`,`sendContent`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`numcomment`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`subCommentLimit`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`commentImageCollection`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`liveImageMergeMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`app`,`livePhotoMode`],`video_and_livephoto`)===`livephoto_only`,message:`修改此配置项需要先将「Live Photo 处理和发送方式」改为非「仅实况图」模式`}]},{path:[`douyin`,`videoQuality`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`douyin`,`videoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`douyin`,`videoInfoMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`displayContent`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`douyin`,`videoInfoMode`],`text`)===`image`,message:`修改此配置项需要先将「视频信息返回形式」改为「文本模式」`}]},{path:[`douyin`,`burnDanmaku`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`danmakuArea`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`danmakuFontSize`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`danmakuOpacity`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`verticalMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`videoCodec`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`push`,`permission`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`cron`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`parsedynamic`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`shareType`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`pushVideoQuality`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`pushMaxAutoVideoSize`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>$(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`bilibili`,`sendContent`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`numcomment`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`realCommentCount`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`commentImageCollection`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`videoQuality`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>Number($(e,[`bilibili`,`videoQuality`],0))!==0,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`bilibili`,`videoInfoMode`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`displayContent`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`bilibili`,`videoInfoMode`],`text`)===`image`,message:`修改此配置项需要先将「视频信息返回形式」改为「文本模式」`}]},{path:[`bilibili`,`showDanmakuInVideoInfo`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`bilibili`,`videoInfoMode`],`text`)===`text`,message:`修改此配置项需要先将「视频信息返回形式」改为「图片模式」`}]},{path:[`bilibili`,`burnDanmaku`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`danmakuArea`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`danmakuFontSize`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`danmakuOpacity`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`verticalMode`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`videoCodec`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`push`,`permission`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`cron`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`parsedynamic`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`parseDynamicTypes`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`}]},{path:[`bilibili`,`push`,`pushVideoQuality`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`}]},{path:[`bilibili`,`push`,`pushMaxAutoVideoSize`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`},{condition:e=>Number($(e,[`bilibili`,`push`,`pushVideoQuality`],0))!==0,message:`修改此配置项需要先将「解析视频动态时的画质偏好」改为「自动选择」`}]},{path:[`kuaishou`,`comment`],rules:[{condition:e=>!$(e,[`kuaishou`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`kuaishou`,`numcomment`],rules:[{condition:e=>!$(e,[`kuaishou`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`kuaishou`,`comment`],!1),message:`修改此配置项需要先将「评论解析」打开`}]},{path:[`xiaohongshu`,`sendContent`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`xiaohongshu`,`numcomment`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`xiaohongshu`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`xiaohongshu`,`videoQuality`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`xiaohongshu`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`xiaohongshu`,`videoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]}],kL=e=>e.join(`.`),AL=(e,t)=>{let n=kL(t),r=OL.find(e=>kL(e.path)===n);if(!r)return``;for(let t of r.rules)if(t.condition(e))return t.message;return``},jL=[{label:`信息`,value:`info`},{label:`评论图`,value:`comment`},{label:`视频`,value:`video`},{label:`图片`,value:`image`}],ML=[{label:`封面`,value:`cover`},{label:`标题`,value:`title`},{label:`作者`,value:`author`},{label:`统计`,value:`stats`},{label:`简介`,value:`desc`}],NL=[{label:`自动选择`,value:`adapt`,description:`根据「视频体积上限(MB)」自动选择分辨率进行下载`},{label:`标清 540p`,value:`540p`},{label:`高清 720p`,value:`720p`},{label:`高清 1080p`,value:`1080p`},{label:`超清 2k`,value:`2k`},{label:`超清 4k`,value:`4k`}],PL=[{label:`自动选择`,value:`0`},{label:`240P 极速`,value:`6`},{label:`360P 流畅`,value:`16`},{label:`480P 清晰`,value:`32`,description:`需登录(配置ck)`},{label:`720P 高清`,value:`64`,description:`需登录(配置ck)`},{label:`720P60 高帧率`,value:`74`,description:`需登录(配置ck)`},{label:`1080P 高清`,value:`80`,description:`需登录(配置ck)`},{label:`1080P+ 高码率`,value:`112`,description:`需大会员&视频支持`},{label:`1080P60 高帧率`,value:`116`,description:`需大会员&视频支持`},{label:`4K 超清`,value:`120`,description:`需大会员&视频支持`},{label:`8K 超高清`,value:`127`,description:`需大会员&视频支持`}],FL=[{label:`视频动态`,value:`DYNAMIC_TYPE_AV`},{label:`图文动态`,value:`DYNAMIC_TYPE_DRAW`},{label:`文章动态`,value:`DYNAMIC_TYPE_ARTICLE`}],IL=[{label:`所有人`,value:`all`},{label:`管理员`,value:`admin`},{label:`主人`,value:`master`},{label:`群主`,value:`group.owner`},{label:`群管理员`,value:`group.admin`}],LL=[{label:`H.264`,value:`h264`,description:`兼容性最好,支持几乎所有设备`},{label:`H.265`,value:`h265`,description:`压缩率更高,近几年设备支持良好(推荐)`},{label:`AV1`,value:`av1`,description:`最新编码格式,压缩率最高,但编码较慢`}],RL=[{label:`关闭`,value:`off`,description:`保持原始比例,不做转换`},{label:`智能`,value:`standard`,description:`仅对宽屏比例视频生效`},{label:`强制 9:16`,value:`force`,description:`所有视频统一转为 9:16 竖屏`}],zL=[{label:`1/4 屏`,value:`0.25`,description:`仅顶部区域`},{label:`半屏`,value:`0.5`,description:`上半部分(推荐)`},{label:`3/4 屏`,value:`0.75`,description:`大部分区域`},{label:`全屏`,value:`1`,description:`铺满整个画面`}],BL=[{label:`小号`,value:`small`},{label:`中号`,value:`medium`},{label:`大号`,value:`large`}],VL={enabled:`已开启`,disabled:`已关闭`},HL=[{key:`amagi`,label:`接口库`,description:`请求与 Cookies`},{key:`app`,label:`通用`,description:`运行与交互`},{key:`douyin`,label:`抖音`,description:`解析与推送`},{key:`bilibili`,label:`哔哩哔哩`,description:`解析与推送`},{key:`kuaishou`,label:`快手`,description:`快手解析`},{key:`xiaohongshu`,label:`小红书`,description:`小红书解析`},{key:`qq`,label:`QQ 适配器`,description:`QQ 平台专属`},{key:`pushlist`,label:`推送列表`,description:`订阅 JSON`}],UL=(0,v.lazy)(()=>YS(()=>import(`./CronEditor-CYgFpX-g.js`),__vite__mapDeps([0,1]))),WL=({className:e,disabled:t,...n})=>{let[r,i]=(0,v.useState)(!1),a=r?`隐藏密码`:`显示密码`;return(0,U.jsxs)(`div`,{className:`relative w-full`,children:[(0,U.jsx)(cx,{...n,variant:`secondary`,className:`w-full pr-10 ${e??``}`,type:r?`text`:`password`}),(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":a,className:`absolute right-1 top-1/2 -translate-y-1/2`,isDisabled:t,size:`sm`,type:`button`,variant:`tertiary`,onPress:()=>i(e=>!e),children:r?(0,U.jsx)(Fj,{className:`size-4`,"aria-hidden":`true`}):(0,U.jsx)(Ij,{className:`size-4`,"aria-hidden":`true`})})]})},GL=({config:e,device:t,classes:n,validationErrors:r,updateConfigValue:i})=>{let a=e=>{let n=vL(e)?e:{description:e},r=t===`mobile`?n.mobileContent??n.desktopContent:n.desktopContent;return(0,U.jsxs)(px,{className:`flex items-center gap-2`,children:[(0,U.jsx)(`span`,{children:n.description}),r?(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`查看详细说明`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:`sm`,variant:`tertiary`,children:(0,U.jsx)(Rj,{className:`size-4`,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:t===`mobile`?`bottom`:`top`,children:[(0,U.jsx)(tx.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72`,children:r})]})]}):null,n.extra]})},o=(n,r,i)=>{if(!i)return n;let a=AL(e,r);return a?t===`mobile`?(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{className:`w-full cursor-not-allowed`,children:n}),(0,U.jsx)(gv.Content,{placement:`bottom`,children:(0,U.jsxs)(gv.Dialog,{children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72 text-sm`,children:a})]})})]}):(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{className:`w-full cursor-not-allowed`,children:n}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72`,children:a})]})]}):n},s=(t,n,r,a)=>{let o=Q(e,t,[]),s=r?Array.from(new Set([...o,n])):o.filter(e=>e!==n);if(a&&r){let e=a.find(e=>e.includes(n));if(e){let t=e.filter(e=>e!==n);s=s.filter(e=>!t.includes(e))}}i(t,s)};return{renderSwitch:(t,n,r,s=!1)=>{let c=Q(e,t,!1),l=(0,U.jsxs)(ob,{isDisabled:s,isSelected:c,onChange:e=>i(t,e),children:[(0,U.jsxs)(ob.Content,{children:[(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})}),(0,U.jsx)(`span`,{className:`font-semibold`,children:n})]}),a(r||(c?VL.enabled:VL.disabled))]});return o(l,t,s)},renderTextField:(t,n,s,c)=>{let l=c?.type||`text`,u=String(Q(e,t,l===`number`?c?.fallback??0:``)),d=r[pL(t)],f=c?.disabled??!1,p=(0,U.jsxs)(lx,{fullWidth:!0,isInvalid:!!d,isDisabled:f,name:t.join(`.`),type:l,value:u,onChange:e=>{i(t,l===`number`?gL(e,c?.fallback??0):e)},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:n}),l===`password`?(0,U.jsx)(WL,{disabled:f,max:c?.max,min:c?.min,pattern:c?.pattern,placeholder:c?.placeholder||n,step:c?.step}):(0,U.jsx)(cx,{variant:`secondary`,max:c?.max,min:c?.min,pattern:c?.pattern,placeholder:c?.placeholder||n,step:c?.step}),d?(0,U.jsx)(hx,{children:d}):a(s)]});return o(p,t,f)},renderSelectField:(t,n,r,s,c=e=>e,l=!1)=>{let u=String(Q(e,t,s[0]?.value||``)),d=(0,U.jsxs)(Ax,{disabledKeys:s.filter(e=>e.disabled).map(e=>e.value),fullWidth:!0,isDisabled:l,name:t.join(`.`),placeholder:n,value:u,variant:`secondary`,onChange:e=>{e===null||Array.isArray(e)||i(t,c(String(e)))},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:n}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),a(r),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:s.map(e=>(0,U.jsxs)(wx.Item,{id:e.value,textValue:e.label,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-1`,children:[(0,U.jsx)(dx,{children:e.label}),e.description?(0,U.jsx)(px,{children:e.description}):null]}),(0,U.jsx)(wx.ItemIndicator,{})]},e.value))})})]});return o(d,t,l)},renderCheckboxGroup:(t,r,i,c,l=!1,u)=>{let d=Q(e,t,[]),f=(0,U.jsxs)(`div`,{className:n.field,children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),a(i),(0,U.jsx)(`div`,{className:n.choiceGrid,children:c.map(e=>(0,U.jsxs)(m_,{variant:`secondary`,isDisabled:l,isSelected:_L(d,e.value),onChange:n=>s(t,e.value,n,u),children:[(0,U.jsxs)(m_.Content,{children:[(0,U.jsx)(m_.Control,{children:(0,U.jsx)(m_.Indicator,{})}),e.label]}),e.description?(0,U.jsx)(px,{children:e.description}):null]},e.value))})]});return o(f,t,l)},renderSlider:(t,r,s,c)=>{let l=Q(e,t,c?.fallback??0),u=c?.disabled??!1,d=(0,U.jsxs)(`div`,{className:n.field,children:[(0,U.jsxs)(Nx,{className:`w-full`,isDisabled:u,value:l,formatOptions:c?.formatOptions??{style:`percent`,maximumFractionDigits:0},maxValue:c?.max??1,minValue:c?.min??0,step:c?.step??.01,onChange:e=>{Array.isArray(e)||i(t,e)},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),(0,U.jsx)(Nx.Output,{}),(0,U.jsxs)(Nx.Track,{children:[(0,U.jsx)(Nx.Fill,{}),(0,U.jsx)(Nx.Thumb,{})]})]}),a(s)]});return o(d,t,u)},renderCronField:(r,a,s,c=!1)=>{let l=Q(e,r,`*/10 * * * *`),u=(0,U.jsx)(`div`,{className:n.field,children:(0,U.jsx)(v.Suspense,{fallback:(0,U.jsx)(`div`,{className:`h-64 animate-pulse rounded-lg bg-muted/30`}),children:(0,U.jsx)(UL,{device:t,disabled:c,value:l,onChange:e=>i(r,e)})})});return o(u,r,c)},/*KKK-PERM-START*/renderPermField:(t,r,s,c)=>{c=c||{};const p=t,list=!!c.list,modes=c.modes||[],raw=Q(e,p,list?[]:`all`),arr0=list?(Array.isArray(raw)?raw.map(String):(raw?[String(raw)]:[])):[],ids=list?arr0.filter(x=>/^\d+$/.test(x)):[],numText=list?ids.join(`, `):([`all`,`admin`].includes(String(raw))?``:String(raw||``)),kw=list?(arr0.find(x=>!/^\d+$/.test(x))||``):([`all`,`admin`].includes(String(raw))?String(raw):``),guess=(kw===`trigger`)?`trigger`:(kw||(String(numText).trim()?`id`:(list?`trigger`:`all`))),pair=(0,v.useState)(null),mode=pair[0]||guess,setMode=pair[1],apply=n=>{setMode(n);if(n===`id`){i(p,list?ids:String(numText))}else{i(p,list?[n]:n)}},setIds=n=>{i(p,list?String(n).split(/[,,\s]+/).map(x=>x.trim()).filter(Boolean):n)},sel=(0,U.jsxs)(Ax,{fullWidth:!0,name:p.join(`.`),placeholder:r,value:mode,variant:`secondary`,onChange:e=>{e===null||Array.isArray(e)||apply(String(e))},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),a(s),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:modes.map(m=>(0,U.jsx)(wx.Item,{id:m.value,textValue:m.label,children:m.label},m.value))})})]}),inp=mode===`id`?(0,U.jsxs)(lx,{fullWidth:!0,name:p.join(`.`),value:numText,onChange:e=>setIds(e),children:[(0,U.jsx)(dx,{className:`font-semibold`,children:list?`接收账号`:`允许的账号`}),(0,U.jsx)(cx,{variant:`secondary`,placeholder:`填写 QQ 号,多个用逗号分隔`})]}):null,box=(0,U.jsxs)(`div`,{className:n.field,children:[sel,inp]});return o(box,t,!1)},/*KKK-PERM-END*/renderPageHeader:(e,n)=>(0,U.jsxs)(`div`,{className:`mb-6 ${t===`mobile`?`pr-36`:``}`,"data-config-section":!0,children:[(0,U.jsx)(`h2`,{className:`text-2xl font-bold`,children:e}),(0,U.jsx)(`div`,{className:`mt-3`,children:(0,U.jsx)(px,{children:n})})]}),renderSubSection:(e,t)=>(0,U.jsxs)(Wg,{"data-config-section":!0,className:`mb-4`,children:[(0,U.jsx)(Wg.Header,{className:n.sectionHeader,children:(0,U.jsx)(Wg.Title,{className:`text-lg font-semibold`,children:e})}),(0,U.jsx)(Wg.Content,{className:n.sectionContent,children:(0,U.jsx)(`div`,{className:n.fields,children:t})})]})}},KL={root:`relative flex min-w-0 max-w-full flex-col gap-8`,loading:`flex min-h-80 items-center justify-center gap-3`,header:`grid grid-cols-[minmax(0,1fr)_auto] items-start gap-8 pr-44`,headerCopy:`flex min-w-0 flex-col gap-2`,form:`flex min-w-0 max-w-full flex-col gap-6`,floatingActions:`fixed right-6 top-20 z-10`,actionControls:`flex items-center justify-end gap-3`,sectionHeader:`p-2`,sectionContent:`p-6`,fields:`grid grid-cols-2 gap-x-6 gap-y-5`,field:`flex min-w-0 flex-col gap-2`,choiceGrid:`grid grid-cols-2 gap-3`,divider:`col-span-full flex min-w-0 flex-col gap-2 pt-3`,tabsListContainer:`w-full min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain overscroll-y-none [scrollbar-width:none] [&::-webkit-scrollbar]:hidden`,tabsList:`w-fit min-w-max *:w-fit *:min-w-fit *:flex-none *:shrink-0 *:whitespace-nowrap`,topLevelFields:`mb-4 space-y-4 px-2`},qL={root:`relative flex min-w-0 max-w-full flex-col gap-5`,loading:`flex min-h-80 items-center justify-center gap-3`,header:`flex flex-col gap-3 pt-12`,headerCopy:`flex min-w-0 flex-col gap-2`,form:`flex min-w-0 max-w-full flex-col gap-3`,floatingActions:`sticky top-0 z-20 flex h-0 w-full justify-end overflow-visible`,actionControls:`flex w-fit h-11 p-1 items-center gap-2 rounded-full border border-default-200 bg-background/90 shadow-sm backdrop-blur-md`,sectionHeader:`p-1`,sectionContent:`p-0`,fields:`grid grid-cols-1 gap-5`,field:`flex min-w-0 flex-col gap-2`,choiceGrid:`grid grid-cols-1 gap-3`,divider:`col-span-full flex min-w-0 flex-col gap-2 pt-3`,tabsListContainer:`w-full min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain overscroll-y-none [scrollbar-width:none] [&::-webkit-scrollbar]:hidden`,tabsList:`w-fit min-w-max *:w-fit *:min-w-fit *:flex-none *:shrink-0 *:whitespace-nowrap`,topLevelFields:`mb-4 space-y-4 px-4`},JL=e=>e===`mobile`?qL:KL,YL=({config:e,renderers:t})=>{let{renderPageHeader:n,renderSelectField:r,renderSubSection:i,renderSwitch:a,renderTextField:o}=t,s=Q(e,[`amagi`,`proxy`,`switch`],!1),c=Q(e,[`amagi`,`APIServer`],!1);return(0,U.jsxs)(U.Fragment,{children:[n(`接口库配置`,`接口库的 Cookies、请求、代理和 API 服务配置。保存后后端会重载接口库客户端。`),i(`平台 Cookies`,(0,U.jsxs)(U.Fragment,{children:[o([`amagi`,`cookies`,`douyin`],`抖音 Cookies`,`请输入你的抖音Cookies,不输入则无法使用抖音相关功能噢。`,{type:`password`}),o([`amagi`,`cookies`,`bilibili`],`B站 Cookies`,`请输入你的B站Cookies,不输入部分功能将受限噢。`,{type:`password`}),o([`amagi`,`cookies`,`kuaishou`],`快手 Cookies`,`请输入你的快手Cookies,不输入则无法使用快手相关功能噢。`,{type:`password`}),o([`amagi`,`cookies`,`xiaohongshu`],`小红书 Cookies`,`请输入你的小红书Cookies,不输入则无法使用小红书相关功能噢。`,{type:`password`})]})),i(`请求配置`,(0,U.jsxs)(U.Fragment,{children:[o([`amagi`,`timeout`],`请求超时时间`,`网络请求的超时时间,单位:毫秒。`,{type:`number`,fallback:15e3,min:1e3,max:3e5}),o([`amagi`,`User-Agent`],`User-Agent`,`请求头中的User-Agent字段,用于标识客户端类型。`)]})),i(`代理配置(可选)`,(0,U.jsxs)(U.Fragment,{children:[a([`amagi`,`proxy`,`switch`],`代理开关`,`开启后需要配置「代理主机」「代理端口」。`),r([`amagi`,`proxy`,`protocol`],`代理协议`,`代理服务使用的协议。`,[{label:`HTTP`,value:`http`},{label:`HTTPS`,value:`https`}],e=>e,!s),o([`amagi`,`proxy`,`host`],`代理主机`,`代理服务器的主机地址,如:127.0.0.1。`,{disabled:!s}),o([`amagi`,`proxy`,`port`],`代理端口`,`代理服务器的端口号。`,{type:`number`,fallback:7890,min:1,max:65535,disabled:!s}),o([`amagi`,`proxy`,`auth`,`username`],`代理用户名`,`代理服务器的认证用户名(如果需要)。`,{disabled:!s}),o([`amagi`,`proxy`,`auth`,`password`],`代理密码`,`代理服务器的认证密码(如果需要)。`,{type:`password`,disabled:!s})]})),i(`API 服务配置`,(0,U.jsxs)(U.Fragment,{children:[a([`amagi`,`APIServer`],`API 服务`,`本地部署一个视频解析API服务,接口范围为本插件用到的所有。`),a([`amagi`,`APIServerMount`],`挂载到 Koishi`,`API 服务是否挂载到 Koishi 上,开启后监听端口为 Koishi 的 http 端口,修改后需重启。需开启「API服务」。`,!c),o([`amagi`,`APIServerPort`],`API 服务端口`,`仅未挂载到 Koishi 时生效。`,{type:`number`,disabled:Q(e,[`amagi`,`APIServerMount`],!0),fallback:4567,min:1024,max:65535})]}))]})},XL=({config:e,renderers:t})=>{let{renderCheckboxGroup:n,renderPageHeader:r,renderSelectField:i,renderSlider:a,renderSubSection:o,renderSwitch:s,renderTextField:c}=t,l=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`);return(0,U.jsxs)(U.Fragment,{children:[r(`通用`,`插件运行、渲染和交互相关配置。`),o(`缓存设置`,(0,U.jsx)(U.Fragment,{children:s([`app`,`removeCache`],`自动删除视频缓存`,`任务完成后删除下载缓存。`)})),o(`交互设置`,(0,U.jsxs)(U.Fragment,{children:[s([`app`,`EmojiReply`],`表情回应`,`在解析任务开始时添加表情回应,若适配器不支持需要关闭。`),s([`app`,`parseTip`],`解析提示`,`发送提示信息:"检测到xxx链接,开始解析"。`),s([`app`,`fakeForward`],`伪造合并转发消息`,`一次解析产生的所有内容(卡片、图片、视频、评论…)合并成一条转发消息发出,过程提示(开始解析 / 下载中 / 发送中…)不会进转发;只有支持合并转发的适配器有效果,QQ 官方适配器会自动退化成逐条发送。开启后合并转发使用触发者身份展示;关闭后使用机器人身份展示。`),t.renderPermField([`app`,`errorLogSendTo`],`错误日志`,`谁来接收错误日志,选「指定账号」后填 QQ 号,多个用逗号分隔。`,{list:true,modes:[{value:`trigger`,label:`触发者所在的群`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]}),/*KKK-APP-START*/s([`qq`,`recallPanel`],`自动撤回面板`,`用户在面板上点完按钮后,自动把上一条提示 / 选择消息撤回,群里不会堆着一排旧提示和选择。`),s([`qq`,`forceNoDanmaku`],`强制不烧录弹幕`,`优先级最高的总开关:打开时无论指令、面板按钮还是平台配置,都不会烧录弹幕,一律按纯视频解析。要用弹幕功能时先把它关掉。`)/*KKK-APP-END*/,,]})),/*KKK-SECTION-START*/o(`在线播放器设置`,(0,U.jsx)(U.Fragment,{children:[s([`qq`,`playerEnabled`],`在线播放器总开关`,`**这一组的总开关**,默认开启。打开时,解析面板里那一列按钮上的「弹幕」会把视频放到在线播放页(带弹幕)并回一条链接,不再把弹幕烧进视频、也不再把视频传到群里;链接有有效期,过期自动清理文件。开着时面板上还会多一列「在线看」(点它直接在线看,不管弹幕功能有没有开都带弹幕),这一列由下面的「面板显示「在线看」按钮」单独控制。**关掉它,这一组里其它设置都会变灰不可改**,解析也回到原来的 ffmpeg 烧录流程(面板列头变回「烧录弹幕」、不再有「在线看」列)。(这一项要先关掉上面的「强制不烧录弹幕」(也就是打开弹幕功能)才能改)`,Q(e,[`qq`,`forceNoDanmaku`],!0)===!0),s([`qq`,`playerWatchButton`],`面板显示「在线看」按钮`,`默认开启。打开后,QQ 解析面板的「弹幕」列右边会多一列「在线看」:点它**直接在线播放**(带弹幕,视频不发到群里、也不占群文件),不看弹幕功能开没开 —— 在线看永远带弹幕。关掉就不显示这一列。注意:只有上面的「在线播放器总开关」开着时这一列才会出现(总开关关掉时这一项会变灰);播放器关掉时它没有任何作用。**超过「在线播放最大文件」的画质档不给「在线看」按钮**,那一格会标「超上限」。(这一项要先把上面的「在线播放器总开关」打开才能改)`,Q(e,[`qq`,`playerEnabled`],!0)===!1),c([`qq`,`playerBaseUrl`],`播放器公网地址`,`**这是你自己的公网地址,插件猜不出来,必须由你填。**例如 https://play.example.com(结尾斜杠会自动去掉),用户收到的链接就是它加上 /kkk/player/<令牌>。留空时链接会退化成「http://本机 IP:端口」,**只有本机 / 内网能打开**;这时日志里会警告一次,机器人回复和播放页上也会带一句「未配置公网地址,仅本机可访问」——公网用户点开打不开是正常的,不是插件坏了。用 Nginx / Caddy 之类的反向代理指向下面的「播放器端口」即可,代理到 https 域名时这里就填那个域名。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`text`,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerPort`],`播放器端口`,`0 = 复用 Koishi 自己的端口(推荐,不用额外开端口);填其它值会用 node:http 另起一个服务。端口被占用时只记一条日志并退回 Koishi 端口,不会影响解析。注意别填浏览器禁止访问的端口(例如 6665-6669 这些 IRC 段),否则用户点开链接会直接 ERR_UNSAFE_PORT,看起来就像网页坏了。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:0,min:0,max:65535,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerExpireMinutes`],`链接有效期(分钟)`,`播放链接与视频文件的有效期,默认 60 分钟(最小 1、最大 1440)。到点后视频和弹幕会被自动删除,链接打开是「链接已过期」。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:60,min:1,max:1440,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerMaxFileMB`],`在线播放最大文件(MB)`,`体积超过这个值的视频**不走在线播放**,改回原来的发送流程(免得把机器磁盘塞满)。留空或填 0 = 跟随全局:用上游的「文件大小限制」(usefilelimit / filelimit,当前默认 200MB);全局没开限制就是不限制。**这条上限对「超限转在线播放」一样有效**:开了转播、但视频比这条上限还大时,仍然按原来的方式处理(拒绝并说明),不会为了转播把机器磁盘塞满。判定发生在把文件搬进播放器目录之前,超限的视频一点都不会占播放器目录。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:0,min:0,max:102400,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),s([`qq`,`playerOnOversize`],`超限转在线播放`,`打开后,体积超过全局「文件大小限制」的视频不再被拒绝(原来会回一句「视频太大了,还是去B站看吧」),而是照常下载、改为在线播放:用户收到一条播放链接,视频不发到群里、也不占群文件。注意:**只有体积不超过上面「在线播放最大文件」的视频才会被转播**——比那个上限还大的照旧拒绝(免得把机器磁盘塞满),拒绝时会说明「超过在线播放的体积上限,按原来的方式处理」。关着时维持原来的行为。(这一项要先把上面的「在线播放器总开关」打开才能改)`,Q(e,[`qq`,`playerEnabled`],!0)===!1)]}))/*KKK-SECTION-END*/,o(`渲染设置`,(0,U.jsxs)(U.Fragment,{children:[c([`app`,`renderScale`],`渲染精度`,`可选值50~200,建议100。设置高精度会提高图片的精细度,过高可能会影响渲染与发送速度。`,{type:`number`,fallback:100,min:50,max:200}),(0,U.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,U.jsx)(`div`,{className:`min-w-0 flex-1`,children:i([`app`,`Theme`],`渲染图片的主题色`,`渲染评论图和推送图的主题色。`,[{label:`自动`,value:`0`,description:`06:00-18:00为浅色,18:00-06:00为深色`},{label:`浅色`,value:`1`},{label:`深色`,value:`2`},{label:`智能场景(实验性)`,value:`3`,description:`自动模式的超集;部分模板会根据封面色调 智能调整主题色,可能会出现不适配的情况。`}],e=>Number(e))}),(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{"aria-label":`封面氛围背景参数`,className:`mt-7 shrink-0`,children:(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`封面氛围背景参数`,variant:`secondary`,children:(0,U.jsx)(Gj,{className:`size-4`,"aria-hidden":`true`})})}),(0,U.jsx)(gv.Content,{className:`w-90 max-w-[calc(100vw-2rem)]`,placement:`bottom`,children:(0,U.jsxs)(gv.Dialog,{children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(gv.Heading,{children:`封面氛围背景`}),(0,U.jsx)(`p`,{className:`mt-1 mb-5 text-sm text-muted`,children:`仅对使用封面氛围背景的模板生效(抖音视频/图文作品、B站视频信息、B站直播推荐动态)。`}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-5`,children:[a([`app`,`ambientCover`,`coverOpacity`],`封面氛围强度`,`封面图对背景氛围的贡献度,即模糊封面层的不透明度,越大封面色越浓。`,{fallback:.7}),a([`app`,`ambientCover`,`overlayEdgeOpacity`],`氛围压色(顶部/底部)`,`背景两端主题色压色罩的不透明度,越大两端越接近纯色主题背景。`,{fallback:.9}),a([`app`,`ambientCover`,`overlayMiddleOpacity`],`氛围压色(中间带)`,`背景中间带主题色压色罩的不透明度,越小封面色越透。`,{fallback:.2})]})]})})]})]}),c([`app`,`RenderWaitTime`],`渲染图片的等待时间`,`单位:秒,Linux系统下不能为0;其他系统传递 0 可禁用。`,{type:`number`,fallback:60,min:0}),s([`app`,`multiPageRender`],`分页渲染`,`将模板渲染成多页的图片,以降低渲染器压力,默认开启,非必要不修改!`),c([`app`,`multiPageHeight`],`分页渲染时,每页的高度`,`经测试最佳每页高度为12000px,默认12000px。`,{type:`number`,disabled:!Q(e,[`app`,`multiPageRender`],!0),fallback:12e3,min:1e3,max:2e4})]})),o(`上传与下载设置`,(0,U.jsxs)(U.Fragment,{children:[(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:[i([`app`,`videoSendMode`],`本地视频发送方式`,`选择本地视频交付给协议端的方式。`,[{label:`File 协议(本地文件)`,value:`file`,description:`使用 file 协议发送本地视频,需 Koishi 与协议端在同一网络环境下`},{label:`Base64(编码传输)`,value:`base64`,description:`将本地视频转换为 base64 发送,传输数据量增大约 30%,不在同一网络环境可能导致额外带宽成本,适合 karin 和协议端不在同一网络环境`}],e=>e,Q(e,[`app`,`usegroupfile`],!1)),s([`app`,`usegroupfile`],`群文件上传`,`使用群文件上传,开启后会将视频文件上传到群文件中,需配置「群文件上传阈值」。与「本地视频发送方式 = Base64」互斥。`,Q(e,[`app`,`videoSendMode`],`file`)===`base64`),c([`app`,`groupfilevalue`],`群文件上传阈值`,`当文件大小超过该值时将使用群文件上传,单位:MB,「使用群文件上传」开启后才会生效。`,{type:`number`,fallback:100,min:1,disabled:!Q(e,[`app`,`usegroupfile`],!1)||Q(e,[`app`,`videoSendMode`],`file`)===`base64`})]}),(0,U.jsx)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:i([`app`,`imageSendMode`],`网络图片发送方式`,`图片资源发送给协议端的方式。`,[{label:`URL 链接(直接传递)`,value:`url`,description:`直接传递 HTTP 链接给上游下载,可能因上游网络问题导致下载超时`},{label:`File 协议(本地文件)`,value:`file`,description:`下载到本地后使用 file 协议发送,需 Koishi 与协议端在同一网络环境下`},{label:`Base64(编码传输)`,value:`base64`,description:`下载后转换为 base64 发送,传输数据量增大约 30%,不在同一网络环境可能导致额外带宽成本`}])}),(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:[s([`app`,`usefilelimit`],`视频上传拦截`,`开启后会根据视频文件大小判断是否需要上传,需配置「视频拦截阈值」。`),c([`app`,`filelimit`],`视频拦截阈值`,`视频文件大于该数值则直接结束任务,不会上传,单位: MB,「视频上传拦截」开启后才会生效。`,{type:`number`,fallback:20,min:1,disabled:!Q(e,[`app`,`usefilelimit`],!1)}),s([`app`,`compress`],`压缩视频`,`开启后会将视频文件压缩后再上传,适合上传大文件,任务过程中会吃满CPU,对低配服务器不友好。需配置「压缩触发阈值」与「压缩后的值」。`),c([`app`,`compresstrigger`],`压缩触发阈值`,`触发视频压缩的阈值,单位:MB。当文件大小超过该值时,才会压缩视频,「压缩视频」开启后才会生效。`,{type:`number`,fallback:80,min:1,disabled:!Q(e,[`app`,`compress`],!1)}),c([`app`,`compressvalue`],`压缩后的值`,`单位:MB,若视频文件大小大于「压缩触发阈值」的值,则会进行压缩至该值(±5%),「压缩视频」开启后才会生效。`,{type:`number`,fallback:30,min:1,disabled:!Q(e,[`app`,`compress`],!1)})]}),(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 rounded-3xl`,variant:`secondary`,children:[s([`app`,`downloadThrottle`],`下载限速`,`开启后会限制下载速度,避免触发服务器风控导致连接被重置(ECONNRESET)。如果下载时经常报错"连接被重置",建议开启。`),c([`app`,`downloadMaxSpeed`],`最大下载速度`,`限速开关打开后生效。单位:MB/s,建议值:10,根据实际情况调整。`,{type:`number`,fallback:10,min:1,max:100,disabled:!Q(e,[`app`,`downloadThrottle`],!1)}),s([`app`,`downloadAutoReduce`],`断流自动降速`,`限速开关打开后生效。当检测到下载中断时,自动降低下载速度,避免再次触发风控。`,!Q(e,[`app`,`downloadThrottle`],!1)),c([`app`,`downloadMinSpeed`],`最低下载速度`,`断流降速开关打开后生效。单位:MB/s,自动降速的下限值。`,{type:`number`,fallback:1,min:.5,max:50,disabled:!Q(e,[`app`,`downloadThrottle`],!1)||!Q(e,[`app`,`downloadAutoReduce`],!1)})]})]})),o(`Live Photo 兼容设置`,(0,U.jsxs)(U.Fragment,{children:[i([`app`,`livePhotoMode`],`Live Photo 处理和发送方式`,`解析遇到实况图时的处理和发送方式。注意:生成视频性能开销大,2C2G 服务器单张约需 20 秒。`,[{label:`视频 + 实况图`,value:`video_and_livephoto`,description:`生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)+ 对应系统的实况图`},{label:`仅视频`,value:`video_only`,description:`仅生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)`},{label:`仅实况图`,value:`livephoto_only`,description:`仅生成并发送对应系统的实况图,性能开销小`}]),i([`app`,`livePhotoSystem`],`Live Photo 静态图兼容系统`,`当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo 静态图按所选系统生成。推荐 OPPO,兼容性最广。`,[{label:`Google`,value:`google`,description:`Google Motion Photo 格式`},{label:`小米(HyperOS)`,value:`xiaomi`,description:`兼容小米(任何版本)和 Google,但无法被 OPPO 识别`},{label:`OPPO(ColorOS)`,value:`oppo`,description:`推荐,兼容 OPPO、小米(较新版本)和 Google`},{label:`华为/荣耀(HarmonyOS/MagicOS)`,value:`huawei_honor`,description:`理论可行但未实测(作者无对应设备)`},{label:`vivo(Origin OS)`,value:`vivo`,description:`需要独立的图片和同名视频文件,暂不支持`,disabled:!0},{label:`iPhone(iOS)`,value:`iphone`,description:`需要独立的图片和同名视频文件,暂不支持`,disabled:!0}],e=>e,l===`video_only`)]})),o(`我的小玩具`,(0,U.jsxs)(U.Fragment,{children:[s([`app`,`videoTool`],`默认解析优先级`,`关闭后使用自定义优先级,修改后需重启。`),c([`app`,`priority`],`自定义优先级`,`默认解析优先级关闭后生效。`,{type:`number`,disabled:Q(e,[`app`,`videoTool`],!0),fallback:800}),i([`app`,`qrLoginAddrType`],`扫码登录地址`,`生成登录二维码时使用的服务器地址。`,[{label:`局域网`,value:`lan`,description:`适用于手机和服务器在同一局域网`},{label:`外部地址`,value:`external`,description:`适用于远程访问,需手动配置`}]),c([`app`,`qrLoginExternalAddr`],`外部访问地址`,`公网 IP 或域名,如:123.45.67.89 或 example.com。`,{disabled:Q(e,[`app`,`qrLoginAddrType`],`lan`)!==`external`})]}))]})},ZL=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderCronField:i,renderPageHeader:a,renderSelectField:o,renderSubSection:s,renderSwitch:c,renderTextField:l}=t,u=Q(e,[`bilibili`,`switch`],!1),d=Q(e,[`bilibili`,`sendContent`],[]),f=Q(e,[`bilibili`,`burnDanmaku`],!1),p=Q(e,[`bilibili`,`videoQuality`],0),m=Q(e,[`bilibili`,`videoInfoMode`],`text`),h=Q(e,[`bilibili`,`push`,`switch`],!1),g=Q(e,[`bilibili`,`push`,`parsedynamic`],!1),_=Q(e,[`bilibili`,`push`,`pushVideoQuality`],0),v=!u||!_L(d,`comment`),y=!u||!f;return(0,U.jsxs)(U.Fragment,{children:[a(`哔哩哔哩`,`B站解析、动态图片布局、弹幕和推送基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[c([`bilibili`,`switch`],`解析开关`,`B站解析开关,此开关为单独开关。`),r([`bilibili`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL.filter(e=>e.value!==`image`),!u)]}),s(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[l([`bilibili`,`numcomment`],`评论解析数量`,`主评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:v}),c([`bilibili`,`realCommentCount`],`显示真实评论数量`,`关闭则显示解析到的评论数量。`,v),c([`bilibili`,`commentImageCollection`],`是否收集评论区的图片`,`开启后将收集评论区的图片,以合并转发的形式返回。`,v)]})),s(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[o([`bilibili`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,PL,Number,!u),l([`bilibili`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!u||Number(p)!==0}),o([`bilibili`,`imageLayout`],`解析图文动态时,遇到多张图片时的页面布局方式(动态推送图片也生效)`,`自动布局:少于4张时逐张上下排列;4~8张时瀑布流;9张及以上九宫格。`,[{label:`自动布局`,value:`auto`},{label:`逐张上下排列`,value:`vertical`},{label:`瀑布流排列`,value:`waterfall`},{label:`九宫格排列`,value:`grid`}]),o([`bilibili`,`videoInfoMode`],`视频信息返回形式`,`视频信息返回文本或图片。`,[{label:`图片模式`,value:`image`},{label:`文本模式`,value:`text`}],e=>e,!u),r([`bilibili`,`displayContent`],`视频信息前返回的内容`,`若什么都不选,则不会返回任何视频相关信息。`,ML,!u||m===`image`),c([`bilibili`,`showDanmakuInVideoInfo`],`视频信息图片中显示弹幕`,`开启后在视频信息图片的封面区域显示热门弹幕。关闭后不会请求弹幕数据,可提升解析速度。仅「视频信息返回形式」为图片模式时生效。`,!u||m===`text`)]})),s(`权限设置`,(0,U.jsx)(U.Fragment,{children:t.renderPermField([`bilibili`,`loginPerm`],`谁可以触发扫码登录`,`选「指定账号」后填 QQ 号,多个用逗号分隔。`,{modes:[{value:`all`,label:`所有人`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]})})),s(`弹幕烧录相关`,(0,U.jsxs)(U.Fragment,{children:[c([`bilibili`,`burnDanmaku`],`弹幕烧录`,`将弹幕硬编码到视频画面中。开启后视频需要重新编码,耗时较长,高分辨率视频会占用较多资源。`,!u),o([`bilibili`,`danmakuArea`],`弹幕区域`,`限制弹幕的显示范围,避免遮挡视频主体内容。`,zL,Number,y),o([`bilibili`,`danmakuFontSize`],`弹幕字号`,`弹幕文字大小。`,BL,e=>e,y),l([`bilibili`,`danmakuOpacity`],`弹幕透明度`,`0为完全透明,100为完全不透明,推荐70。`,{type:`number`,fallback:70,min:0,max:100,disabled:y}),o([`bilibili`,`verticalMode`],`竖屏适配`,`模拟手机端竖屏观看体验,视频居中显示,上下黑边区域用于展示弹幕。`,RL,e=>e,y),o([`bilibili`,`videoCodec`],`视频编码格式`,`弹幕烧录时使用的视频编码格式,会自动检测硬件加速。`,LL,e=>e,y)]})),s(`B站推送相关`,(0,U.jsxs)(U.Fragment,{children:[c([`bilibili`,`push`,`switch`],`推送开关`,`推送开关,修改后需重启;使用「#设置B站推送 + UID」配置推送列表。`),o([`bilibili`,`push`,`permission`],`谁可以设置推送`,`修改后需重启。`,IL,e=>e,!h),i([`bilibili`,`push`,`cron`],`定时任务表达式`,`定时推送的时间,支持可视化编辑或手动输入 cron 表达式。`,!h),c([`bilibili`,`push`,`parsedynamic`],`作品解析`,`触发推送时是否一同解析该作品。`,!h),r([`bilibili`,`push`,`parseDynamicTypes`],`需要解析的动态类型`,`选择推送时需要进一步解析的动态类型;未选择的类型只发送动态卡片。`,FL,!h||!g),o([`bilibili`,`push`,`pushVideoQuality`],`解析视频动态时的画质偏好`,`「作品解析」开启时生效,仅对视频动态有效。`,PL.filter(e=>e.value!==`127`),Number,!h||!g),l([`bilibili`,`push`,`pushMaxAutoVideoSize`],`视频动态的视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「解析视频动态时的画质偏好」 为 "自动选择" 且「作品解析」开启时生效,仅对视频动态有效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!h||!g||Number(_)!==0})]}))]})},QL=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderCronField:i,renderPageHeader:a,renderSelectField:o,renderSubSection:s,renderSwitch:c,renderTextField:l}=t,u=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`),d=Q(e,[`douyin`,`switch`],!1),f=Q(e,[`douyin`,`sendContent`],[]),p=Q(e,[`douyin`,`burnDanmaku`],!1),m=Q(e,[`douyin`,`videoQuality`],`adapt`),h=Q(e,[`douyin`,`videoInfoMode`],`text`),g=Q(e,[`douyin`,`push`,`switch`],!1),_=Q(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`),v=!d||!_L(f,`comment`),y=!d||!p;return(0,U.jsxs)(U.Fragment,{children:[a(`抖音`,`抖音解析、画质、弹幕和推送基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[c([`douyin`,`switch`],`解析开关`,`抖音解析开关,此开关为单独开关。`),r([`douyin`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL.filter(e=>e.value!==`image`),!d)]}),s(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[l([`douyin`,`numcomment`],`评论解析数量`,`主评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:v}),l([`douyin`,`subCommentLimit`],`子评论请求数量`,`单条主评论下请求的子评论总条数(含多层嵌套)。注意:UI中最多显示 6 层回复嵌套,超出部分会被隐藏;因实际嵌套深度不可预知,配置数量不代表最终可见数量。`,{type:`number`,fallback:5,min:1,max:20,disabled:v}),c([`douyin`,`commentImageCollection`],`是否收集评论区的图片`,`开启后将收集评论区的图片,以合并转发的形式返回。`,v)]})),s(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[o([`douyin`,`liveImageMergeMode`],`合辑 Live 图 BGM 合并方式`,`合辑 Live 图 BGM 合并方式,仅 Live Photo 模式不是「仅实况图」时生效。`,[{label:`连续`,value:`continuous`,description:`BGM 接续播放,结束后自动循环`},{label:`独立`,value:`independent`,description:`每张图 BGM 从头开始`}],e=>e,!d||u===`livephoto_only`),o([`douyin`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,NL,e=>e,!d),l([`douyin`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!d||m!==`adapt`}),o([`douyin`,`videoInfoMode`],`视频信息返回形式`,`视频信息返回文本或图片。`,[{label:`图片模式`,value:`image`},{label:`文本模式`,value:`text`}],e=>e,!d),r([`douyin`,`displayContent`],`视频信息的内容`,`若什么都不选,则不会返回任何视频相关信息。`,ML.filter(e=>e.value!==`desc`),!d||h===`image`)]})),s(`权限设置`,(0,U.jsx)(U.Fragment,{children:t.renderPermField([`douyin`,`loginPerm`],`谁可以触发扫码登录`,`选「指定账号」后填 QQ 号,多个用逗号分隔。`,{modes:[{value:`all`,label:`所有人`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]})})),s(`弹幕烧录相关`,(0,U.jsxs)(U.Fragment,{children:[c([`douyin`,`burnDanmaku`],`弹幕烧录`,`将弹幕硬编码到视频画面中。开启后视频需要重新编码,耗时较长。`,!d),o([`douyin`,`danmakuArea`],`弹幕显示区域`,`限制弹幕范围,避免遮挡视频主体。`,zL,Number,y),o([`douyin`,`danmakuFontSize`],`弹幕字号`,`弹幕文字大小。`,BL,e=>e,y),l([`douyin`,`danmakuOpacity`],`弹幕透明度`,`0为完全透明,100为完全不透明,推荐70。`,{type:`number`,fallback:70,min:0,max:100,disabled:y}),o([`douyin`,`verticalMode`],`竖屏适配`,`针对横屏视频,模拟手机端竖屏观看体验,视频居中显示,上下黑边区域用于展示弹幕。`,RL,e=>e,y),o([`douyin`,`videoCodec`],`视频编码格式`,`烧录弹幕后的视频编码格式。`,LL,e=>e,y)]})),s(`抖音推送相关`,(0,U.jsxs)(U.Fragment,{children:[c([`douyin`,`push`,`switch`],`推送开关`,`推送开关,修改后需重启;使用「#设置抖音推送 + 抖音号」配置推送列表。`),o([`douyin`,`push`,`permission`],`谁可以设置推送`,`修改后需重启。`,IL,e=>e,!g),i([`douyin`,`push`,`cron`],`定时任务表达式`,`定时推送的时间,支持可视化编辑或手动输入 cron 表达式。`,!g),c([`douyin`,`push`,`parsedynamic`],`作品解析`,`触发推送时是否一同解析该作品。`,!g),o([`douyin`,`push`,`shareType`],`推送图二维码的类型`,`推送图二维码识别后的跳转类型。`,[{label:`网页链接`,value:`web`,description:`识别后访问抖音官网对应的作品地址`},{label:`下载链接`,value:`download`,description:`识别后访问无水印作品下载地址`}],e=>e,!g),o([`douyin`,`push`,`pushVideoQuality`],`画质偏好`,`推送解析时解析视频的分辨率偏好。`,NL,e=>e,!g),l([`douyin`,`push`,`pushMaxAutoVideoSize`],`视频体积上限(MB)`,`推送解析时根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!g||_!==`adapt`})]}))]})},$L=({config:e,renderers:t,classes:n})=>{let{renderPageHeader:r,renderSubSection:i,renderSwitch:a,renderTextField:o}=t,s=Q(e,[`kuaishou`,`switch`],!1),c=Q(e,[`kuaishou`,`comment`],!1);return(0,U.jsxs)(U.Fragment,{children:[r(`快手`,`快手解析基础设置。`),(0,U.jsx)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:a([`kuaishou`,`switch`],`解析开关`,`快手解析开关,此开关为单独开关。`)}),i(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[a([`kuaishou`,`comment`],`评论解析`,`快手评论解析,开启后可发送快手作品评论图。`,!s),o([`kuaishou`,`numcomment`],`评论解析数量`,`快手评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:!s||!c})]}))]})},eR=({children:e,disabled:t,message:n,device:r})=>t?r===`mobile`?(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{className:`w-full cursor-not-allowed`,children:e}),(0,U.jsxs)(gv.Content,{placement:`bottom`,children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(`div`,{className:`px-3 py-2`,children:(0,U.jsx)(`p`,{className:`text-sm text-foreground`,children:n})})]})]}):(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{className:`w-full cursor-not-allowed`,children:e}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),n]})]}):e,tR=e=>e===`desktop`?`grid grid-cols-2 gap-4`:`flex flex-col gap-4`,nR=[{label:`作品列表`,value:`post`,description:`推送用户发布的作品`},{label:`喜欢列表`,value:`favorite`,description:`推送用户喜欢的作品`},{label:`推荐列表`,value:`recommend`,description:`推送推荐的作品`},{label:`直播`,value:`live`,description:`推送直播状态`}],rR=[{label:`投稿视频`,value:`video`,description:`推送UP主投稿的视频`},{label:`图文动态`,value:`draw`,description:`推送图文动态`},{label:`纯文动态`,value:`word`,description:`推送纯文字动态`},{label:`直播动态`,value:`live`,description:`推送直播状态`},{label:`转发动态`,value:`forward`,description:`推送转发的动态`},{label:`投稿专栏`,value:`article`,description:`推送专栏文章`}],iR=[{label:`黑名单`,value:`blacklist`,description:`命中关键词/标签则不推送`},{label:`白名单`,value:`whitelist`,description:`只推送命中关键词/标签的内容`}],aR=({label:e,description:t,items:n,onAdd:r,onRemove:i,disabled:a=!1})=>{let[o,s]=(0,v.useState)(``),[c,l]=(0,v.useState)(``),u=()=>{let e=o.trim();if(!e){l(`请输入内容`);return}if(n.includes(e)){l(`该项已存在,请勿重复添加`);return}r(e),s(``),l(``)};return(0,U.jsxs)(`div`,{className:`space-y-2`,children:[(0,U.jsxs)(`div`,{className:`flex gap-2`,children:[(0,U.jsxs)(lx,{className:`flex-1`,isDisabled:a,isInvalid:!!c,value:o,onChange:e=>{s(e),c&&l(``)},children:[(0,U.jsx)(dx,{children:e}),(0,U.jsx)(cx,{variant:`secondary`,placeholder:`输入${e}`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),u())}}),c?(0,U.jsx)(hx,{children:c}):null]}),(0,U.jsx)(Vg,{isDisabled:a,variant:`secondary`,onPress:u,children:(0,U.jsx)(Hj,{className:`size-4`})})]}),n.length>0?(0,U.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:n.map(e=>(0,U.jsxs)(v_,{color:`accent`,variant:`soft`,children:[(0,U.jsx)(`span`,{children:e}),a?null:(0,U.jsx)(`button`,{type:`button`,className:`ml-1 rounded-full p-0.5 hover:bg-black/10`,onClick:()=>i(e),children:(0,U.jsx)(Kj,{className:`size-3`})})]},e))}):(0,U.jsxs)(px,{children:[`暂无`,e]}),(0,U.jsx)(px,{children:t})]})},oR=(e,t)=>{if((e.success||e.code===200)&&e.data!==void 0)return e.data;throw Error(e.message||t)},sR=async()=>{let r=(await eI.get(`/kkk/v1/bots`)).data?.data;return Array.isArray(r)?r:[]},cR=async e=>{let r=(await eI.get(`/kkk/v1/bots/${encodeURIComponent(e)}/groups`)).data?.data;return Array.isArray(r)?r:[]},lR=async e=>{if(!e.length)return [];let r=(await eI.post(`/kkk/v1/groups/batch`,{groups:e})).data?.data;return Array.isArray(r)?r:[]},uR=({mapping:e,compact:t=!1,stacked:n=!1})=>n?(0,U.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.groupName||e.groupId,src:e.groupAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.groupName||e.groupId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.groupName||e.groupId}),(0,U.jsx)(px,{className:`block truncate`,children:e.groupId})]})]}),(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 pl-8`,children:[(0,U.jsx)(Nj,{className:`size-4 shrink-0 text-muted`}),(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.botName||e.botId,src:e.botAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.botName||e.botId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.botName||e.botId}),(0,U.jsx)(px,{className:`block truncate`,children:t?e.botId:`Bot ${e.botId}`})]})]})]}):(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.groupName||e.groupId,src:e.groupAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.groupName||e.groupId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.groupName||e.groupId}),(0,U.jsx)(px,{className:`block truncate`,children:e.groupId})]}),(0,U.jsx)(Nj,{className:`size-4 shrink-0 text-muted`}),(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.botName||e.botId,src:e.botAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.botName||e.botId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.botName||e.botId}),(0,U.jsx)(px,{className:`block truncate`,children:t?e.botId:`Bot ${e.botId}`})]})]}),dR=e=>`${e.groupId}:${e.botId}`,fR=e=>{let[t,n,r]=e.split(`:`);return!t||!n||r!==void 0?null:{groupId:t,botId:n}},pR=e=>{let t=new Set,n=[];return e.forEach(e=>{let r=fR(e);if(!r)return;let i=dR(r);t.has(i)||(t.add(i),n.push(i))}),n},mR=({device:e,mappings:t,onEdit:n,onRemove:r})=>(0,U.jsxs)(`div`,{className:e===`mobile`?`flex min-h-0 min-w-0 flex-1 flex-col gap-4`:`flex min-w-0 flex-col gap-3`,children:[(0,U.jsxs)(`div`,{children:[(0,U.jsx)(dx,{children:`已配置目标`}),(0,U.jsxs)(px,{children:[t.length,` 个推送目标`]})]}),t.length>0?(0,U.jsx)(`div`,{className:e===`mobile`?`flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto pb-2`:`flex max-h-72 flex-col gap-2 overflow-y-auto`,children:t.map(t=>{let i=dR(t);return(0,U.jsxs)(`div`,{className:`flex min-w-0 items-start gap-2 rounded-lg border border-default-200 bg-default-50/50 p-2.5`,children:[(0,U.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,U.jsx)(uR,{compact:!0,mapping:t,stacked:e===`mobile`})}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`编辑推送目标`,size:`sm`,variant:`tertiary`,onPress:()=>n(i),children:(0,U.jsx)(Vj,{className:`size-4`})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),`编辑`]})]}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`删除推送目标`,size:`sm`,variant:`danger`,onPress:()=>r(i),children:(0,U.jsx)(Kj,{className:`size-4`})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),`删除`]})]})]},i)})}):(0,U.jsx)(`div`,{className:`rounded-lg border border-dashed border-default-300 px-4 py-5 text-sm text-muted`,children:`还没有推送目标,点击上方按钮添加。`})]}),hR=({label:e,description:t,placeholder:n,disabled:r=!1,items:i,selectedId:a,onSelect:o})=>(0,U.jsxs)(Ax,{fullWidth:!0,allowsEmptyCollection:!0,isDisabled:r,placeholder:n,value:a||null,variant:`secondary`,onChange:e=>o(String(e||``)),children:[(0,U.jsx)(dx,{children:e}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{children:({defaultChildren:e,isPlaceholder:t,state:n})=>{if(t||n.selectedItems.length===0)return e;let r=i.find(e=>e.id===n.selectedItems[0]?.key);return r?(0,U.jsxs)(`span`,{className:`flex min-w-0 items-center gap-3`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:r.name,src:r.avatar}),(0,U.jsx)(Ig.Fallback,{children:r.name.slice(0,1)})]}),(0,U.jsxs)(`span`,{className:`min-w-0`,children:[(0,U.jsx)(`span`,{className:`block truncate`,children:r.name}),(0,U.jsx)(`span`,{className:`block truncate text-xs text-muted`,children:r.description})]})]}):e}}),(0,U.jsx)(Ax.Indicator,{})]}),(0,U.jsx)(px,{children:t}),!r&&i.length===0?(0,U.jsx)(px,{className:`text-warning`,children:`当前没有可选项`}):null,(0,U.jsx)(Ax.Popover,{className:`max-h-72`,children:(0,U.jsx)(wx,{items:i,children:e=>(0,U.jsxs)(wx.Item,{id:e.id,textValue:`${e.name} ${e.description}`,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.name,src:e.avatar}),(0,U.jsx)(Ig.Fallback,{children:e.name.slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`truncate`,children:e.name}),(0,U.jsx)(px,{className:`truncate`,children:e.description})]})]}),(0,U.jsx)(wx.ItemIndicator,{})]})})})]}),gR=({isOpen:e,device:t,initialMapping:n,onOpenChange:r,onConfirm:i})=>{let[a,o]=(0,v.useState)([]),[s,c]=(0,v.useState)([]),[l,u]=(0,v.useState)(n?.botId||``),[d,f]=(0,v.useState)(n?.groupId||``),[p,m]=(0,v.useState)(!0),[h,g]=(0,v.useState)(!!n?.botId),[_,y]=(0,v.useState)(``);(0,v.useEffect)(()=>{e&&(u(n?.botId||``),f(n?.groupId||``),c([]),o([]),m(!0),g(!!n?.botId),y(``))},[e,n?.botId,n?.groupId]);let b=(0,v.useMemo)(()=>a.find(e=>e.id===l),[a,l]),x=(0,v.useMemo)(()=>s.find(e=>e.id===d),[s,d]),S=(0,v.useMemo)(()=>a.map(e=>({id:e.id,name:e.name,avatar:e.avatar,description:e.id})),[a]),C=(0,v.useMemo)(()=>s.map(e=>({id:e.id,name:e.name,avatar:e.avatar,description:e.id})),[s]),w=!!(l&&d);(0,v.useEffect)(()=>{e&&sR().then(o).catch(e=>{y(e instanceof Error?e.message:`获取 Bot 列表失败`)}).finally(()=>m(!1))},[e]),(0,v.useEffect)(()=>{!e||!l||cR(l).then(e=>{c(e),f(t=>e.some(e=>e.id===t)?t:``)}).catch(e=>{y(e instanceof Error?e.message:`获取群列表失败`)}).finally(()=>g(!1))},[e,l]);let T=()=>{if(!w||!b)return;let e={groupId:(x&&x.id)||String(d||``).trim(),botId:b.id};x&&x.name&&(e.groupName=x.name),x&&x.avatar&&(e.groupAvatar=x.avatar),b.name&&(e.botName=b.name),b.avatar&&(e.botAvatar=b.avatar),b.isOnline!==void 0&&(e.isOnline=b.isOnline),i(e)},E=t===`desktop`?`right`:`bottom`,D=n?`编辑推送目标`:`添加推送目标`;return(0,U.jsx)(pv.Backdrop,{isOpen:e,onOpenChange:r,children:(0,U.jsx)(pv.Content,{placement:E,children:(0,U.jsxs)(pv.Dialog,{className:t===`desktop`?`h-full w-105 max-w-[90vw]`:`max-h-[78dvh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsxs)(pv.Header,{children:[(0,U.jsx)(pv.Heading,{children:D}),(0,U.jsx)(px,{children:`先选择机器人账号,再填写要推送的群号。`})]}),(0,U.jsxs)(pv.Body,{className:`flex flex-col gap-4`,children:[(0,U.jsx)(hR,{description:`Koishi 当前已注册且在线的 Bot。`,disabled:p,items:S,label:`机器人账号`,placeholder:`选择机器人账号`,selectedId:l,onSelect:e=>{y(``),c([]),g(!!e),u(e),f(``)}}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(dx,{className:`font-semibold`,children:`推送群`}),(0,U.jsx)(`input`,{className:`w-full rounded-large border border-default-200 bg-default-100 px-3 py-2 text-sm outline-none`,placeholder:`填写群号,例如 1050229473`,value:d||``,onChange:e=>f(e.target.value)}),(0,U.jsx)(px,{className:`text-xs`,children:`直接填群号(频道 id)即可;要指定平台时写成 平台:群号。`})]}),p||h?(0,U.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-muted`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取列表`}),(0,U.jsx)(`span`,{children:`正在读取列表`})]}):null,b&&x?(0,U.jsxs)(`div`,{className:`flex flex-col gap-2 rounded-lg border border-default-200 bg-default-50/60 p-3`,children:[(0,U.jsx)(dx,{children:`将写入`}),(0,U.jsxs)(px,{className:`mt-1`,children:[x.name,`(`,x.id,`) -> `,b.name,`(`,b.id,`)`]})]}):null,_?(0,U.jsx)(px,{className:`text-danger`,children:_}):null]}),(0,U.jsxs)(pv.Footer,{children:[(0,U.jsx)(Vg,{size:t===`mobile`?`sm`:`md`,slot:`close`,variant:`secondary`,children:`取消`}),(0,U.jsx)(Vg,{size:t===`mobile`?`sm`:`md`,slot:`close`,isDisabled:!w,onPress:T,children:n?`保存`:`添加`})]})]})})})},_R=(e,t,n)=>{let r=pR(e);return{values:r,mappings:r.map(e=>{let r=fR(e),i=n[e]||t.find(t=>dR(t)===e);if(!r)return null;let a={groupId:r.groupId,botId:r.botId};return i?.groupName&&(a.groupName=i.groupName),i?.groupAvatar&&(a.groupAvatar=i.groupAvatar),i?.botName&&(a.botName=i.botName),i?.botAvatar&&(a.botAvatar=i.botAvatar),i?.isOnline!==void 0&&(a.isOnline=i.isOnline),a}).filter(e=>!!e)}},vR=({isOpen:e,values:t,mappings:n,device:r,onOpenChange:i,onApply:a})=>{let[o,s]=(0,v.useState)(()=>pR(t)),[c,l]=(0,v.useState)({}),[u,d]=(0,v.useState)(null),[f,p]=(0,v.useState)(!1),m=(0,v.useMemo)(()=>_R(o,n,c),[o,c,n]),h=r===`desktop`?`right`:`bottom`,g=u?fR(u):null,_=e=>{d(e),p(!0)};return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(pv.Backdrop,{isOpen:e,onOpenChange:e=>{e||a(m.values),i(e)},variant:`blur`,children:(0,U.jsx)(pv.Content,{placement:h,children:(0,U.jsxs)(pv.Dialog,{className:r===`desktop`?`h-full w-130 max-w-[90vw]`:`max-h-[84dvh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsxs)(pv.Header,{children:[(0,U.jsx)(pv.Heading,{children:`推送目标`}),(0,U.jsx)(px,{children:`管理所有接收推送的群和 Bot 映射。`})]}),(0,U.jsxs)(pv.Body,{className:`flex min-h-0 flex-col gap-3`,children:[(0,U.jsxs)(Vg,{className:`self-start`,size:r===`mobile`?`sm`:`md`,onPress:()=>_(null),children:[(0,U.jsx)(Hj,{className:`size-4`}),`添加推送目标`]}),(0,U.jsx)(mR,{device:r,mappings:m.mappings,onEdit:e=>_(e),onRemove:e=>{s(t=>t.filter(t=>t!==e)),l(t=>{let n={...t};return delete n[e],n})}})]}),(0,U.jsxs)(pv.Footer,{children:[(0,U.jsx)(Vg,{size:r===`mobile`?`sm`:`md`,slot:`close`,variant:`secondary`,children:`取消`}),(0,U.jsx)(Vg,{size:r===`mobile`?`sm`:`md`,slot:`close`,onPress:()=>{a(m.values)},children:`完成`})]})]})})}),(0,U.jsx)(gR,{device:r,initialMapping:g,isOpen:f,onConfirm:e=>{let t=dR(e),n=[...o],r=u?n.indexOf(u):-1;r>=0?n[r]=t:n.unshift(t),s(pR(n)),l(n=>{let r={...n,[t]:e};return u&&u!==t&&delete r[u],r}),p(!1),d(null)},onOpenChange:p},u||`new`)]})},yR=(e,t)=>{let n=fR(e);if(!n)return null;let r={groupId:n.groupId,botId:n.botId};return t?.groupName&&(r.groupName=t.groupName),t?.groupAvatar&&(r.groupAvatar=t.groupAvatar),t?.botName&&(r.botName=t.botName),t?.botAvatar&&(r.botAvatar=t.botAvatar),t?.isOnline!==void 0&&(r.isOnline=t.isOnline),r},bR=({value:e,disabled:t,itemLabel:n,device:r,onChange:i})=>{let a=(0,v.useMemo)(()=>pR(e),[e]),o=(0,v.useMemo)(()=>e.filter(e=>!fR(e)),[e]),[s,c]=(0,v.useState)([]),[l,u]=(0,v.useState)(!1),[d,f]=(0,v.useState)(!1),p=(0,v.useMemo)(()=>a.map(e=>{let t=fR(e);return yR(e,t?s.find(e=>e.groupId===t.groupId&&e.botId===t.botId):void 0)}).filter(e=>!!e),[s,a]);(0,v.useEffect)(()=>{lR(a.map(fR).filter(e=>!!e)).then(c).catch(()=>c([])).finally(()=>u(!1))},[a]);let m=e=>i(pR(e)),h=`开启【${n}】的推送开关后才能编辑此字段`,g=a.length>0?`已配置 ${a.length} 个推送目标`:`还没有配置推送目标`;return(0,U.jsx)(eR,{disabled:t,device:r,message:h,children:(0,U.jsxs)(`div`,{className:`space-y-3`,children:[(0,U.jsxs)(`div`,{className:`flex items-center justify-between gap-4 rounded-lg border border-default-200 bg-default-50/50 px-4 py-3`,children:[(0,U.jsxs)(`div`,{className:`flex flex-col min-w-0`,children:[(0,U.jsx)(dx,{children:`推送目标`}),(0,U.jsx)(px,{className:`mt-1`,children:g})]}),(0,U.jsxs)(Vg,{isDisabled:t,size:r===`mobile`?`sm`:`md`,variant:r===`mobile`?`primary`:`secondary`,onPress:()=>f(!0),children:[(0,U.jsx)(Vj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`管理`})]})]}),l?(0,U.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-muted`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取推送目标`}),(0,U.jsx)(`span`,{children:`正在读取推送目标`})]}):null,o.length>0?(0,U.jsxs)(`div`,{className:`rounded-lg border border-warning/30 bg-warning/10 p-3 text-sm`,children:[(0,U.jsxs)(`div`,{className:`flex items-center gap-2 font-medium text-warning`,children:[(0,U.jsx)(qj,{className:`size-4`}),(0,U.jsxs)(`span`,{children:[`发现 `,o.length,` 条旧格式或错误格式`]})]}),(0,U.jsx)(px,{className:`mt-1`,children:`建议删除后用可视化选择重新添加,避免后端解析异常。`})]}):null,(0,U.jsx)(vR,{device:r,isOpen:d,mappings:p,values:a,onApply:m,onOpenChange:f})]})})},xR=({disabled:e,itemLabel:t,device:n,value:r,onChange:i})=>(0,U.jsx)(bR,{disabled:e,device:n,itemLabel:t,value:r,onChange:i}),SR=({disabled:e,itemLabel:t,device:n,options:r,value:i,onChange:a})=>(0,U.jsx)(eR,{disabled:e,device:n,message:`开启【${t}】的推送开关后才能编辑此字段`,children:(0,U.jsxs)(c_,{"aria-label":`推送类型`,isDisabled:e,value:i,onChange:e=>a(e),children:[(0,U.jsx)(dx,{children:`推送类型`}),(0,U.jsx)(px,{children:`选择要推送的内容类型`}),(0,U.jsx)(`div`,{className:`mt-2 ${tR(n)}`,children:r.map(e=>(0,U.jsxs)(m_,{value:e.value,variant:`secondary`,children:[(0,U.jsxs)(m_.Content,{children:[(0,U.jsx)(m_.Control,{children:(0,U.jsx)(m_.Indicator,{})}),e.label]}),(0,U.jsx)(px,{children:e.description})]},e.value))})]})}),CR=({disabled:e,itemLabel:t,device:n,value:r,onChange:i})=>(0,U.jsx)(eR,{disabled:e,device:n,message:`开启【${t}】的推送开关后才能编辑此字段`,children:(0,U.jsxs)(Ax,{fullWidth:!0,isDisabled:e,value:r,onChange:e=>{e&&!Array.isArray(e)&&i(e)},children:[(0,U.jsx)(dx,{children:`过滤模式`}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),(0,U.jsx)(px,{children:`设置关键词/标签的过滤方式`}),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:iR.map(e=>(0,U.jsxs)(wx.Item,{id:e.value,textValue:e.label,children:[(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(dx,{children:e.label}),(0,U.jsx)(px,{children:e.description})]}),(0,U.jsx)(wx.ItemIndicator,{})]},e.value))})})]})}),wR=({disabled:e,itemLabel:t,device:n,keywords:r,tags:i,onKeywordsChange:a,onTagsChange:o})=>{let s=`开启【${t}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(eR,{disabled:e,device:n,message:s,children:(0,U.jsx)(`div`,{children:(0,U.jsx)(aR,{label:`关键词`,description:`多个关键词用于内容过滤`,disabled:e,items:r,onAdd:e=>a([...r,e]),onRemove:e=>a(r.filter(t=>t!==e))})})}),(0,U.jsx)(eR,{disabled:e,device:n,message:s,children:(0,U.jsx)(`div`,{children:(0,U.jsx)(aR,{label:`标签`,description:`多个标签用于内容过滤`,disabled:e,items:i,onAdd:e=>o([...i,e]),onRemove:e=>o(i.filter(t=>t!==e))})})})]})},TR=({onDelete:e})=>(0,U.jsxs)(Vg,{className:`w-full`,variant:`danger`,onPress:e,children:[(0,U.jsx)(Kj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`删除此推送项`})]}),ER=({item:e,index:t,list:n,onChange:r,device:i})=>{let a=i=>{let a=[...n];a[t]={...e,...i},r(a)},o=!e.switch,s=e.remark||`UID: ${e.host_mid}`||`未命名`,c=`开启【${s}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(Fc.Item,{id:`bilibili-${t}`,children:[(0,U.jsx)(Fc.Heading,{children:(0,U.jsxs)(Fc.Trigger,{children:[(0,U.jsxs)(`div`,{className:`flex flex-1 items-center gap-3`,children:[(0,U.jsx)(`div`,{onClick:e=>e.stopPropagation(),onPointerDown:e=>e.stopPropagation(),children:(0,U.jsx)(ob,{"aria-label":`推送开关`,isSelected:e.switch,onChange:e=>a({switch:e}),children:(0,U.jsx)(ob.Content,{children:(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})})})})}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(`span`,{className:`font-medium`,children:e.remark||`UID: ${e.host_mid}`||`推送项 ${t+1}`}),(0,U.jsxs)(px,{className:`text-xs`,children:[`B站 UID: `,e.host_mid]})]})]}),(0,U.jsx)(Fc.Indicator,{children:(0,U.jsx)(Pj,{className:`size-5`})})]})}),(0,U.jsx)(Fc.Panel,{children:(0,U.jsx)(Fc.Body,{children:(0,U.jsxs)(`div`,{className:`space-y-4`,children:[(0,U.jsxs)(`div`,{className:tR(i),children:[(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,isRequired:!0,type:`number`,value:String(e.host_mid),onChange:e=>a({host_mid:Number(e)||0}),children:[(0,U.jsx)(dx,{children:`B站 UID`}),(0,U.jsx)(cx,{placeholder:`UP主的 UID`}),(0,U.jsx)(px,{children:`B站用户的唯一标识,必填`})]})}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.remark,onChange:e=>a({remark:e}),children:[(0,U.jsx)(dx,{children:`备注名称`}),(0,U.jsx)(cx,{placeholder:`可选,用于识别该推送项`}),(0,U.jsx)(px,{children:`方便识别的名称,如:UP主昵称`})]})})]}),(0,U.jsx)(xR,{disabled:o,device:i,itemLabel:s,value:e.group_id,onChange:e=>a({group_id:e})}),(0,U.jsx)(SR,{disabled:o,device:i,itemLabel:s,options:rR,value:e.pushTypes||[],onChange:e=>a({pushTypes:e})}),(0,U.jsx)(CR,{disabled:o,device:i,itemLabel:s,value:e.filterMode||`blacklist`,onChange:e=>a({filterMode:e})}),(0,U.jsx)(wR,{disabled:o,device:i,itemLabel:s,keywords:e.Keywords||[],tags:e.Tags||[],onKeywordsChange:e=>a({Keywords:e}),onTagsChange:e=>a({Tags:e})}),(0,U.jsx)(TR,{onDelete:()=>r(n.filter((e,n)=>n!==t))})]})})})]},t)},DR=({item:e,index:t,list:n,onChange:r,device:i})=>{let a=i=>{let a=[...n];a[t]={...e,...i},r(a)},o=!e.switch,s=e.remark||e.short_id||e.sec_uid||`未命名`,c=`开启【${s}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(Fc.Item,{id:`douyin-${t}`,children:[(0,U.jsx)(Fc.Heading,{children:(0,U.jsxs)(Fc.Trigger,{children:[(0,U.jsxs)(`div`,{className:`flex flex-1 items-center gap-3`,children:[(0,U.jsx)(`div`,{onClick:e=>e.stopPropagation(),onPointerDown:e=>e.stopPropagation(),children:(0,U.jsx)(ob,{"aria-label":`推送开关`,isSelected:e.switch,onChange:e=>a({switch:e}),children:(0,U.jsx)(ob.Content,{children:(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})})})})}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(`span`,{className:`font-medium`,children:e.remark||e.short_id||e.sec_uid||`推送项 ${t+1}`}),(0,U.jsxs)(px,{className:`text-xs`,children:[e.short_id&&`抖音号: ${e.short_id}`,e.sec_uid&&!e.short_id&&`sec_uid: ${e.sec_uid.slice(0,20)}...`]})]})]}),(0,U.jsx)(Fc.Indicator,{children:(0,U.jsx)(Pj,{className:`size-5`})})]})}),(0,U.jsx)(Fc.Panel,{children:(0,U.jsx)(Fc.Body,{children:(0,U.jsxs)(`div`,{className:`space-y-4`,children:[(0,U.jsxs)(`div`,{className:tR(i),children:[(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,isRequired:!0,value:e.short_id,onChange:e=>a({short_id:e}),children:[(0,U.jsx)(dx,{children:`抖音号`}),(0,U.jsx)(cx,{placeholder:`用户的抖音号`,variant:`secondary`}),(0,U.jsx)(px,{children:`用户的抖音号(short_id),必填`})]})}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.sec_uid,onChange:e=>a({sec_uid:e}),children:[(0,U.jsx)(dx,{children:`sec_uid`}),(0,U.jsx)(cx,{placeholder:`选填,会根据抖音号自动获取`,variant:`secondary`}),(0,U.jsx)(px,{children:`用户的 sec_uid,可从分享链接获取。选填,推送时会自动获取`})]})})]}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.remark,onChange:e=>a({remark:e}),children:[(0,U.jsx)(dx,{children:`备注名称`}),(0,U.jsx)(cx,{placeholder:`可选,用于识别该推送项`,variant:`secondary`}),(0,U.jsx)(px,{children:`方便识别的名称,如:博主昵称`})]})}),(0,U.jsx)(xR,{disabled:o,device:i,itemLabel:s,value:e.group_id,onChange:e=>a({group_id:e})}),(0,U.jsx)(SR,{disabled:o,device:i,itemLabel:s,options:nR,value:e.pushTypes||[],onChange:e=>a({pushTypes:e})}),(0,U.jsx)(CR,{disabled:o,device:i,itemLabel:s,value:e.filterMode||`blacklist`,onChange:e=>a({filterMode:e})}),(0,U.jsx)(wR,{disabled:o,device:i,itemLabel:s,keywords:e.Keywords||[],tags:e.Tags||[],onKeywordsChange:e=>a({Keywords:e}),onTagsChange:e=>a({Tags:e})}),(0,U.jsx)(TR,{onDelete:()=>r(n.filter((e,n)=>n!==t))})]})})})]},t)},OR=()=>({switch:!0,sec_uid:``,short_id:``,group_id:[],remark:``,pushTypes:[`post`],filterMode:`blacklist`,Keywords:[],Tags:[]}),kR=()=>({switch:!0,host_mid:0,group_id:[],remark:``,pushTypes:[`video`],filterMode:`blacklist`,Keywords:[],Tags:[]}),AR=({platform:e})=>(0,U.jsx)(`div`,{className:`rounded-lg border-2 border-dashed border-gray-300 p-8 text-center`,children:(0,U.jsxs)(`p`,{className:`text-muted`,children:[`暂无`,e===`douyin`?`抖音`:`B站`,`推送项,点击上方按钮添加`]})});function jR({douyinList:e,bilibiliList:t,onDouyinChange:n,onBilibiliChange:r,device:i}){let[a,o]=(0,v.useState)(`douyin`);return(0,U.jsx)(`div`,{className:`space-y-4`,children:(0,U.jsxs)(kb,{selectedKey:a,onSelectionChange:e=>o(e),children:[(0,U.jsx)(kb.ListContainer,{children:(0,U.jsxs)(kb.List,{children:[(0,U.jsxs)(kb.Tab,{id:`douyin`,children:[(0,U.jsx)(`span`,{children:`抖音推送`}),(0,U.jsx)(kb.Indicator,{})]}),(0,U.jsxs)(kb.Tab,{id:`bilibili`,children:[(0,U.jsx)(`span`,{children:`B站推送`}),(0,U.jsx)(kb.Indicator,{})]})]})}),(0,U.jsx)(kb.Panel,{id:`douyin`,children:(0,U.jsxs)(`div`,{className:`space-y-4 pt-4`,children:[(0,U.jsxs)(Vg,{className:`w-full`,variant:`primary`,size:`sm`,onPress:()=>n([...e,OR()]),children:[(0,U.jsx)(Hj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`添加抖音推送项`})]}),e.length>0?(0,U.jsx)(Fc,{variant:`surface`,"aria-label":`抖音推送列表`,children:e.map((t,r)=>(0,U.jsx)(DR,{device:i,index:r,item:t,list:e,onChange:n},r))}):(0,U.jsx)(AR,{platform:`douyin`})]})}),(0,U.jsx)(kb.Panel,{id:`bilibili`,children:(0,U.jsxs)(`div`,{className:`space-y-4 pt-4`,children:[(0,U.jsxs)(Vg,{className:`w-full`,variant:`primary`,onPress:()=>r([...t,kR()]),children:[(0,U.jsx)(Hj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`添加B站推送项`})]}),t.length>0?(0,U.jsx)(Fc,{variant:`surface`,"aria-label":`B站推送列表`,children:t.map((e,n)=>(0,U.jsx)(ER,{device:i,index:n,item:e,list:t,onChange:r},n))}):(0,U.jsx)(AR,{platform:`bilibili`})]})})]})})}var MR=({config:e,device:t,renderers:n,updateConfigValue:r})=>{let{renderPageHeader:i}=n;return(0,U.jsxs)(U.Fragment,{children:[i(`推送列表`,`管理「抖音」与「哔哩哔哩」的推送订阅。`),(0,U.jsx)(jR,{douyinList:e.pushlist?.douyin||[],bilibiliList:e.pushlist?.bilibili||[],onDouyinChange:e=>{r([`pushlist`,`douyin`],e)},onBilibiliChange:e=>{r([`pushlist`,`bilibili`],e)},device:t})]})},NR=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderPageHeader:i,renderSelectField:a,renderSubSection:o,renderSwitch:s,renderTextField:c}=t,l=Q(e,[`xiaohongshu`,`switch`],!1),u=Q(e,[`xiaohongshu`,`sendContent`],[]),d=Q(e,[`xiaohongshu`,`videoQuality`],`adapt`);return(0,U.jsxs)(U.Fragment,{children:[i(`小红书`,`小红书解析基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[s([`xiaohongshu`,`switch`],`解析开关`,`小红书解析开关,此开关为单独开关。`),r([`xiaohongshu`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL,!l),c([`xiaohongshu`,`numcomment`],`评论解析数量`,`小红书评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:!l||!_L(u,`comment`)})]}),o(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[a([`xiaohongshu`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,NL,e=>e,!l),c([`xiaohongshu`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!l||d!==`adapt`})]}))]})},/*KKK-QQ-START*/KKKQQConfig=({config:e,renderers:t})=>{let{renderPageHeader:n,renderSubSection:r,renderSwitch:i,renderTextField:a}=t;return(0,U.jsxs)(U.Fragment,{children:[n(`QQ 适配器`,`这些设置只对 QQ 平台生效,其它平台不受影响。改完点右下角保存即可,不用重启。`),r(`解析面板`,(0,U.jsx)(U.Fragment,{children:[i([`qq`,`qqPanel`],`链接解析面板`,`QQ 里收到链接时先回一条带按钮的面板,让用户自己挑解析内容和画质,点一下才开始下载。关掉就直接按默认配置解析。`),a([`qq`,`qqFileLimitMB`],`画质档体积上限(MB)`,`面板里「清晰度」(= 发到 QQ)这一列的体积上限:超过它的画质档不给发送按钮,那一格标「超上限」。QQ 单个视频上限 200MB,选了也发不出去,所以默认 200。**在线播放模式下画质档位不再按这个值过滤**:视频根本不发到 QQ,所有档位都会列出来,超过这个值的档位只是不能发到 QQ,右边的「在线看」照常可用(它受「在线播放最大文件」约束)。`,{type:`number`,fallback:200,min:1,max:2000}),i([`qq`,`qqPanelDanmaku`],`面板显示「烧录弹幕」列`,`只对**烧录模式**生效(通用里把「弹幕重定向在线播放器」关掉之后):打开后,QQ 里的解析面板会多一列「烧录弹幕」,用户点它就按那一档画质把弹幕烧进视频再发。在线播放模式下那一列由「弹幕重定向在线播放器」自己控制(开着就有),不需要在这里开。`),i([`qq`,`qqPanelSourceLink`],`面板带「打开原站」链接`,`打开后,解析面板(以及番剧选集面板)的下方会多一个「打开原站」按钮,点一下直接跳到抖音 / B站的原作品页;关掉就不显示。`)]})),r(`番剧选集面板`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`bangumiPanelCols`],`表格列数`,`番剧分集面板每行放几个集数,默认 5。`,{type:`number`,fallback:5,min:1,max:10}),a([`qq`,`bangumiPanelRows`],`表格行数`,`番剧分集面板每页几行(含表头那一行),默认 4 行。列数 × 行数就是每页的集数。`,{type:`number`,fallback:4,min:1,max:10})]})),r(`图片发送`,(0,U.jsx)(U.Fragment,{children:[i([`qq`,`sliceImageOnDemand`],`超大图片自动切片`,`长图(评论区那种)默认按普通图片发;只有超过 20MB 或者发送失败(拿不到消息 ID)时才自动切成几片,再用一条 markdown 拼回一整张。关掉就一律按普通图片发。`),a([`qq`,`sliceImageHeight`],`切片高度(像素)`,`切片时每片的高度,默认 2000。越大片数越少、字越小;越小越清晰、片数越多。`,{type:`number`,fallback:2000,min:500,max:4000})]})),r(`卡片识别`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`ocrApiKey`],`卡片文字识别密钥`,`群里转发过来的分享卡片没有链接,只能靠截图识别出标题和作者再去搜索。填自己的免费密钥更稳定:https://ocr.space/ocrapi 。留空会用公共测试密钥,容易被限流。`,{type:`password`,placeholder:`留空则使用公共测试密钥`})]})),r(`视频发送`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`qqGroupFileLimitMB`],`群文件发送阈值(MB)`,`视频体积超过这个值时,改用「群文件」发送。QQ 对富媒体视频会压缩、改名甚至丢掉后缀,走群文件才能原样发出去;填 0 表示不启用。`,{type:`number`,fallback:30,min:0,max:2000})]}))]})}/*KKK-QQ-END*/,PR=e=>{switch(e.activeFile){case`amagi`:return(0,U.jsx)(YL,{...e});case`app`:return(0,U.jsx)(XL,{...e});case`douyin`:return(0,U.jsx)(QL,{...e});case`bilibili`:return(0,U.jsx)(ZL,{...e});case`kuaishou`:return(0,U.jsx)($L,{...e});case`xiaohongshu`:return(0,U.jsx)(NR,{...e});case`pushlist`:return(0,U.jsx)(MR,{...e});case`qq`:return(0,U.jsx)(KKKQQConfig,{...e})}},FR=(e,t)=>{let n=Number(e);return Number.isFinite(n)?t.min!==void 0&&n<t.min?t.error||`${t.label} 不能小于 ${t.min}`:t.max!==void 0&&n>t.max?t.error||`${t.label} 不能大于 ${t.max}`:``:`${t.label} 必须是数字`},IR=(e,t,n)=>{if(n.disabled)return;let r=FR(Q(t,n.path,0),n);r&&(e[pL(n.path)]=r)},LR=e=>typeof e==`string`&&/.+:.+/.test(e),RR=(e,t,n)=>{if(!Array.isArray(n)){e[`pushlist.${t}`]=`${t} 推送列表必须是数组`;return}let r=n.findIndex(e=>{if(!mL(e))return!0;let n=e.group_id,r=t===`douyin`?e.short_id:e.host_mid;return r==null||String(r).trim()===``||!Array.isArray(n)||n.length===0||n.some(e=>!LR(e))});r>=0&&(e[`pushlist.${t}`]=`${t} 推送列表第 ${r+1} 项缺少必填 UID/抖音号,或 group_id 未使用「群号:机器人账号」格式`)},zR=e=>{if(!e)return{};let t={},n=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`),r=Q(e,[`amagi`,`APIServerMount`],!1),i=Q(e,[`app`,`videoSendMode`],`file`),a=Q(e,[`app`,`usegroupfile`],!1),o=Q(e,[`app`,`usefilelimit`],!1),s=Q(e,[`app`,`compress`],!1),c=Q(e,[`app`,`downloadThrottle`],!1),l=Q(e,[`app`,`downloadAutoReduce`],!1),u=Q(e,[`amagi`,`proxy`,`switch`],!1),d=Q(e,[`douyin`,`switch`],!1),f=Q(e,[`douyin`,`sendContent`],[]),p=Q(e,[`douyin`,`burnDanmaku`],!1),m=Q(e,[`douyin`,`videoQuality`],`adapt`),h=Q(e,[`douyin`,`push`,`switch`],!1),g=Q(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`),_=Q(e,[`bilibili`,`switch`],!1),v=Q(e,[`bilibili`,`sendContent`],[]),y=Q(e,[`bilibili`,`burnDanmaku`],!1),b=Q(e,[`bilibili`,`videoQuality`],0),x=Q(e,[`bilibili`,`push`,`switch`],!1),S=Q(e,[`bilibili`,`push`,`parsedynamic`],!1),C=Q(e,[`bilibili`,`push`,`pushVideoQuality`],0),w=Q(e,[`kuaishou`,`switch`],!1),T=Q(e,[`kuaishou`,`comment`],!1),E=Q(e,[`xiaohongshu`,`switch`],!1),D=Q(e,[`xiaohongshu`,`sendContent`],[]),O=Q(e,[`xiaohongshu`,`videoQuality`],`adapt`);return[{path:[`app`,`renderScale`],label:`渲染精度`,min:50,max:200},{path:[`app`,`ambientCover`,`coverOpacity`],label:`封面氛围强度`,min:0,max:1},{path:[`app`,`ambientCover`,`overlayEdgeOpacity`],label:`氛围压色(顶部/底部)`,min:0,max:1},{path:[`app`,`ambientCover`,`overlayMiddleOpacity`],label:`氛围压色(中间带)`,min:0,max:1},{path:[`app`,`RenderWaitTime`],label:`渲染图片的等待时间`,min:0},{path:[`app`,`multiPageHeight`],label:`分页渲染时,每页的高度`,min:1e3,max:2e4,disabled:!Q(e,[`app`,`multiPageRender`],!0),error:`请输入一个范围在 1000 到 20000 之间的数字`},{path:[`amagi`,`APIServerPort`],label:`API服务端口`,min:1024,max:65535,disabled:r,error:`请输入一个范围在 1024 到 65535 之间的数字`},{path:[`app`,`groupfilevalue`],label:`群文件上传阈值`,min:1,disabled:!a||i===`base64`},{path:[`app`,`filelimit`],label:`视频拦截阈值`,min:1,disabled:!o},{path:[`app`,`compresstrigger`],label:`压缩触发阈值`,min:1,disabled:!s},{path:[`app`,`compressvalue`],label:`压缩后的值`,min:1,disabled:!s},{path:[`app`,`downloadMaxSpeed`],label:`最大下载速度`,min:1,max:1e3,disabled:!c,error:`请输入一个范围在 1 到 1000 之间的数字`},{path:[`app`,`downloadMinSpeed`],label:`最低下载速度`,min:.1,max:100,disabled:!c||!l,error:`请输入一个范围在 0.1 到 100 之间的数字`},{path:[`amagi`,`timeout`],label:`请求超时时间`,min:1e3,max:3e5,error:`请输入一个范围在 1000 到 300000 之间的数字`},{path:[`amagi`,`proxy`,`port`],label:`代理端口`,min:1,max:65535,disabled:!u,error:`请输入一个范围在 1 到 65535 之间的数字`},{path:[`douyin`,`numcomment`],label:`评论解析数量`,min:1,disabled:!d||!_L(f,`comment`)},{path:[`douyin`,`subCommentLimit`],label:`次级评论解析数量`,min:1,max:20,disabled:!d||!_L(f,`comment`)},{path:[`douyin`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!d||m!==`adapt`},{path:[`douyin`,`danmakuOpacity`],label:`弹幕透明度`,min:0,max:100,disabled:!d||!p},{path:[`douyin`,`push`,`pushMaxAutoVideoSize`],label:`推送视频体积上限(MB)`,min:1,max:2e4,disabled:!h||g!==`adapt`},{path:[`bilibili`,`numcomment`],label:`评论解析数量`,min:1,disabled:!_||!_L(v,`comment`)},{path:[`bilibili`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!_||Number(b)!==0},{path:[`bilibili`,`danmakuOpacity`],label:`弹幕透明度`,min:0,max:100,disabled:!_||!y},{path:[`bilibili`,`push`,`pushMaxAutoVideoSize`],label:`视频动态的视频体积上限(MB)`,min:1,max:2e4,disabled:!x||!S||Number(C)!==0},{path:[`kuaishou`,`numcomment`],label:`评论解析数量`,min:1,disabled:!w||!T},{path:[`xiaohongshu`,`numcomment`],label:`评论解析数量`,min:1,disabled:!E||!_L(D,`comment`)},{path:[`xiaohongshu`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!E||O!==`adapt`}].forEach(n=>IR(t,e,n)),n===`video_only`&&delete t[`app.livePhotoSystem`],RR(t,`douyin`,e.pushlist?.douyin||[]),RR(t,`bilibili`,e.pushlist?.bilibili||[]),t},BR=({device:e=`desktop`})=>{let t=(0,v.useRef)(null),[n,r]=JT(),i=Px(),a=n.get(`file`),[o,s]=GS({config:null,savedConfig:null,activeFile:a&&HL.some(e=>e.key===a)?a:`amagi`}),{activeFile:c,config:l,savedConfig:u}=o,d=(0,v.useMemo)(()=>JL(e),[e]),f=e===`mobile`?`sm`:`md`,{loading:p,run:m}=HS(iI,{onSuccess:e=>{s({config:structuredClone(e),savedConfig:structuredClone(e)})},onError:e=>{Ny.danger(`加载配置失败`,{description:e.message})}}),{loading:h,runAsync:g}=HS(aI,{manual:!0}),_=(0,v.useMemo)(()=>!l||!u?!1:!(0,mE.default)(yL(l),yL(u)),[l,u]),y=(0,v.useMemo)(()=>zR(l),[l]),b=(0,v.useMemo)(()=>Object.values(y).some(Boolean),[y]),x=(0,v.useMemo)(()=>_&&!b&&!p,[_,b,p]),S=Ux((e,t)=>{s(n=>n.config?{config:hL(n.config,e,t)}:null)}),C=Ux(()=>{if(!l||b)return;let e=l,t=g(e).then(()=>{s({savedConfig:e})});Ny.promise(t,{loading:`正在保存配置...`,success:`配置已保存`,error:e=>e instanceof Error?e.message:`保存配置失败`})}),w=Ux(()=>{m()}),T=Ux(e=>{r({file:e})}),E=Ux(e=>{e.preventDefault(),C()});(0,v.useEffect)(()=>{let e=n.get(`file`);e&&HL.some(t=>t.key===e)&&e!==c&&s({activeFile:e})},[n,c,s]),(0,v.useEffect)(()=>{let e=t.current?.querySelector(`[data-config-tabs-scroll="true"]`);if(!e)return;let n=t=>{let n=Math.abs(t.deltaX)>Math.abs(t.deltaY)?t.deltaX:t.deltaY;n&&(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),!(e.scrollWidth<=e.clientWidth)&&(e.scrollLeft+=n))};return e.addEventListener(`wheel`,n,{passive:!1}),()=>{e.removeEventListener(`wheel`,n)}},[l]);let D=Ux(()=>{t.current&&Sj.fromTo(t.current.querySelectorAll(`[data-config-section]`),uI,{...dI,duration:sI(.35),stagger:cI(.03)})});(0,v.useEffect)(()=>{!l||t.current?.dataset.animated===`true`||(t.current&&(t.current.dataset.animated=`true`),D())},[l,D]),Wx(()=>{D()},[c]);let O=(0,v.useMemo)(()=>l?GL({config:l,device:e,classes:d,validationErrors:y,updateConfigValue:S}):{},[l,e,d,y,S]);if(p||!l)return(0,U.jsxs)(`div`,{className:`${d.root} ${d.loading}`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取配置`}),(0,U.jsx)(`span`,{children:`正在读取配置`})]});let k=(0,U.jsx)(`div`,{className:d.floatingActions,children:(0,U.jsxs)(`div`,{className:d.actionControls,children:[(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`重新读取配置`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:f,variant:`secondary`,isDisabled:p||h,onPress:w,children:(0,U.jsx)(Uj,{size:16,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`bottom`,children:[(0,U.jsx)(tx.Arrow,{}),`重新读取`]})]}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`查看配置变更`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:f,variant:`secondary`,isDisabled:!_,onPress:i.open,children:(0,U.jsx)(Lj,{size:16,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`bottom`,children:[(0,U.jsx)(tx.Arrow,{}),`查看变更`]})]}),(0,U.jsxs)(Vg,{size:f,isDisabled:!x,isPending:h,onPress:C,variant:`primary`,children:[(0,U.jsx)(Wj,{size:16,"aria-hidden":`true`}),(0,U.jsx)(`span`,{children:`保存`})]})]})});return(0,U.jsxs)(`div`,{ref:t,className:d.root,children:[(0,U.jsx)(TL,{device:e,original:u,current:l,isOpen:i.isOpen,onOpenChange:i.setOpen}),(0,U.jsxs)(_x,{className:d.form,onSubmit:E,children:[(0,U.jsx)(kb,{className:`w-full min-w-0 max-w-full`,selectedKey:c,onSelectionChange:T,children:(0,U.jsx)(kb.ListContainer,{className:d.tabsListContainer,"data-config-tabs-scroll":`true`,"data-scrollbar":`none`,children:(0,U.jsx)(kb.List,{"aria-label":`配置文件选择`,className:d.tabsList,children:HL.map((e,t)=>(0,U.jsxs)(kb.Tab,{id:e.key,children:[t>0?(0,U.jsx)(kb.Separator,{}):null,(0,U.jsx)(`span`,{className:`whitespace-nowrap`,children:e.label}),(0,U.jsx)(kb.Indicator,{})]},e.key))})})}),(0,U.jsxs)(`div`,{className:`relative min-w-0 max-w-full`,children:[k,(0,U.jsx)(PR,{activeFile:c,classes:d,config:l,device:e,renderers:O,updateConfigValue:S},c)]})]})]})},VR=({onLogin:e})=>{let[t,n]=GS({authKey:``,loading:!1,error:``}),[r,{toggle:i}]=WS(!1),a=r?`隐藏密钥`:`显示密钥`,o=Ux(async r=>{r.preventDefault();let i=t.authKey.trim();if(!i){n({error:`请输入 Koishi HTTP 鉴权密钥`});return}try{n({loading:!0,error:``}),await tI(i),e()}catch(e){n({error:e instanceof Error?e.message:`登录失败`})}finally{n({loading:!1})}});return(0,U.jsx)(Ev,{className:`flex min-h-screen items-center justify-center px-4 py-8`,children:(0,U.jsxs)(Wg,{className:`w-full max-w-105`,children:[(0,U.jsxs)(Wg.Header,{className:`gap-4 p-6`,children:[(0,U.jsx)(zj,{className:`size-8 shrink-0`,"aria-hidden":`true`}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(Wg.Title,{children:`Koishi 鉴权`}),(0,U.jsx)(Wg.Description,{children:`使用 Koishi HTTP 鉴权密钥登录后管理 KKK 配置。`})]})]}),(0,U.jsx)(Wg.Content,{className:`p-6`,children:(0,U.jsxs)(_x,{className:`flex flex-col gap-6`,onSubmit:o,children:[(0,U.jsxs)(lx,{fullWidth:!0,isInvalid:!!t.error,value:t.authKey,onChange:e=>{n({authKey:e,error:t.error?``:t.error})},children:[(0,U.jsx)(dx,{children:`HTTP 鉴权密钥`}),(0,U.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,U.jsx)(cx,{autoComplete:`current-password`,className:`min-w-0 flex-1`,placeholder:`请输入 Koishi 的 HTTP_AUTH_KEY`,type:r?`text`:`password`}),(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":a,type:`button`,variant:`tertiary`,onPress:i,children:r?(0,U.jsx)(Fj,{className:`size-4`,"aria-hidden":`true`}):(0,U.jsx)(Ij,{className:`size-4`,"aria-hidden":`true`})})]}),(0,U.jsx)(px,{children:t.error||`生产环境会复用 Koishi 主 Web 已保存的登录凭据。`})]}),(0,U.jsx)(Vg,{fullWidth:!0,isPending:t.loading,type:`submit`,children:({isPending:e})=>(0,U.jsxs)(U.Fragment,{children:[e?(0,U.jsx)(Tv,{color:`current`,size:`sm`,"aria-label":`登录中`}):(0,U.jsx)(Bj,{className:`size-4`,"aria-hidden":`true`}),(0,U.jsx)(`span`,{children:`登录`})]})})]})})]})})},HR=`theme`,UR=`kkk-theme-changed`,WR=`karin-theme-change`,GR={light:`light`,dark:`dark`,system:`system`,inverse:`inverse`},KR=e=>e===GR.system||e===GR.inverse,qR=e=>e===GR.light||e===GR.dark,JR=e=>!e||typeof e!=`object`?!1:e.type===WR,YR=()=>{let e=localStorage.getItem(HR);if(KR(e))return e;try{let t=JSON.parse(e??``);if(KR(t))return t}catch{}return localStorage.setItem(HR,GR.system),GR.system},XR=()=>window.matchMedia(`(prefers-color-scheme: dark)`).matches?GR.dark:GR.light,ZR=()=>window.matchMedia(`(prefers-color-scheme: dark)`).matches?GR.light:GR.dark,QR=e=>e===GR.system?XR():ZR(),$R=e=>ez(QR(e)),ez=e=>(document.documentElement.classList.remove(GR.light,GR.dark),document.documentElement.classList.add(e),document.documentElement.dataset.theme=e,e),tz=()=>{let[e,t]=(0,v.useState)(()=>YR()),[n,r]=(0,v.useState)(()=>QR(e)),i=(0,v.useRef)(!1),a=(0,v.useCallback)(e=>{localStorage.setItem(HR,e),t(e),r($R(e)),window.dispatchEvent(new CustomEvent(UR,{detail:e}))},[]),o=(0,v.useCallback)(()=>{a(GR.system)},[a]),s=(0,v.useCallback)(()=>{a(GR.inverse)},[a]),c=(0,v.useCallback)(()=>{a(e===GR.system?GR.inverse:GR.system)},[a,e]);return(0,v.useEffect)(()=>{i.current?i.current=!1:r($R(e));let n=window.matchMedia(`(prefers-color-scheme: dark)`),a=()=>{r($R(e))},o=e=>{if(e.key!==HR||window.self!==window.top)return;let n=YR();t(n),r($R(n))},s=e=>{let n=e.detail;KR(n)&&(t(n),r($R(n)))},c=e=>{if(!JR(e.data))return;let n=e.data.theme,a=KR(n??null)?n:YR(),o=qR(e.data.appliedTheme)?e.data.appliedTheme:QR(a);i.current=!0,localStorage.setItem(HR,a),t(a),r(ez(o))};return n.addEventListener(`change`,a),window.addEventListener(`storage`,o),window.addEventListener(UR,s),window.addEventListener(`message`,c),()=>{n.removeEventListener(`change`,a),window.removeEventListener(`storage`,o),window.removeEventListener(UR,s),window.removeEventListener(`message`,c)}},[e]),{theme:e,appliedTheme:n,isDark:(0,v.useMemo)(()=>n===GR.dark,[n]),isLight:(0,v.useMemo)(()=>n===GR.light,[n]),isSystem:e===GR.system,isInverse:e===GR.inverse,setSystemTheme:o,setInverseTheme:s,toggleTheme:c}},nz=()=>document.documentElement.clientWidth||window.innerWidth,rz=(e=nz())=>e<=768?`mobile`:`desktop`,iz=()=>{let e=navigator.userAgent.toLowerCase();return[`android`,`webos`,`iphone`,`ipad`,`ipod`,`blackberry`,`windows phone`,`mobile`].some(t=>e.includes(t))},az=()=>{let e=rz();return iz()||e===`mobile`?`mobile`:`desktop`},oz=()=>YS(()=>import(`./DesktopLayout-iI43ij11.js`),__vite__mapDeps([2,1,3])),sz=()=>YS(()=>import(`./MobileLayout-CziU8MCR.js`),__vite__mapDeps([4,3])),cz={config:`/kkk/assets/config`,about:`/kkk/assets/about`},lz={"/kkk/assets/config":`config`,"/kkk/assets/about":`about`},uz=({device:e})=>(0,U.jsxs)(Ev,{className:`h-screen overflow-hidden bg-background`,children:[(0,U.jsx)(qy.Provider,{placement:`top`}),(0,U.jsx)(bv,{hideScrollBar:!0,className:`h-full px-3 py-3 sm:px-5 sm:py-4 ${e===`mobile`?`data-[top-scroll=true]:mask-none data-[top-scroll=true]:[-webkit-mask-image:none] data-[top-bottom-scroll=true]:mask-[linear-gradient(180deg,black_calc(100%-var(--scroll-shadow-size)),transparent)] data-[top-bottom-scroll=true]:[-webkit-mask-image:linear-gradient(180deg,black_calc(100%-var(--scroll-shadow-size)),transparent)]`:``}`,size:56,children:(0,U.jsx)(BR,{device:e})})]}),dz=({LayoutComponent:e})=>{let t=vw(),n=xw(),r=lz[t.pathname]||`config`,i=Ux(e=>{n(cz[e])});return e?(0,U.jsxs)(`div`,{children:[(0,U.jsx)(qy.Provider,{placement:`top`}),(0,U.jsx)(e,{activeMenu:r,onMenuChange:i})]}):(0,U.jsxs)(Ev,{className:`flex min-h-screen items-center justify-center gap-4`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在加载布局`}),(0,U.jsx)(px,{children:`正在加载`})]})},fz=()=>{tz();let[e,t]=GS({authenticated:uE(),device:az(),LayoutComponent:null}),{authenticated:n,device:r,LayoutComponent:i}=e;(0,v.useEffect)(()=>{let e=()=>{t({authenticated:uE()})};return window.addEventListener(oE,e),window.addEventListener(`storage`,e),()=>{window.removeEventListener(oE,e),window.removeEventListener(`storage`,e)}},[t]);let a=Ux(()=>{let e=az();t(t=>t.device===e?null:{device:e,LayoutComponent:null})});(0,v.useEffect)(()=>{let e=0,t=()=>{window.cancelAnimationFrame(e),e=window.requestAnimationFrame(a)};return window.addEventListener(`resize`,t),window.addEventListener(`orientationchange`,t),()=>{window.cancelAnimationFrame(e),window.removeEventListener(`resize`,t),window.removeEventListener(`orientationchange`,t)}},[a]),(0,v.useEffect)(()=>{if(!n){t({LayoutComponent:null});return}let e=!1;return(async()=>{if(r===`mobile`){let n=await sz();e||t({LayoutComponent:n.default})}else{let n=await oz();e||t({LayoutComponent:n.default})}})(),()=>{e=!0}},[n,r,t]);let o=Ux(()=>{t({authenticated:!0})});return n?(0,U.jsxs)(Yw,{children:[(0,U.jsx)(qw,{path:`/kkk/assets/karin-config`,element:(0,U.jsx)(uz,{device:r})}),(0,U.jsx)(qw,{path:`/kkk/assets/config`,element:(0,U.jsx)(dz,{LayoutComponent:i})}),(0,U.jsx)(qw,{path:`/kkk/assets/about`,element:(0,U.jsx)(dz,{LayoutComponent:i})}),(0,U.jsx)(qw,{path:`/kkk/assets`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`/kkk`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`/kkk/login`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`*`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})})]}):(0,U.jsxs)(Yw,{children:[(0,U.jsx)(qw,{path:`/kkk/login`,element:(0,U.jsx)(VR,{onLogin:o})}),(0,U.jsx)(qw,{path:`*`,element:(0,U.jsx)(Kw,{to:`/kkk/login`,replace:!0})})]})};(0,y.createRoot)(document.getElementById(`root`)).render((0,U.jsx)(v.StrictMode,{children:(0,U.jsx)(()=>(0,U.jsx)(RT,{children:(0,U.jsx)(fz,{})}),{})}));export{Rs as $,hm as A,Le as At,rd as B,l as Bt,Wg as C,wt as Ct,jh as D,H as Dt,Ph as E,rt as Et,_f as F,E as Ft,Y as G,Vl as H,gf as I,M as It,tc as J,J as K,pf as L,O as Lt,om as M,ke as Mt,am as N,we as Nt,Sm as O,V as Ot,vf as P,R as Pt,qs as Q,df as R,h as Rt,Jg as S,kt as St,Ig as T,at as Tt,kc as U,ed as V,Ac as W,ec as X,nc as Y,Js as Z,gv as _,ga as _t,pE as a,Do as at,b_ as b,Yt as bt,Ax as c,q as ct,dx as d,Ja as dt,Es as et,lx as f,Qa as ft,Ev as g,ma as gt,kb as h,Xa as ht,Sj as i,Mo as it,sm as j,B as jt,mm as k,He as kt,wx as l,qa as lt,tx as m,$a as mt,BR as n,cs as nt,WS as o,wo as ot,cx as p,K as pt,sc as q,Mj as r,jo as rt,Ux as s,yo as st,tz as t,Ss as tt,px as u,Za as ut,pv as v,nn as vt,Vg as w,st as wt,S_ as x,Zt as xt,C_ as y,$t as yt,lf as z,d as zt};
47
+ </div>`),e.hasArrows=!0}format_textdiff(e,t){e.out(`<div class="jsondiffpatch-value">`),this.formatTextDiffString(e,t[0]),e.out(`</div>`)}};function sL(e){if(typeof e==`number`)return e;let t=String(e);for(let e of[[/&/g,`&amp;`],[/</g,`&lt;`],[/>/g,`&gt;`],[/'/g,`&apos;`],[/"/g,`&quot;`]])t=t.replace(e[0],e[1]);return t}var cL=function(e){let t=e||document,n=({textContent:e,innerText:t})=>e||t,r=(e,t,n)=>{let r=e.querySelectorAll(t);for(let e=0,t=r.length;e<t;e++)n(r[e])},i=({children:e},t)=>{for(let n=0,r=e.length;n<r;n++){let r=e[n];r&&t(r,n)}};r(t,`.jsondiffpatch-arrow`,({parentNode:e,children:t,style:r})=>{let a=e,o=t[0],s=o.children[1];o.style.display=`none`;let c=a.querySelector(`.jsondiffpatch-moved-destination`);if(!(c instanceof HTMLElement))return;let l=n(c),u=a.parentNode;if(!u)return;let d;if(i(u,e=>{e.getAttribute(`data-key`)===l&&(d=e)}),d)try{let e=d.offsetTop-a.offsetTop;o.setAttribute(`height`,`${Math.abs(e)+6}`),r.top=`${-8+(e>0?0:e)}px`;let t=e>0?`M30,0 Q-10,${Math.round(e/2)} 26,${e-4}`:`M30,${-e} Q-10,${Math.round(-e/2)} 26,4`;s.setAttribute(`d`,t),o.style.display=``}catch(e){console.debug(`[jsondiffpatch] error adjusting arrows: ${e}`)}})},lL=(e,t,n)=>{let r=t||document.body,i=`jsondiffpatch-unchanged-`,a={showing:`${i}showing`,hiding:`${i}hiding`,visible:`${i}visible`,hidden:`${i}hidden`},o=r.classList;if(!o)return;if(!n){o.remove(a.showing),o.remove(a.hiding),o.remove(a.visible),o.remove(a.hidden),e===!1&&o.add(a.hidden);return}e===!1?(o.remove(a.showing),o.add(a.visible),setTimeout(()=>{o.add(a.hiding)},10)):(o.remove(a.hiding),o.add(a.showing),o.remove(a.hidden));let s=setInterval(()=>{cL(r)},100);setTimeout(()=>{o.remove(a.showing),o.remove(a.hiding),e===!1?(o.add(a.hidden),o.remove(a.visible)):(o.add(a.visible),o.remove(a.hidden)),setTimeout(()=>{o.remove(a.visible),clearInterval(s)},n+400)},n)},uL=(e,t)=>lL(!1,e,t),dL;function fL(e,t){return dL||=new oL,dL.format(e,t)}var pL=e=>e.join(`.`),mL=e=>!!(e&&typeof e==`object`),Q=(e,t,n)=>e?t.reduce((e,t)=>{if(mL(e))return e[t]},e)??n:n,hL=(e,t,n)=>{let r=structuredClone(e),i=r;for(let e=0;e<t.length-1;e++){let n=t[e],r=i[n];mL(r)||(i[n]={}),i=i[n]}return i[t[t.length-1]]=n,r},gL=(e,t)=>{let n=Number(e);return Number.isFinite(n)?n:t},_L=(e,t)=>Array.isArray(e)&&e.includes(t),vL=e=>!!(e&&typeof e==`object`&&`description`in e),yL=e=>{if(!e||typeof e!=`object`)return e;let t=structuredClone(e);for(let{path:e,options:n}of[{path:[`bilibili`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`bilibili`,`displayContent`],options:[`cover`,`title`,`author`,`stats`,`desc`]},{path:[`bilibili`,`push`,`parseDynamicTypes`],options:[`DYNAMIC_TYPE_AV`,`DYNAMIC_TYPE_DRAW`,`DYNAMIC_TYPE_ARTICLE`]},{path:[`douyin`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`xiaohongshu`,`sendContent`],options:[`info`,`comment`,`video`,`image`]},{path:[`kuaishou`,`sendContent`],options:[`info`,`comment`,`video`,`image`]}]){let r=Q(t,e,null);if(!Array.isArray(r))continue;let i=n.filter(e=>r.includes(e)),a=t;for(let t=0;t<e.length-1;t++){let n=e[t];mL(a[n])||(a[n]={}),a=a[n]}a[e[e.length-1]]=i}return t},bL=e=>typeof e==`object`&&!!e,xL=e=>{let t={added:0,modified:0,deleted:0},n=e=>{if(bL(e)){if(Array.isArray(e)){e.length===1?t.added+=1:e.length===2?t.modified+=1:e.length===3&&e[2]===0&&(t.deleted+=1);return}for(let[t,r]of Object.entries(e))t!==`_t`&&n(r)}};return n(e),t},SL=({original:e,current:t,showUnchanged:n=!1})=>{let r=(0,v.useRef)(null),i=(0,v.useMemo)(()=>{if(!(!e||!t))return iL(yL(e),yL(t))},[e,t]),a=(0,v.useMemo)(()=>e?yL(e):void 0,[e]),o=(0,v.useMemo)(()=>{if(i)return fL(i,a)},[i,a]),s=(0,v.useMemo)(()=>xL(i),[i]);return(0,v.useEffect)(()=>{r.current&&(o?(r.current.innerHTML=o,n?lL(!0,r.current):uL(r.current)):r.current.innerHTML=``)},[o,n]),o?(0,U.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,U.jsx)(v_,{size:`sm`,color:`success`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`+ `,s.added,` 新增`]})}),(0,U.jsx)(v_,{size:`sm`,color:`warning`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`~ `,s.modified,` 修改`]})}),(0,U.jsx)(v_,{size:`sm`,color:`danger`,variant:`soft`,children:(0,U.jsxs)(v_.Label,{children:[`- `,s.deleted,` 删除`]})})]}),(0,U.jsx)(`div`,{className:`max-h-[60vh] overflow-auto rounded-xl border border-default-200 bg-surface p-4`,children:(0,U.jsx)(`div`,{ref:r,className:`min-w-fit`})})]}):(0,U.jsx)(`div`,{className:`flex flex-col items-center justify-center gap-2 py-10 text-center`,children:(0,U.jsx)(px,{className:`text-sm text-muted`,children:`当前没有检测到配置变更`})})},CL=`变更预览`,wL=`绿色 = 新增/改后的内容,红色 = 删除/改前的内容,灰色 = 没变化的内容。`,TL=({device:e,original:t,current:n,isOpen:r,onOpenChange:i})=>{let[a,o]=(0,v.useState)(!1),s=(0,U.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,U.jsx)(px,{className:`text-xs text-muted`,children:wL}),(0,U.jsx)(ob,{size:`sm`,isSelected:a,onChange:o,"aria-label":`显示未变更字段`,children:(0,U.jsxs)(ob.Content,{children:[(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})}),`显示未变更`]})})]}),(0,U.jsx)(SL,{original:t,current:n,showUnchanged:a})]}),c=(0,U.jsx)(Vg,{slot:`close`,size:`sm`,variant:`secondary`,children:`关闭`});return e===`mobile`?(0,U.jsx)(pv,{children:(0,U.jsx)(pv.Backdrop,{isOpen:r,onOpenChange:i,children:(0,U.jsx)(pv.Content,{placement:`bottom`,children:(0,U.jsxs)(pv.Dialog,{className:`h-[85vh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsx)(pv.Header,{children:(0,U.jsx)(pv.Heading,{children:CL})}),(0,U.jsx)(pv.Body,{children:s}),(0,U.jsx)(pv.Footer,{children:c})]})})})}):(0,U.jsx)(Dx,{children:(0,U.jsx)(Dx.Backdrop,{isOpen:r,onOpenChange:i,children:(0,U.jsx)(Dx.Container,{scroll:`inside`,size:`lg`,children:(0,U.jsxs)(Dx.Dialog,{className:`w-full max-w-4xl`,children:[(0,U.jsx)(Dx.CloseTrigger,{}),(0,U.jsxs)(Dx.Header,{children:[(0,U.jsx)(Dx.Icon,{className:`bg-accent-soft text-accent-soft-foreground`,children:(0,U.jsx)(Lj,{className:`size-5`})}),(0,U.jsx)(Dx.Heading,{children:CL})]}),(0,U.jsx)(Dx.Body,{children:s}),(0,U.jsx)(Dx.Footer,{children:c})]})})})})},EL=e=>!!(e&&typeof e==`object`),$=(e,t,n)=>e?t.reduce((e,t)=>{if(EL(e))return e[t]},e)??n:n,DL=(e,t)=>Array.isArray(e)&&e.includes(t),OL=[{path:[`app`,`priority`],rules:[{condition:e=>$(e,[`app`,`videoTool`],!0),message:`修改此配置项需要先将「默认解析优先级」关闭`}]},{path:[`app`,`multiPageHeight`],rules:[{condition:e=>!$(e,[`app`,`multiPageRender`],!0),message:`修改此配置项需要先将「分页渲染」打开`}]},{path:[`app`,`livePhotoSystem`],rules:[{condition:e=>$(e,[`app`,`livePhotoMode`],`video_and_livephoto`)===`video_only`,message:`修改此配置项需要先将「Live Photo 处理和发送方式」改为非「仅视频」模式`}]},{path:[`amagi`,`APIServerMount`],rules:[{condition:e=>!$(e,[`amagi`,`APIServer`],!1),message:`修改此配置项需要先将「API 服务」打开`}]},{path:[`amagi`,`APIServerPort`],rules:[{condition:e=>$(e,[`amagi`,`APIServerMount`],!0),message:`修改此配置项需要先将「挂载到 Koishi」关闭`}]},{path:[`app`,`qrLoginExternalAddr`],rules:[{condition:e=>$(e,[`app`,`qrLoginAddrType`],`lan`)!==`external`,message:`修改此配置项需要先将「扫码登录地址」改为「外部地址」`}]},{path:[`app`,`videoSendMode`],rules:[{condition:e=>$(e,[`app`,`usegroupfile`],!1),message:`修改此配置项需要先将「群文件上传」关闭`}]},{path:[`app`,`usegroupfile`],rules:[{condition:e=>$(e,[`app`,`videoSendMode`],`file`)===`base64`,message:`修改此配置项需要先将「本地视频发送方式」改为「File 协议」`}]},{path:[`app`,`groupfilevalue`],rules:[{condition:e=>!$(e,[`app`,`usegroupfile`],!1),message:`修改此配置项需要先将「群文件上传」打开`},{condition:e=>$(e,[`app`,`videoSendMode`],`file`)===`base64`,message:`修改此配置项需要先将「本地视频发送方式」改为「File 协议」`}]},{path:[`app`,`filelimit`],rules:[{condition:e=>!$(e,[`app`,`usefilelimit`],!1),message:`修改此配置项需要先将「视频上传拦截」打开`}]},{path:[`app`,`compresstrigger`],rules:[{condition:e=>!$(e,[`app`,`compress`],!1),message:`修改此配置项需要先将「压缩视频」打开`}]},{path:[`app`,`compressvalue`],rules:[{condition:e=>!$(e,[`app`,`compress`],!1),message:`修改此配置项需要先将「压缩视频」打开`}]},{path:[`app`,`downloadMaxSpeed`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`}]},{path:[`app`,`downloadAutoReduce`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`}]},{path:[`app`,`downloadMinSpeed`],rules:[{condition:e=>!$(e,[`app`,`downloadThrottle`],!1),message:`修改此配置项需要先将「下载限速」打开`},{condition:e=>!$(e,[`app`,`downloadAutoReduce`],!1),message:`修改此配置项需要先将「断流自动降速」打开`}]},{path:[`amagi`,`proxy`,`protocol`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`host`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`port`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`auth`,`username`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`amagi`,`proxy`,`auth`,`password`],rules:[{condition:e=>!$(e,[`amagi`,`proxy`,`switch`],!1),message:`修改此配置项需要先将「代理开关」打开`}]},{path:[`douyin`,`sendContent`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`numcomment`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`subCommentLimit`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`commentImageCollection`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`douyin`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`douyin`,`liveImageMergeMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`app`,`livePhotoMode`],`video_and_livephoto`)===`livephoto_only`,message:`修改此配置项需要先将「Live Photo 处理和发送方式」改为非「仅实况图」模式`}]},{path:[`douyin`,`videoQuality`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`douyin`,`videoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`douyin`,`videoInfoMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`displayContent`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`douyin`,`videoInfoMode`],`text`)===`image`,message:`修改此配置项需要先将「视频信息返回形式」改为「文本模式」`}]},{path:[`douyin`,`burnDanmaku`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`douyin`,`danmakuArea`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`danmakuFontSize`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`danmakuOpacity`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`verticalMode`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`videoCodec`],rules:[{condition:e=>!$(e,[`douyin`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`douyin`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`douyin`,`push`,`permission`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`cron`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`parsedynamic`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`shareType`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`pushVideoQuality`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`douyin`,`push`,`pushMaxAutoVideoSize`],rules:[{condition:e=>!$(e,[`douyin`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>$(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`bilibili`,`sendContent`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`numcomment`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`realCommentCount`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`commentImageCollection`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`bilibili`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`bilibili`,`videoQuality`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>Number($(e,[`bilibili`,`videoQuality`],0))!==0,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]},{path:[`bilibili`,`videoInfoMode`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`displayContent`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`bilibili`,`videoInfoMode`],`text`)===`image`,message:`修改此配置项需要先将「视频信息返回形式」改为「文本模式」`}]},{path:[`bilibili`,`showDanmakuInVideoInfo`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`bilibili`,`videoInfoMode`],`text`)===`text`,message:`修改此配置项需要先将「视频信息返回形式」改为「图片模式」`}]},{path:[`bilibili`,`burnDanmaku`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`bilibili`,`danmakuArea`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`danmakuFontSize`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`danmakuOpacity`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`verticalMode`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`videoCodec`],rules:[{condition:e=>!$(e,[`bilibili`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`bilibili`,`burnDanmaku`],!1),message:`修改此配置项需要先将「弹幕烧录」打开`}]},{path:[`bilibili`,`push`,`permission`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`cron`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`parsedynamic`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`}]},{path:[`bilibili`,`push`,`parseDynamicTypes`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`}]},{path:[`bilibili`,`push`,`pushVideoQuality`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`}]},{path:[`bilibili`,`push`,`pushMaxAutoVideoSize`],rules:[{condition:e=>!$(e,[`bilibili`,`push`,`switch`],!1),message:`修改此配置项需要先将「推送开关」打开`},{condition:e=>!$(e,[`bilibili`,`push`,`parsedynamic`],!1),message:`修改此配置项需要先将「作品解析」打开`},{condition:e=>Number($(e,[`bilibili`,`push`,`pushVideoQuality`],0))!==0,message:`修改此配置项需要先将「解析视频动态时的画质偏好」改为「自动选择」`}]},{path:[`kuaishou`,`comment`],rules:[{condition:e=>!$(e,[`kuaishou`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`kuaishou`,`numcomment`],rules:[{condition:e=>!$(e,[`kuaishou`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!$(e,[`kuaishou`,`comment`],!1),message:`修改此配置项需要先将「评论解析」打开`}]},{path:[`xiaohongshu`,`sendContent`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`xiaohongshu`,`numcomment`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>!DL($(e,[`xiaohongshu`,`sendContent`],[]),`comment`),message:`修改此配置项需要在「解析时发送的内容」中勾选「评论图」`}]},{path:[`xiaohongshu`,`videoQuality`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`}]},{path:[`xiaohongshu`,`maxAutoVideoSize`],rules:[{condition:e=>!$(e,[`xiaohongshu`,`switch`],!1),message:`修改此配置项需要先将「解析开关」打开`},{condition:e=>$(e,[`xiaohongshu`,`videoQuality`],`adapt`)!==`adapt`,message:`修改此配置项需要先将「画质偏好」改为「自动选择」`}]}],kL=e=>e.join(`.`),AL=(e,t)=>{let n=kL(t),r=OL.find(e=>kL(e.path)===n);if(!r)return``;for(let t of r.rules)if(t.condition(e))return t.message;return``},jL=[{label:`信息`,value:`info`},{label:`评论图`,value:`comment`},{label:`视频`,value:`video`},{label:`图片`,value:`image`}],ML=[{label:`封面`,value:`cover`},{label:`标题`,value:`title`},{label:`作者`,value:`author`},{label:`统计`,value:`stats`},{label:`简介`,value:`desc`}],NL=[{label:`自动选择`,value:`adapt`,description:`根据「视频体积上限(MB)」自动选择分辨率进行下载`},{label:`标清 540p`,value:`540p`},{label:`高清 720p`,value:`720p`},{label:`高清 1080p`,value:`1080p`},{label:`超清 2k`,value:`2k`},{label:`超清 4k`,value:`4k`}],PL=[{label:`自动选择`,value:`0`},{label:`240P 极速`,value:`6`},{label:`360P 流畅`,value:`16`},{label:`480P 清晰`,value:`32`,description:`需登录(配置ck)`},{label:`720P 高清`,value:`64`,description:`需登录(配置ck)`},{label:`720P60 高帧率`,value:`74`,description:`需登录(配置ck)`},{label:`1080P 高清`,value:`80`,description:`需登录(配置ck)`},{label:`1080P+ 高码率`,value:`112`,description:`需大会员&视频支持`},{label:`1080P60 高帧率`,value:`116`,description:`需大会员&视频支持`},{label:`4K 超清`,value:`120`,description:`需大会员&视频支持`},{label:`8K 超高清`,value:`127`,description:`需大会员&视频支持`}],FL=[{label:`视频动态`,value:`DYNAMIC_TYPE_AV`},{label:`图文动态`,value:`DYNAMIC_TYPE_DRAW`},{label:`文章动态`,value:`DYNAMIC_TYPE_ARTICLE`}],IL=[{label:`所有人`,value:`all`},{label:`管理员`,value:`admin`},{label:`主人`,value:`master`},{label:`群主`,value:`group.owner`},{label:`群管理员`,value:`group.admin`}],LL=[{label:`H.264`,value:`h264`,description:`兼容性最好,支持几乎所有设备`},{label:`H.265`,value:`h265`,description:`压缩率更高,近几年设备支持良好(推荐)`},{label:`AV1`,value:`av1`,description:`最新编码格式,压缩率最高,但编码较慢`}],RL=[{label:`关闭`,value:`off`,description:`保持原始比例,不做转换`},{label:`智能`,value:`standard`,description:`仅对宽屏比例视频生效`},{label:`强制 9:16`,value:`force`,description:`所有视频统一转为 9:16 竖屏`}],zL=[{label:`1/4 屏`,value:`0.25`,description:`仅顶部区域`},{label:`半屏`,value:`0.5`,description:`上半部分(推荐)`},{label:`3/4 屏`,value:`0.75`,description:`大部分区域`},{label:`全屏`,value:`1`,description:`铺满整个画面`}],BL=[{label:`小号`,value:`small`},{label:`中号`,value:`medium`},{label:`大号`,value:`large`}],VL={enabled:`已开启`,disabled:`已关闭`},HL=[{key:`amagi`,label:`接口库`,description:`请求与 Cookies`},{key:`app`,label:`通用`,description:`运行与交互`},{key:`douyin`,label:`抖音`,description:`解析与推送`},{key:`bilibili`,label:`哔哩哔哩`,description:`解析与推送`},{key:`kuaishou`,label:`快手`,description:`快手解析`},{key:`xiaohongshu`,label:`小红书`,description:`小红书解析`},{key:`qq`,label:`QQ 适配器`,description:`QQ 平台专属`},{key:`pushlist`,label:`推送列表`,description:`订阅 JSON`}],UL=(0,v.lazy)(()=>YS(()=>import(`./CronEditor-CYgFpX-g.js`),__vite__mapDeps([0,1]))),WL=({className:e,disabled:t,...n})=>{let[r,i]=(0,v.useState)(!1),a=r?`隐藏密码`:`显示密码`;return(0,U.jsxs)(`div`,{className:`relative w-full`,children:[(0,U.jsx)(cx,{...n,variant:`secondary`,className:`w-full pr-10 ${e??``}`,type:r?`text`:`password`}),(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":a,className:`absolute right-1 top-1/2 -translate-y-1/2`,isDisabled:t,size:`sm`,type:`button`,variant:`tertiary`,onPress:()=>i(e=>!e),children:r?(0,U.jsx)(Fj,{className:`size-4`,"aria-hidden":`true`}):(0,U.jsx)(Ij,{className:`size-4`,"aria-hidden":`true`})})]})},GL=({config:e,device:t,classes:n,validationErrors:r,updateConfigValue:i})=>{let a=e=>{let n=vL(e)?e:{description:e},r=t===`mobile`?n.mobileContent??n.desktopContent:n.desktopContent;return(0,U.jsxs)(px,{className:`flex items-center gap-2`,children:[(0,U.jsx)(`span`,{children:n.description}),r?(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`查看详细说明`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:`sm`,variant:`tertiary`,children:(0,U.jsx)(Rj,{className:`size-4`,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:t===`mobile`?`bottom`:`top`,children:[(0,U.jsx)(tx.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72`,children:r})]})]}):null,n.extra]})},o=(n,r,i)=>{if(!i)return n;let a=AL(e,r);return a?t===`mobile`?(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{className:`w-full cursor-not-allowed`,children:n}),(0,U.jsx)(gv.Content,{placement:`bottom`,children:(0,U.jsxs)(gv.Dialog,{children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72 text-sm`,children:a})]})})]}):(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{className:`w-full cursor-not-allowed`,children:n}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),(0,U.jsx)(`div`,{className:`max-w-72`,children:a})]})]}):n},s=(t,n,r,a)=>{let o=Q(e,t,[]),s=r?Array.from(new Set([...o,n])):o.filter(e=>e!==n);if(a&&r){let e=a.find(e=>e.includes(n));if(e){let t=e.filter(e=>e!==n);s=s.filter(e=>!t.includes(e))}}i(t,s)};return{renderSwitch:(t,n,r,s=!1)=>{let c=Q(e,t,!1),l=(0,U.jsxs)(ob,{isDisabled:s,isSelected:c,onChange:e=>i(t,e),children:[(0,U.jsxs)(ob.Content,{children:[(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})}),(0,U.jsx)(`span`,{className:`font-semibold`,children:n})]}),a(r||(c?VL.enabled:VL.disabled))]});return o(l,t,s)},renderTextField:(t,n,s,c)=>{let l=c?.type||`text`,u=String(Q(e,t,l===`number`?c?.fallback??0:``)),d=r[pL(t)],f=c?.disabled??!1,p=(0,U.jsxs)(lx,{fullWidth:!0,isInvalid:!!d,isDisabled:f,name:t.join(`.`),type:l,value:u,onChange:e=>{i(t,l===`number`?gL(e,c?.fallback??0):e)},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:n}),l===`password`?(0,U.jsx)(WL,{disabled:f,max:c?.max,min:c?.min,pattern:c?.pattern,placeholder:c?.placeholder||n,step:c?.step}):(0,U.jsx)(cx,{variant:`secondary`,max:c?.max,min:c?.min,pattern:c?.pattern,placeholder:c?.placeholder||n,step:c?.step}),d?(0,U.jsx)(hx,{children:d}):a(s)]});return o(p,t,f)},renderSelectField:(t,n,r,s,c=e=>e,l=!1)=>{let u=String(Q(e,t,s[0]?.value||``)),d=(0,U.jsxs)(Ax,{disabledKeys:s.filter(e=>e.disabled).map(e=>e.value),fullWidth:!0,isDisabled:l,name:t.join(`.`),placeholder:n,value:u,variant:`secondary`,onChange:e=>{e===null||Array.isArray(e)||i(t,c(String(e)))},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:n}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),a(r),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:s.map(e=>(0,U.jsxs)(wx.Item,{id:e.value,textValue:e.label,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-1`,children:[(0,U.jsx)(dx,{children:e.label}),e.description?(0,U.jsx)(px,{children:e.description}):null]}),(0,U.jsx)(wx.ItemIndicator,{})]},e.value))})})]});return o(d,t,l)},renderCheckboxGroup:(t,r,i,c,l=!1,u)=>{let d=Q(e,t,[]),f=(0,U.jsxs)(`div`,{className:n.field,children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),a(i),(0,U.jsx)(`div`,{className:n.choiceGrid,children:c.map(e=>(0,U.jsxs)(m_,{variant:`secondary`,isDisabled:l,isSelected:_L(d,e.value),onChange:n=>s(t,e.value,n,u),children:[(0,U.jsxs)(m_.Content,{children:[(0,U.jsx)(m_.Control,{children:(0,U.jsx)(m_.Indicator,{})}),e.label]}),e.description?(0,U.jsx)(px,{children:e.description}):null]},e.value))})]});return o(f,t,l)},renderSlider:(t,r,s,c)=>{let l=Q(e,t,c?.fallback??0),u=c?.disabled??!1,d=(0,U.jsxs)(`div`,{className:n.field,children:[(0,U.jsxs)(Nx,{className:`w-full`,isDisabled:u,value:l,formatOptions:c?.formatOptions??{style:`percent`,maximumFractionDigits:0},maxValue:c?.max??1,minValue:c?.min??0,step:c?.step??.01,onChange:e=>{Array.isArray(e)||i(t,e)},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),(0,U.jsx)(Nx.Output,{}),(0,U.jsxs)(Nx.Track,{children:[(0,U.jsx)(Nx.Fill,{}),(0,U.jsx)(Nx.Thumb,{})]})]}),a(s)]});return o(d,t,u)},renderCronField:(r,a,s,c=!1)=>{let l=Q(e,r,`*/10 * * * *`),u=(0,U.jsx)(`div`,{className:n.field,children:(0,U.jsx)(v.Suspense,{fallback:(0,U.jsx)(`div`,{className:`h-64 animate-pulse rounded-lg bg-muted/30`}),children:(0,U.jsx)(UL,{device:t,disabled:c,value:l,onChange:e=>i(r,e)})})});return o(u,r,c)},/*KKK-PERM-START*/renderPermField:(t,r,s,c)=>{c=c||{};const p=t,list=!!c.list,modes=c.modes||[],raw=Q(e,p,list?[]:`all`),arr0=list?(Array.isArray(raw)?raw.map(String):(raw?[String(raw)]:[])):[],ids=list?arr0.filter(x=>/^\d+$/.test(x)):[],numText=list?ids.join(`, `):([`all`,`admin`].includes(String(raw))?``:String(raw||``)),kw=list?(arr0.find(x=>!/^\d+$/.test(x))||``):([`all`,`admin`].includes(String(raw))?String(raw):``),guess=(kw===`trigger`)?`trigger`:(kw||(String(numText).trim()?`id`:(list?`trigger`:`all`))),pair=(0,v.useState)(null),mode=pair[0]||guess,setMode=pair[1],apply=n=>{setMode(n);if(n===`id`){i(p,list?ids:String(numText))}else{i(p,list?[n]:n)}},setIds=n=>{i(p,list?String(n).split(/[,,\s]+/).map(x=>x.trim()).filter(Boolean):n)},sel=(0,U.jsxs)(Ax,{fullWidth:!0,name:p.join(`.`),placeholder:r,value:mode,variant:`secondary`,onChange:e=>{e===null||Array.isArray(e)||apply(String(e))},children:[(0,U.jsx)(dx,{className:`font-semibold`,children:r}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),a(s),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:modes.map(m=>(0,U.jsx)(wx.Item,{id:m.value,textValue:m.label,children:m.label},m.value))})})]}),inp=mode===`id`?(0,U.jsxs)(lx,{fullWidth:!0,name:p.join(`.`),value:numText,onChange:e=>setIds(e),children:[(0,U.jsx)(dx,{className:`font-semibold`,children:list?`接收账号`:`允许的账号`}),(0,U.jsx)(cx,{variant:`secondary`,placeholder:`填写 QQ 号,多个用逗号分隔`})]}):null,box=(0,U.jsxs)(`div`,{className:n.field,children:[sel,inp]});return o(box,t,!1)},/*KKK-PERM-END*/renderPageHeader:(e,n)=>(0,U.jsxs)(`div`,{className:`mb-6 ${t===`mobile`?`pr-36`:``}`,"data-config-section":!0,children:[(0,U.jsx)(`h2`,{className:`text-2xl font-bold`,children:e}),(0,U.jsx)(`div`,{className:`mt-3`,children:(0,U.jsx)(px,{children:n})})]}),renderSubSection:(e,t)=>(0,U.jsxs)(Wg,{"data-config-section":!0,className:`mb-4`,children:[(0,U.jsx)(Wg.Header,{className:n.sectionHeader,children:(0,U.jsx)(Wg.Title,{className:`text-lg font-semibold`,children:e})}),(0,U.jsx)(Wg.Content,{className:n.sectionContent,children:(0,U.jsx)(`div`,{className:n.fields,children:t})})]})}},KL={root:`relative flex min-w-0 max-w-full flex-col gap-8`,loading:`flex min-h-80 items-center justify-center gap-3`,header:`grid grid-cols-[minmax(0,1fr)_auto] items-start gap-8 pr-44`,headerCopy:`flex min-w-0 flex-col gap-2`,form:`flex min-w-0 max-w-full flex-col gap-6`,floatingActions:`fixed right-6 top-20 z-10`,actionControls:`flex items-center justify-end gap-3`,sectionHeader:`p-2`,sectionContent:`p-6`,fields:`grid grid-cols-2 gap-x-6 gap-y-5`,field:`flex min-w-0 flex-col gap-2`,choiceGrid:`grid grid-cols-2 gap-3`,divider:`col-span-full flex min-w-0 flex-col gap-2 pt-3`,tabsListContainer:`w-full min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain overscroll-y-none [scrollbar-width:none] [&::-webkit-scrollbar]:hidden`,tabsList:`w-fit min-w-max *:w-fit *:min-w-fit *:flex-none *:shrink-0 *:whitespace-nowrap`,topLevelFields:`mb-4 space-y-4 px-2`},qL={root:`relative flex min-w-0 max-w-full flex-col gap-5`,loading:`flex min-h-80 items-center justify-center gap-3`,header:`flex flex-col gap-3 pt-12`,headerCopy:`flex min-w-0 flex-col gap-2`,form:`flex min-w-0 max-w-full flex-col gap-3`,floatingActions:`sticky top-0 z-20 flex h-0 w-full justify-end overflow-visible`,actionControls:`flex w-fit h-11 p-1 items-center gap-2 rounded-full border border-default-200 bg-background/90 shadow-sm backdrop-blur-md`,sectionHeader:`p-1`,sectionContent:`p-0`,fields:`grid grid-cols-1 gap-5`,field:`flex min-w-0 flex-col gap-2`,choiceGrid:`grid grid-cols-1 gap-3`,divider:`col-span-full flex min-w-0 flex-col gap-2 pt-3`,tabsListContainer:`w-full min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain overscroll-y-none [scrollbar-width:none] [&::-webkit-scrollbar]:hidden`,tabsList:`w-fit min-w-max *:w-fit *:min-w-fit *:flex-none *:shrink-0 *:whitespace-nowrap`,topLevelFields:`mb-4 space-y-4 px-4`},JL=e=>e===`mobile`?qL:KL,YL=({config:e,renderers:t})=>{let{renderPageHeader:n,renderSelectField:r,renderSubSection:i,renderSwitch:a,renderTextField:o}=t,s=Q(e,[`amagi`,`proxy`,`switch`],!1),c=Q(e,[`amagi`,`APIServer`],!1);return(0,U.jsxs)(U.Fragment,{children:[n(`接口库配置`,`接口库的 Cookies、请求、代理和 API 服务配置。保存后后端会重载接口库客户端。`),i(`平台 Cookies`,(0,U.jsxs)(U.Fragment,{children:[o([`amagi`,`cookies`,`douyin`],`抖音 Cookies`,`请输入你的抖音Cookies,不输入则无法使用抖音相关功能噢。`,{type:`password`}),o([`amagi`,`cookies`,`bilibili`],`B站 Cookies`,`请输入你的B站Cookies,不输入部分功能将受限噢。`,{type:`password`}),o([`amagi`,`cookies`,`kuaishou`],`快手 Cookies`,`请输入你的快手Cookies,不输入则无法使用快手相关功能噢。`,{type:`password`}),o([`amagi`,`cookies`,`xiaohongshu`],`小红书 Cookies`,`请输入你的小红书Cookies,不输入则无法使用小红书相关功能噢。`,{type:`password`})]})),i(`请求配置`,(0,U.jsxs)(U.Fragment,{children:[o([`amagi`,`timeout`],`请求超时时间`,`网络请求的超时时间,单位:毫秒。`,{type:`number`,fallback:15e3,min:1e3,max:3e5}),o([`amagi`,`User-Agent`],`User-Agent`,`请求头中的User-Agent字段,用于标识客户端类型。`)]})),i(`代理配置(可选)`,(0,U.jsxs)(U.Fragment,{children:[a([`amagi`,`proxy`,`switch`],`代理开关`,`开启后需要配置「代理主机」「代理端口」。`),r([`amagi`,`proxy`,`protocol`],`代理协议`,`代理服务使用的协议。`,[{label:`HTTP`,value:`http`},{label:`HTTPS`,value:`https`}],e=>e,!s),o([`amagi`,`proxy`,`host`],`代理主机`,`代理服务器的主机地址,如:127.0.0.1。`,{disabled:!s}),o([`amagi`,`proxy`,`port`],`代理端口`,`代理服务器的端口号。`,{type:`number`,fallback:7890,min:1,max:65535,disabled:!s}),o([`amagi`,`proxy`,`auth`,`username`],`代理用户名`,`代理服务器的认证用户名(如果需要)。`,{disabled:!s}),o([`amagi`,`proxy`,`auth`,`password`],`代理密码`,`代理服务器的认证密码(如果需要)。`,{type:`password`,disabled:!s})]})),i(`API 服务配置`,(0,U.jsxs)(U.Fragment,{children:[a([`amagi`,`APIServer`],`API 服务`,`本地部署一个视频解析API服务,接口范围为本插件用到的所有。`),a([`amagi`,`APIServerMount`],`挂载到 Koishi`,`API 服务是否挂载到 Koishi 上,开启后监听端口为 Koishi 的 http 端口,修改后需重启。需开启「API服务」。`,!c),o([`amagi`,`APIServerPort`],`API 服务端口`,`仅未挂载到 Koishi 时生效。`,{type:`number`,disabled:Q(e,[`amagi`,`APIServerMount`],!0),fallback:4567,min:1024,max:65535})]}))]})},XL=({config:e,renderers:t})=>{let{renderCheckboxGroup:n,renderPageHeader:r,renderSelectField:i,renderSlider:a,renderSubSection:o,renderSwitch:s,renderTextField:c}=t,l=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`);return(0,U.jsxs)(U.Fragment,{children:[r(`通用`,`插件运行、渲染和交互相关配置。`),o(`缓存设置`,(0,U.jsx)(U.Fragment,{children:s([`app`,`removeCache`],`自动删除视频缓存`,`任务完成后删除下载缓存。`)})),o(`交互设置`,(0,U.jsxs)(U.Fragment,{children:[s([`app`,`EmojiReply`],`表情回应`,`在解析任务开始时添加表情回应,若适配器不支持需要关闭。`),s([`app`,`parseTip`],`解析提示`,`发送提示信息:"检测到xxx链接,开始解析"。`),s([`app`,`fakeForward`],`伪造合并转发消息`,`一次解析产生的所有内容(卡片、图片、视频、评论…)合并成一条转发消息发出,过程提示(开始解析 / 下载中 / 发送中…)不会进转发;只有支持合并转发的适配器有效果,QQ 官方适配器会自动退化成逐条发送。开启后合并转发使用触发者身份展示;关闭后使用机器人身份展示。`),t.renderPermField([`app`,`errorLogSendTo`],`错误日志`,`谁来接收错误日志,选「指定账号」后填 QQ 号,多个用逗号分隔。`,{list:true,modes:[{value:`trigger`,label:`触发者所在的群`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]}),/*KKK-APP-START*/s([`qq`,`recallPanel`],`自动撤回面板`,`用户在面板上点完按钮后,自动把上一条提示 / 选择消息撤回,群里不会堆着一排旧提示和选择。`),s([`qq`,`forceNoDanmaku`],`强制不烧录弹幕`,`优先级最高的总开关:打开时无论指令、面板按钮还是平台配置,都不会烧录弹幕,一律按纯视频解析。要用弹幕功能时先把它关掉。`),s([`qq`,`parseDedupe`],`短时间不重复解析`,`默认开启。同一条链接在下面设定的一段时间内只解析一次:QQ 的指令按钮是「发一条消息 + 再发一个交互事件」,用户连点、客户端重发也会把同一条链接投递两遍,跑两遍就是两次「开始解析」、两次下载、两次发送(第二次还常因为缓存已被清理而失败)。去重键包含会话、作品 ID、画质与弹幕开关,换画质、换作品、换群都不会被误伤。**关掉后每条消息都会解析**,需要反复调试同一条链接时可以临时关掉。`),c([`qq`,`parseDedupeMinutes`],`重复解析间隔(分钟)`,`上面那个开关打开时才生效:同一条链接在这段时间内只解析一次,默认 1 分钟(可填 1 ~ 60)。填得越大越省事(重复投递/连点不会再跑第二遍),但也意味着这段时间里你手动再发一次同一条链接会被忽略;想立刻重解析就把上面的开关关掉。(这一项要先把上面的「短时间不重复解析」打开才能改)`,{type:`number`,fallback:1,min:1,max:60,disabled:Q(e,[`qq`,`parseDedupe`],!0)===!1})/*KKK-APP-END*/,,]})),/*KKK-SECTION-START*/o(`在线播放器设置`,(0,U.jsx)(U.Fragment,{children:[s([`qq`,`playerEnabled`],`在线播放器总开关`,`**这一组的总开关**,默认开启。打开时,解析面板里那一列按钮上的「弹幕」会把视频放到在线播放页(带弹幕)并回一条链接,不再把弹幕烧进视频、也不再把视频传到群里;链接有有效期,过期自动清理文件。开着时面板上还会多一列「在线看」(点它直接在线看,不管弹幕功能有没有开都带弹幕),这一列由下面的「面板显示「在线看」按钮」单独控制。**关掉它,这一组里其它设置都会变灰不可改**,解析也回到原来的 ffmpeg 烧录流程(面板列头变回「烧录弹幕」、不再有「在线看」列)。(这一项要先关掉上面的「强制不烧录弹幕」(也就是打开弹幕功能)才能改)`,Q(e,[`qq`,`forceNoDanmaku`],!0)===!0),s([`qq`,`playerWatchButton`],`面板显示「在线看」按钮`,`默认开启。打开后,QQ 解析面板的「弹幕」列右边会多一列「在线看」:点它**直接在线播放**(带弹幕,视频不发到群里、也不占群文件),不看弹幕功能开没开 —— 在线看永远带弹幕。关掉就不显示这一列。注意:只有上面的「在线播放器总开关」开着时这一列才会出现(总开关关掉时这一项会变灰);播放器关掉时它没有任何作用。**超过「在线播放最大文件」的画质档不给「在线看」按钮**,那一格会标「超上限」。(这一项要先把上面的「在线播放器总开关」打开才能改)`,Q(e,[`qq`,`playerEnabled`],!0)===!1),c([`qq`,`playerBaseUrl`],`播放器公网地址`,`**这是你自己的公网地址,插件猜不出来,必须由你填。**例如 https://play.example.com(结尾斜杠会自动去掉),用户收到的链接就是它加上 /kkk/player/<令牌>。留空时链接会退化成「http://本机 IP:端口」,**只有本机 / 内网能打开**;这时日志里会警告一次,机器人回复和播放页上也会带一句「未配置公网地址,仅本机可访问」——公网用户点开打不开是正常的,不是插件坏了。用 Nginx / Caddy 之类的反向代理指向下面的「播放器端口」即可,代理到 https 域名时这里就填那个域名。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`text`,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerPort`],`播放器端口`,`0 = 复用 Koishi 自己的端口(推荐,不用额外开端口);填其它值会用 node:http 另起一个服务。端口被占用时只记一条日志并退回 Koishi 端口,不会影响解析。注意别填浏览器禁止访问的端口(例如 6665-6669 这些 IRC 段),否则用户点开链接会直接 ERR_UNSAFE_PORT,看起来就像网页坏了。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:0,min:0,max:65535,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerExpireMinutes`],`链接有效期(分钟)`,`播放链接与视频文件的有效期,默认 60 分钟(最小 1、最大 1440)。到点后视频和弹幕会被自动删除,链接打开是「链接已过期」。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:60,min:1,max:1440,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),c([`qq`,`playerMaxFileMB`],`在线播放最大文件(MB)`,`体积超过这个值的视频**不走在线播放**,改回原来的发送流程(免得把机器磁盘塞满)。留空或填 0 = 跟随全局:用上游的「文件大小限制」(usefilelimit / filelimit,当前默认 200MB);全局没开限制就是不限制。**这条上限对「超限转在线播放」一样有效**:开了转播、但视频比这条上限还大时,仍然按原来的方式处理(拒绝并说明),不会为了转播把机器磁盘塞满。判定发生在把文件搬进播放器目录之前,超限的视频一点都不会占播放器目录。(这一项要先把上面的「在线播放器总开关」打开才能改)`,{type:`number`,fallback:0,min:0,max:102400,disabled:Q(e,[`qq`,`playerEnabled`],!0)===!1}),s([`qq`,`playerOnOversize`],`超限转在线播放`,`打开后,体积超过全局「文件大小限制」的视频不再被拒绝(原来会回一句「视频太大了,还是去B站看吧」),而是照常下载、改为在线播放:用户收到一条播放链接,视频不发到群里、也不占群文件。注意:**只有体积不超过上面「在线播放最大文件」的视频才会被转播**——比那个上限还大的照旧拒绝(免得把机器磁盘塞满),拒绝时会说明「超过在线播放的体积上限,按原来的方式处理」。关着时维持原来的行为。(这一项要先把上面的「在线播放器总开关」打开才能改)`,Q(e,[`qq`,`playerEnabled`],!0)===!1)]}))/*KKK-SECTION-END*/,o(`渲染设置`,(0,U.jsxs)(U.Fragment,{children:[c([`app`,`renderScale`],`渲染精度`,`可选值50~200,建议100。设置高精度会提高图片的精细度,过高可能会影响渲染与发送速度。`,{type:`number`,fallback:100,min:50,max:200}),(0,U.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,U.jsx)(`div`,{className:`min-w-0 flex-1`,children:i([`app`,`Theme`],`渲染图片的主题色`,`渲染评论图和推送图的主题色。`,[{label:`自动`,value:`0`,description:`06:00-18:00为浅色,18:00-06:00为深色`},{label:`浅色`,value:`1`},{label:`深色`,value:`2`},{label:`智能场景(实验性)`,value:`3`,description:`自动模式的超集;部分模板会根据封面色调 智能调整主题色,可能会出现不适配的情况。`}],e=>Number(e))}),(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{"aria-label":`封面氛围背景参数`,className:`mt-7 shrink-0`,children:(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`封面氛围背景参数`,variant:`secondary`,children:(0,U.jsx)(Gj,{className:`size-4`,"aria-hidden":`true`})})}),(0,U.jsx)(gv.Content,{className:`w-90 max-w-[calc(100vw-2rem)]`,placement:`bottom`,children:(0,U.jsxs)(gv.Dialog,{children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(gv.Heading,{children:`封面氛围背景`}),(0,U.jsx)(`p`,{className:`mt-1 mb-5 text-sm text-muted`,children:`仅对使用封面氛围背景的模板生效(抖音视频/图文作品、B站视频信息、B站直播推荐动态)。`}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-5`,children:[a([`app`,`ambientCover`,`coverOpacity`],`封面氛围强度`,`封面图对背景氛围的贡献度,即模糊封面层的不透明度,越大封面色越浓。`,{fallback:.7}),a([`app`,`ambientCover`,`overlayEdgeOpacity`],`氛围压色(顶部/底部)`,`背景两端主题色压色罩的不透明度,越大两端越接近纯色主题背景。`,{fallback:.9}),a([`app`,`ambientCover`,`overlayMiddleOpacity`],`氛围压色(中间带)`,`背景中间带主题色压色罩的不透明度,越小封面色越透。`,{fallback:.2})]})]})})]})]}),c([`app`,`RenderWaitTime`],`渲染图片的等待时间`,`单位:秒,Linux系统下不能为0;其他系统传递 0 可禁用。`,{type:`number`,fallback:60,min:0}),s([`app`,`multiPageRender`],`分页渲染`,`将模板渲染成多页的图片,以降低渲染器压力,默认开启,非必要不修改!`),c([`app`,`multiPageHeight`],`分页渲染时,每页的高度`,`经测试最佳每页高度为12000px,默认12000px。`,{type:`number`,disabled:!Q(e,[`app`,`multiPageRender`],!0),fallback:12e3,min:1e3,max:2e4})]})),o(`上传与下载设置`,(0,U.jsxs)(U.Fragment,{children:[(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:[i([`app`,`videoSendMode`],`本地视频发送方式`,`选择本地视频交付给协议端的方式。`,[{label:`File 协议(本地文件)`,value:`file`,description:`使用 file 协议发送本地视频,需 Koishi 与协议端在同一网络环境下`},{label:`Base64(编码传输)`,value:`base64`,description:`将本地视频转换为 base64 发送,传输数据量增大约 30%,不在同一网络环境可能导致额外带宽成本,适合 karin 和协议端不在同一网络环境`}],e=>e,Q(e,[`app`,`usegroupfile`],!1)),s([`app`,`usegroupfile`],`群文件上传`,`使用群文件上传,开启后会将视频文件上传到群文件中,需配置「群文件上传阈值」。与「本地视频发送方式 = Base64」互斥。`,Q(e,[`app`,`videoSendMode`],`file`)===`base64`),c([`app`,`groupfilevalue`],`群文件上传阈值`,`当文件大小超过该值时将使用群文件上传,单位:MB,「使用群文件上传」开启后才会生效。`,{type:`number`,fallback:100,min:1,disabled:!Q(e,[`app`,`usegroupfile`],!1)||Q(e,[`app`,`videoSendMode`],`file`)===`base64`})]}),(0,U.jsx)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:i([`app`,`imageSendMode`],`网络图片发送方式`,`图片资源发送给协议端的方式。`,[{label:`URL 链接(直接传递)`,value:`url`,description:`直接传递 HTTP 链接给上游下载,可能因上游网络问题导致下载超时`},{label:`File 协议(本地文件)`,value:`file`,description:`下载到本地后使用 file 协议发送,需 Koishi 与协议端在同一网络环境下`},{label:`Base64(编码传输)`,value:`base64`,description:`下载后转换为 base64 发送,传输数据量增大约 30%,不在同一网络环境可能导致额外带宽成本`}])}),(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 mb-4 rounded-3xl`,variant:`secondary`,children:[s([`app`,`usefilelimit`],`视频上传拦截`,`开启后会根据视频文件大小判断是否需要上传,需配置「视频拦截阈值」。`),c([`app`,`filelimit`],`视频拦截阈值`,`视频文件大于该数值则直接结束任务,不会上传,单位: MB,「视频上传拦截」开启后才会生效。`,{type:`number`,fallback:20,min:1,disabled:!Q(e,[`app`,`usefilelimit`],!1)}),s([`app`,`compress`],`压缩视频`,`开启后会将视频文件压缩后再上传,适合上传大文件,任务过程中会吃满CPU,对低配服务器不友好。需配置「压缩触发阈值」与「压缩后的值」。`),c([`app`,`compresstrigger`],`压缩触发阈值`,`触发视频压缩的阈值,单位:MB。当文件大小超过该值时,才会压缩视频,「压缩视频」开启后才会生效。`,{type:`number`,fallback:80,min:1,disabled:!Q(e,[`app`,`compress`],!1)}),c([`app`,`compressvalue`],`压缩后的值`,`单位:MB,若视频文件大小大于「压缩触发阈值」的值,则会进行压缩至该值(±5%),「压缩视频」开启后才会生效。`,{type:`number`,fallback:30,min:1,disabled:!Q(e,[`app`,`compress`],!1)})]}),(0,U.jsxs)(Ev,{className:`flex flex-col gap-5 p-4 rounded-3xl`,variant:`secondary`,children:[s([`app`,`downloadThrottle`],`下载限速`,`开启后会限制下载速度,避免触发服务器风控导致连接被重置(ECONNRESET)。如果下载时经常报错"连接被重置",建议开启。`),c([`app`,`downloadMaxSpeed`],`最大下载速度`,`限速开关打开后生效。单位:MB/s,建议值:10,根据实际情况调整。`,{type:`number`,fallback:10,min:1,max:100,disabled:!Q(e,[`app`,`downloadThrottle`],!1)}),s([`app`,`downloadAutoReduce`],`断流自动降速`,`限速开关打开后生效。当检测到下载中断时,自动降低下载速度,避免再次触发风控。`,!Q(e,[`app`,`downloadThrottle`],!1)),c([`app`,`downloadMinSpeed`],`最低下载速度`,`断流降速开关打开后生效。单位:MB/s,自动降速的下限值。`,{type:`number`,fallback:1,min:.5,max:50,disabled:!Q(e,[`app`,`downloadThrottle`],!1)||!Q(e,[`app`,`downloadAutoReduce`],!1)})]})]})),o(`Live Photo 兼容设置`,(0,U.jsxs)(U.Fragment,{children:[i([`app`,`livePhotoMode`],`Live Photo 处理和发送方式`,`解析遇到实况图时的处理和发送方式。注意:生成视频性能开销大,2C2G 服务器单张约需 20 秒。`,[{label:`视频 + 实况图`,value:`video_and_livephoto`,description:`生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)+ 对应系统的实况图`},{label:`仅视频`,value:`video_only`,description:`仅生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)`},{label:`仅实况图`,value:`livephoto_only`,description:`仅生成并发送对应系统的实况图,性能开销小`}]),i([`app`,`livePhotoSystem`],`Live Photo 静态图兼容系统`,`当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo 静态图按所选系统生成。推荐 OPPO,兼容性最广。`,[{label:`Google`,value:`google`,description:`Google Motion Photo 格式`},{label:`小米(HyperOS)`,value:`xiaomi`,description:`兼容小米(任何版本)和 Google,但无法被 OPPO 识别`},{label:`OPPO(ColorOS)`,value:`oppo`,description:`推荐,兼容 OPPO、小米(较新版本)和 Google`},{label:`华为/荣耀(HarmonyOS/MagicOS)`,value:`huawei_honor`,description:`理论可行但未实测(作者无对应设备)`},{label:`vivo(Origin OS)`,value:`vivo`,description:`需要独立的图片和同名视频文件,暂不支持`,disabled:!0},{label:`iPhone(iOS)`,value:`iphone`,description:`需要独立的图片和同名视频文件,暂不支持`,disabled:!0}],e=>e,l===`video_only`)]})),o(`我的小玩具`,(0,U.jsxs)(U.Fragment,{children:[s([`app`,`videoTool`],`默认解析优先级`,`关闭后使用自定义优先级,修改后需重启。`),c([`app`,`priority`],`自定义优先级`,`默认解析优先级关闭后生效。`,{type:`number`,disabled:Q(e,[`app`,`videoTool`],!0),fallback:800}),i([`app`,`qrLoginAddrType`],`扫码登录地址`,`生成登录二维码时使用的服务器地址。`,[{label:`局域网`,value:`lan`,description:`适用于手机和服务器在同一局域网`},{label:`外部地址`,value:`external`,description:`适用于远程访问,需手动配置`}]),c([`app`,`qrLoginExternalAddr`],`外部访问地址`,`公网 IP 或域名,如:123.45.67.89 或 example.com。`,{disabled:Q(e,[`app`,`qrLoginAddrType`],`lan`)!==`external`})]}))]})},ZL=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderCronField:i,renderPageHeader:a,renderSelectField:o,renderSubSection:s,renderSwitch:c,renderTextField:l}=t,u=Q(e,[`bilibili`,`switch`],!1),d=Q(e,[`bilibili`,`sendContent`],[]),f=Q(e,[`bilibili`,`burnDanmaku`],!1),p=Q(e,[`bilibili`,`videoQuality`],0),m=Q(e,[`bilibili`,`videoInfoMode`],`text`),h=Q(e,[`bilibili`,`push`,`switch`],!1),g=Q(e,[`bilibili`,`push`,`parsedynamic`],!1),_=Q(e,[`bilibili`,`push`,`pushVideoQuality`],0),v=!u||!_L(d,`comment`),y=!u||!f;return(0,U.jsxs)(U.Fragment,{children:[a(`哔哩哔哩`,`B站解析、动态图片布局、弹幕和推送基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[c([`bilibili`,`switch`],`解析开关`,`B站解析开关,此开关为单独开关。`),r([`bilibili`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL.filter(e=>e.value!==`image`),!u)]}),s(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[l([`bilibili`,`numcomment`],`评论解析数量`,`主评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:v}),c([`bilibili`,`realCommentCount`],`显示真实评论数量`,`关闭则显示解析到的评论数量。`,v),c([`bilibili`,`commentImageCollection`],`是否收集评论区的图片`,`开启后将收集评论区的图片,以合并转发的形式返回。`,v)]})),s(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[o([`bilibili`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,PL,Number,!u),l([`bilibili`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!u||Number(p)!==0}),o([`bilibili`,`imageLayout`],`解析图文动态时,遇到多张图片时的页面布局方式(动态推送图片也生效)`,`自动布局:少于4张时逐张上下排列;4~8张时瀑布流;9张及以上九宫格。`,[{label:`自动布局`,value:`auto`},{label:`逐张上下排列`,value:`vertical`},{label:`瀑布流排列`,value:`waterfall`},{label:`九宫格排列`,value:`grid`}]),o([`bilibili`,`videoInfoMode`],`视频信息返回形式`,`视频信息返回文本或图片。`,[{label:`图片模式`,value:`image`},{label:`文本模式`,value:`text`}],e=>e,!u),r([`bilibili`,`displayContent`],`视频信息前返回的内容`,`若什么都不选,则不会返回任何视频相关信息。`,ML,!u||m===`image`),c([`bilibili`,`showDanmakuInVideoInfo`],`视频信息图片中显示弹幕`,`开启后在视频信息图片的封面区域显示热门弹幕。关闭后不会请求弹幕数据,可提升解析速度。仅「视频信息返回形式」为图片模式时生效。`,!u||m===`text`)]})),s(`权限设置`,(0,U.jsx)(U.Fragment,{children:t.renderPermField([`bilibili`,`loginPerm`],`谁可以触发扫码登录`,`选「指定账号」后填 QQ 号,多个用逗号分隔。`,{modes:[{value:`all`,label:`所有人`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]})})),s(`弹幕烧录相关`,(0,U.jsxs)(U.Fragment,{children:[c([`bilibili`,`burnDanmaku`],`弹幕烧录`,`将弹幕硬编码到视频画面中。开启后视频需要重新编码,耗时较长,高分辨率视频会占用较多资源。`,!u),o([`bilibili`,`danmakuArea`],`弹幕区域`,`限制弹幕的显示范围,避免遮挡视频主体内容。`,zL,Number,y),o([`bilibili`,`danmakuFontSize`],`弹幕字号`,`弹幕文字大小。`,BL,e=>e,y),l([`bilibili`,`danmakuOpacity`],`弹幕透明度`,`0为完全透明,100为完全不透明,推荐70。`,{type:`number`,fallback:70,min:0,max:100,disabled:y}),o([`bilibili`,`verticalMode`],`竖屏适配`,`模拟手机端竖屏观看体验,视频居中显示,上下黑边区域用于展示弹幕。`,RL,e=>e,y),o([`bilibili`,`videoCodec`],`视频编码格式`,`弹幕烧录时使用的视频编码格式,会自动检测硬件加速。`,LL,e=>e,y)]})),s(`B站推送相关`,(0,U.jsxs)(U.Fragment,{children:[c([`bilibili`,`push`,`switch`],`推送开关`,`推送开关,修改后需重启;使用「#设置B站推送 + UID」配置推送列表。`),o([`bilibili`,`push`,`permission`],`谁可以设置推送`,`修改后需重启。`,IL,e=>e,!h),i([`bilibili`,`push`,`cron`],`定时任务表达式`,`定时推送的时间,支持可视化编辑或手动输入 cron 表达式。`,!h),c([`bilibili`,`push`,`parsedynamic`],`作品解析`,`触发推送时是否一同解析该作品。`,!h),r([`bilibili`,`push`,`parseDynamicTypes`],`需要解析的动态类型`,`选择推送时需要进一步解析的动态类型;未选择的类型只发送动态卡片。`,FL,!h||!g),o([`bilibili`,`push`,`pushVideoQuality`],`解析视频动态时的画质偏好`,`「作品解析」开启时生效,仅对视频动态有效。`,PL.filter(e=>e.value!==`127`),Number,!h||!g),l([`bilibili`,`push`,`pushMaxAutoVideoSize`],`视频动态的视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「解析视频动态时的画质偏好」 为 "自动选择" 且「作品解析」开启时生效,仅对视频动态有效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!h||!g||Number(_)!==0})]}))]})},QL=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderCronField:i,renderPageHeader:a,renderSelectField:o,renderSubSection:s,renderSwitch:c,renderTextField:l}=t,u=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`),d=Q(e,[`douyin`,`switch`],!1),f=Q(e,[`douyin`,`sendContent`],[]),p=Q(e,[`douyin`,`burnDanmaku`],!1),m=Q(e,[`douyin`,`videoQuality`],`adapt`),h=Q(e,[`douyin`,`videoInfoMode`],`text`),g=Q(e,[`douyin`,`push`,`switch`],!1),_=Q(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`),v=!d||!_L(f,`comment`),y=!d||!p;return(0,U.jsxs)(U.Fragment,{children:[a(`抖音`,`抖音解析、画质、弹幕和推送基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[c([`douyin`,`switch`],`解析开关`,`抖音解析开关,此开关为单独开关。`),r([`douyin`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL.filter(e=>e.value!==`image`),!d)]}),s(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[l([`douyin`,`numcomment`],`评论解析数量`,`主评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:v}),l([`douyin`,`subCommentLimit`],`子评论请求数量`,`单条主评论下请求的子评论总条数(含多层嵌套)。注意:UI中最多显示 6 层回复嵌套,超出部分会被隐藏;因实际嵌套深度不可预知,配置数量不代表最终可见数量。`,{type:`number`,fallback:5,min:1,max:20,disabled:v}),c([`douyin`,`commentImageCollection`],`是否收集评论区的图片`,`开启后将收集评论区的图片,以合并转发的形式返回。`,v)]})),s(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[o([`douyin`,`liveImageMergeMode`],`合辑 Live 图 BGM 合并方式`,`合辑 Live 图 BGM 合并方式,仅 Live Photo 模式不是「仅实况图」时生效。`,[{label:`连续`,value:`continuous`,description:`BGM 接续播放,结束后自动循环`},{label:`独立`,value:`independent`,description:`每张图 BGM 从头开始`}],e=>e,!d||u===`livephoto_only`),o([`douyin`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,NL,e=>e,!d),l([`douyin`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!d||m!==`adapt`}),o([`douyin`,`videoInfoMode`],`视频信息返回形式`,`视频信息返回文本或图片。`,[{label:`图片模式`,value:`image`},{label:`文本模式`,value:`text`}],e=>e,!d),r([`douyin`,`displayContent`],`视频信息的内容`,`若什么都不选,则不会返回任何视频相关信息。`,ML.filter(e=>e.value!==`desc`),!d||h===`image`)]})),s(`权限设置`,(0,U.jsx)(U.Fragment,{children:t.renderPermField([`douyin`,`loginPerm`],`谁可以触发扫码登录`,`选「指定账号」后填 QQ 号,多个用逗号分隔。`,{modes:[{value:`all`,label:`所有人`},{value:`admin`,label:`管理员(权限等级 4 及以上)`},{value:`id`,label:`指定账号`}]})})),s(`弹幕烧录相关`,(0,U.jsxs)(U.Fragment,{children:[c([`douyin`,`burnDanmaku`],`弹幕烧录`,`将弹幕硬编码到视频画面中。开启后视频需要重新编码,耗时较长。`,!d),o([`douyin`,`danmakuArea`],`弹幕显示区域`,`限制弹幕范围,避免遮挡视频主体。`,zL,Number,y),o([`douyin`,`danmakuFontSize`],`弹幕字号`,`弹幕文字大小。`,BL,e=>e,y),l([`douyin`,`danmakuOpacity`],`弹幕透明度`,`0为完全透明,100为完全不透明,推荐70。`,{type:`number`,fallback:70,min:0,max:100,disabled:y}),o([`douyin`,`verticalMode`],`竖屏适配`,`针对横屏视频,模拟手机端竖屏观看体验,视频居中显示,上下黑边区域用于展示弹幕。`,RL,e=>e,y),o([`douyin`,`videoCodec`],`视频编码格式`,`烧录弹幕后的视频编码格式。`,LL,e=>e,y)]})),s(`抖音推送相关`,(0,U.jsxs)(U.Fragment,{children:[c([`douyin`,`push`,`switch`],`推送开关`,`推送开关,修改后需重启;使用「#设置抖音推送 + 抖音号」配置推送列表。`),o([`douyin`,`push`,`permission`],`谁可以设置推送`,`修改后需重启。`,IL,e=>e,!g),i([`douyin`,`push`,`cron`],`定时任务表达式`,`定时推送的时间,支持可视化编辑或手动输入 cron 表达式。`,!g),c([`douyin`,`push`,`parsedynamic`],`作品解析`,`触发推送时是否一同解析该作品。`,!g),o([`douyin`,`push`,`shareType`],`推送图二维码的类型`,`推送图二维码识别后的跳转类型。`,[{label:`网页链接`,value:`web`,description:`识别后访问抖音官网对应的作品地址`},{label:`下载链接`,value:`download`,description:`识别后访问无水印作品下载地址`}],e=>e,!g),o([`douyin`,`push`,`pushVideoQuality`],`画质偏好`,`推送解析时解析视频的分辨率偏好。`,NL,e=>e,!g),l([`douyin`,`push`,`pushMaxAutoVideoSize`],`视频体积上限(MB)`,`推送解析时根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!g||_!==`adapt`})]}))]})},$L=({config:e,renderers:t,classes:n})=>{let{renderPageHeader:r,renderSubSection:i,renderSwitch:a,renderTextField:o}=t,s=Q(e,[`kuaishou`,`switch`],!1),c=Q(e,[`kuaishou`,`comment`],!1);return(0,U.jsxs)(U.Fragment,{children:[r(`快手`,`快手解析基础设置。`),(0,U.jsx)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:a([`kuaishou`,`switch`],`解析开关`,`快手解析开关,此开关为单独开关。`)}),i(`评论详情设置`,(0,U.jsxs)(U.Fragment,{children:[a([`kuaishou`,`comment`],`评论解析`,`快手评论解析,开启后可发送快手作品评论图。`,!s),o([`kuaishou`,`numcomment`],`评论解析数量`,`快手评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:!s||!c})]}))]})},eR=({children:e,disabled:t,message:n,device:r})=>t?r===`mobile`?(0,U.jsxs)(gv,{children:[(0,U.jsx)(gv.Trigger,{className:`w-full cursor-not-allowed`,children:e}),(0,U.jsxs)(gv.Content,{placement:`bottom`,children:[(0,U.jsx)(gv.Arrow,{}),(0,U.jsx)(`div`,{className:`px-3 py-2`,children:(0,U.jsx)(`p`,{className:`text-sm text-foreground`,children:n})})]})]}):(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{className:`w-full cursor-not-allowed`,children:e}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),n]})]}):e,tR=e=>e===`desktop`?`grid grid-cols-2 gap-4`:`flex flex-col gap-4`,nR=[{label:`作品列表`,value:`post`,description:`推送用户发布的作品`},{label:`喜欢列表`,value:`favorite`,description:`推送用户喜欢的作品`},{label:`推荐列表`,value:`recommend`,description:`推送推荐的作品`},{label:`直播`,value:`live`,description:`推送直播状态`}],rR=[{label:`投稿视频`,value:`video`,description:`推送UP主投稿的视频`},{label:`图文动态`,value:`draw`,description:`推送图文动态`},{label:`纯文动态`,value:`word`,description:`推送纯文字动态`},{label:`直播动态`,value:`live`,description:`推送直播状态`},{label:`转发动态`,value:`forward`,description:`推送转发的动态`},{label:`投稿专栏`,value:`article`,description:`推送专栏文章`}],iR=[{label:`黑名单`,value:`blacklist`,description:`命中关键词/标签则不推送`},{label:`白名单`,value:`whitelist`,description:`只推送命中关键词/标签的内容`}],aR=({label:e,description:t,items:n,onAdd:r,onRemove:i,disabled:a=!1})=>{let[o,s]=(0,v.useState)(``),[c,l]=(0,v.useState)(``),u=()=>{let e=o.trim();if(!e){l(`请输入内容`);return}if(n.includes(e)){l(`该项已存在,请勿重复添加`);return}r(e),s(``),l(``)};return(0,U.jsxs)(`div`,{className:`space-y-2`,children:[(0,U.jsxs)(`div`,{className:`flex gap-2`,children:[(0,U.jsxs)(lx,{className:`flex-1`,isDisabled:a,isInvalid:!!c,value:o,onChange:e=>{s(e),c&&l(``)},children:[(0,U.jsx)(dx,{children:e}),(0,U.jsx)(cx,{variant:`secondary`,placeholder:`输入${e}`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),u())}}),c?(0,U.jsx)(hx,{children:c}):null]}),(0,U.jsx)(Vg,{isDisabled:a,variant:`secondary`,onPress:u,children:(0,U.jsx)(Hj,{className:`size-4`})})]}),n.length>0?(0,U.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:n.map(e=>(0,U.jsxs)(v_,{color:`accent`,variant:`soft`,children:[(0,U.jsx)(`span`,{children:e}),a?null:(0,U.jsx)(`button`,{type:`button`,className:`ml-1 rounded-full p-0.5 hover:bg-black/10`,onClick:()=>i(e),children:(0,U.jsx)(Kj,{className:`size-3`})})]},e))}):(0,U.jsxs)(px,{children:[`暂无`,e]}),(0,U.jsx)(px,{children:t})]})},oR=(e,t)=>{if((e.success||e.code===200)&&e.data!==void 0)return e.data;throw Error(e.message||t)},sR=async()=>{let r=(await eI.get(`/kkk/v1/bots`)).data?.data;return Array.isArray(r)?r:[]},cR=async e=>{let r=(await eI.get(`/kkk/v1/bots/${encodeURIComponent(e)}/groups`)).data?.data;return Array.isArray(r)?r:[]},lR=async e=>{if(!e.length)return [];let r=(await eI.post(`/kkk/v1/groups/batch`,{groups:e})).data?.data;return Array.isArray(r)?r:[]},uR=({mapping:e,compact:t=!1,stacked:n=!1})=>n?(0,U.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.groupName||e.groupId,src:e.groupAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.groupName||e.groupId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.groupName||e.groupId}),(0,U.jsx)(px,{className:`block truncate`,children:e.groupId})]})]}),(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 pl-8`,children:[(0,U.jsx)(Nj,{className:`size-4 shrink-0 text-muted`}),(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.botName||e.botId,src:e.botAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.botName||e.botId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.botName||e.botId}),(0,U.jsx)(px,{className:`block truncate`,children:t?e.botId:`Bot ${e.botId}`})]})]})]}):(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.groupName||e.groupId,src:e.groupAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.groupName||e.groupId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.groupName||e.groupId}),(0,U.jsx)(px,{className:`block truncate`,children:e.groupId})]}),(0,U.jsx)(Nj,{className:`size-4 shrink-0 text-muted`}),(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.botName||e.botId,src:e.botAvatar}),(0,U.jsx)(Ig.Fallback,{children:(e.botName||e.botId).slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(dx,{className:`block truncate`,children:e.botName||e.botId}),(0,U.jsx)(px,{className:`block truncate`,children:t?e.botId:`Bot ${e.botId}`})]})]}),dR=e=>`${e.groupId}:${e.botId}`,fR=e=>{let[t,n,r]=e.split(`:`);return!t||!n||r!==void 0?null:{groupId:t,botId:n}},pR=e=>{let t=new Set,n=[];return e.forEach(e=>{let r=fR(e);if(!r)return;let i=dR(r);t.has(i)||(t.add(i),n.push(i))}),n},mR=({device:e,mappings:t,onEdit:n,onRemove:r})=>(0,U.jsxs)(`div`,{className:e===`mobile`?`flex min-h-0 min-w-0 flex-1 flex-col gap-4`:`flex min-w-0 flex-col gap-3`,children:[(0,U.jsxs)(`div`,{children:[(0,U.jsx)(dx,{children:`已配置目标`}),(0,U.jsxs)(px,{children:[t.length,` 个推送目标`]})]}),t.length>0?(0,U.jsx)(`div`,{className:e===`mobile`?`flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto pb-2`:`flex max-h-72 flex-col gap-2 overflow-y-auto`,children:t.map(t=>{let i=dR(t);return(0,U.jsxs)(`div`,{className:`flex min-w-0 items-start gap-2 rounded-lg border border-default-200 bg-default-50/50 p-2.5`,children:[(0,U.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,U.jsx)(uR,{compact:!0,mapping:t,stacked:e===`mobile`})}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`编辑推送目标`,size:`sm`,variant:`tertiary`,onPress:()=>n(i),children:(0,U.jsx)(Vj,{className:`size-4`})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),`编辑`]})]}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":`删除推送目标`,size:`sm`,variant:`danger`,onPress:()=>r(i),children:(0,U.jsx)(Kj,{className:`size-4`})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`top`,children:[(0,U.jsx)(tx.Arrow,{}),`删除`]})]})]},i)})}):(0,U.jsx)(`div`,{className:`rounded-lg border border-dashed border-default-300 px-4 py-5 text-sm text-muted`,children:`还没有推送目标,点击上方按钮添加。`})]}),hR=({label:e,description:t,placeholder:n,disabled:r=!1,items:i,selectedId:a,onSelect:o})=>(0,U.jsxs)(Ax,{fullWidth:!0,allowsEmptyCollection:!0,isDisabled:r,placeholder:n,value:a||null,variant:`secondary`,onChange:e=>o(String(e||``)),children:[(0,U.jsx)(dx,{children:e}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{children:({defaultChildren:e,isPlaceholder:t,state:n})=>{if(t||n.selectedItems.length===0)return e;let r=i.find(e=>e.id===n.selectedItems[0]?.key);return r?(0,U.jsxs)(`span`,{className:`flex min-w-0 items-center gap-3`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:r.name,src:r.avatar}),(0,U.jsx)(Ig.Fallback,{children:r.name.slice(0,1)})]}),(0,U.jsxs)(`span`,{className:`min-w-0`,children:[(0,U.jsx)(`span`,{className:`block truncate`,children:r.name}),(0,U.jsx)(`span`,{className:`block truncate text-xs text-muted`,children:r.description})]})]}):e}}),(0,U.jsx)(Ax.Indicator,{})]}),(0,U.jsx)(px,{children:t}),!r&&i.length===0?(0,U.jsx)(px,{className:`text-warning`,children:`当前没有可选项`}):null,(0,U.jsx)(Ax.Popover,{className:`max-h-72`,children:(0,U.jsx)(wx,{items:i,children:e=>(0,U.jsxs)(wx.Item,{id:e.id,textValue:`${e.name} ${e.description}`,children:[(0,U.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3`,children:[(0,U.jsxs)(Ig,{size:`sm`,children:[(0,U.jsx)(Ig.Image,{alt:e.name,src:e.avatar}),(0,U.jsx)(Ig.Fallback,{children:e.name.slice(0,1)})]}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(dx,{className:`truncate`,children:e.name}),(0,U.jsx)(px,{className:`truncate`,children:e.description})]})]}),(0,U.jsx)(wx.ItemIndicator,{})]})})})]}),gR=({isOpen:e,device:t,initialMapping:n,onOpenChange:r,onConfirm:i})=>{let[a,o]=(0,v.useState)([]),[s,c]=(0,v.useState)([]),[l,u]=(0,v.useState)(n?.botId||``),[d,f]=(0,v.useState)(n?.groupId||``),[p,m]=(0,v.useState)(!0),[h,g]=(0,v.useState)(!!n?.botId),[_,y]=(0,v.useState)(``);(0,v.useEffect)(()=>{e&&(u(n?.botId||``),f(n?.groupId||``),c([]),o([]),m(!0),g(!!n?.botId),y(``))},[e,n?.botId,n?.groupId]);let b=(0,v.useMemo)(()=>a.find(e=>e.id===l),[a,l]),x=(0,v.useMemo)(()=>s.find(e=>e.id===d),[s,d]),S=(0,v.useMemo)(()=>a.map(e=>({id:e.id,name:e.name,avatar:e.avatar,description:e.id})),[a]),C=(0,v.useMemo)(()=>s.map(e=>({id:e.id,name:e.name,avatar:e.avatar,description:e.id})),[s]),w=!!(l&&d);(0,v.useEffect)(()=>{e&&sR().then(o).catch(e=>{y(e instanceof Error?e.message:`获取 Bot 列表失败`)}).finally(()=>m(!1))},[e]),(0,v.useEffect)(()=>{!e||!l||cR(l).then(e=>{c(e),f(t=>e.some(e=>e.id===t)?t:``)}).catch(e=>{y(e instanceof Error?e.message:`获取群列表失败`)}).finally(()=>g(!1))},[e,l]);let T=()=>{if(!w||!b)return;let e={groupId:(x&&x.id)||String(d||``).trim(),botId:b.id};x&&x.name&&(e.groupName=x.name),x&&x.avatar&&(e.groupAvatar=x.avatar),b.name&&(e.botName=b.name),b.avatar&&(e.botAvatar=b.avatar),b.isOnline!==void 0&&(e.isOnline=b.isOnline),i(e)},E=t===`desktop`?`right`:`bottom`,D=n?`编辑推送目标`:`添加推送目标`;return(0,U.jsx)(pv.Backdrop,{isOpen:e,onOpenChange:r,children:(0,U.jsx)(pv.Content,{placement:E,children:(0,U.jsxs)(pv.Dialog,{className:t===`desktop`?`h-full w-105 max-w-[90vw]`:`max-h-[78dvh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsxs)(pv.Header,{children:[(0,U.jsx)(pv.Heading,{children:D}),(0,U.jsx)(px,{children:`先选择机器人账号,再填写要推送的群号。`})]}),(0,U.jsxs)(pv.Body,{className:`flex flex-col gap-4`,children:[(0,U.jsx)(hR,{description:`Koishi 当前已注册且在线的 Bot。`,disabled:p,items:S,label:`机器人账号`,placeholder:`选择机器人账号`,selectedId:l,onSelect:e=>{y(``),c([]),g(!!e),u(e),f(``)}}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(dx,{className:`font-semibold`,children:`推送群`}),(0,U.jsx)(`input`,{className:`w-full rounded-large border border-default-200 bg-default-100 px-3 py-2 text-sm outline-none`,placeholder:`填写群号,例如 1050229473`,value:d||``,onChange:e=>f(e.target.value)}),(0,U.jsx)(px,{className:`text-xs`,children:`直接填群号(频道 id)即可;要指定平台时写成 平台:群号。`})]}),p||h?(0,U.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-muted`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取列表`}),(0,U.jsx)(`span`,{children:`正在读取列表`})]}):null,b&&x?(0,U.jsxs)(`div`,{className:`flex flex-col gap-2 rounded-lg border border-default-200 bg-default-50/60 p-3`,children:[(0,U.jsx)(dx,{children:`将写入`}),(0,U.jsxs)(px,{className:`mt-1`,children:[x.name,`(`,x.id,`) -> `,b.name,`(`,b.id,`)`]})]}):null,_?(0,U.jsx)(px,{className:`text-danger`,children:_}):null]}),(0,U.jsxs)(pv.Footer,{children:[(0,U.jsx)(Vg,{size:t===`mobile`?`sm`:`md`,slot:`close`,variant:`secondary`,children:`取消`}),(0,U.jsx)(Vg,{size:t===`mobile`?`sm`:`md`,slot:`close`,isDisabled:!w,onPress:T,children:n?`保存`:`添加`})]})]})})})},_R=(e,t,n)=>{let r=pR(e);return{values:r,mappings:r.map(e=>{let r=fR(e),i=n[e]||t.find(t=>dR(t)===e);if(!r)return null;let a={groupId:r.groupId,botId:r.botId};return i?.groupName&&(a.groupName=i.groupName),i?.groupAvatar&&(a.groupAvatar=i.groupAvatar),i?.botName&&(a.botName=i.botName),i?.botAvatar&&(a.botAvatar=i.botAvatar),i?.isOnline!==void 0&&(a.isOnline=i.isOnline),a}).filter(e=>!!e)}},vR=({isOpen:e,values:t,mappings:n,device:r,onOpenChange:i,onApply:a})=>{let[o,s]=(0,v.useState)(()=>pR(t)),[c,l]=(0,v.useState)({}),[u,d]=(0,v.useState)(null),[f,p]=(0,v.useState)(!1),m=(0,v.useMemo)(()=>_R(o,n,c),[o,c,n]),h=r===`desktop`?`right`:`bottom`,g=u?fR(u):null,_=e=>{d(e),p(!0)};return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(pv.Backdrop,{isOpen:e,onOpenChange:e=>{e||a(m.values),i(e)},variant:`blur`,children:(0,U.jsx)(pv.Content,{placement:h,children:(0,U.jsxs)(pv.Dialog,{className:r===`desktop`?`h-full w-130 max-w-[90vw]`:`max-h-[84dvh]`,children:[(0,U.jsx)(pv.Handle,{}),(0,U.jsx)(pv.CloseTrigger,{}),(0,U.jsxs)(pv.Header,{children:[(0,U.jsx)(pv.Heading,{children:`推送目标`}),(0,U.jsx)(px,{children:`管理所有接收推送的群和 Bot 映射。`})]}),(0,U.jsxs)(pv.Body,{className:`flex min-h-0 flex-col gap-3`,children:[(0,U.jsxs)(Vg,{className:`self-start`,size:r===`mobile`?`sm`:`md`,onPress:()=>_(null),children:[(0,U.jsx)(Hj,{className:`size-4`}),`添加推送目标`]}),(0,U.jsx)(mR,{device:r,mappings:m.mappings,onEdit:e=>_(e),onRemove:e=>{s(t=>t.filter(t=>t!==e)),l(t=>{let n={...t};return delete n[e],n})}})]}),(0,U.jsxs)(pv.Footer,{children:[(0,U.jsx)(Vg,{size:r===`mobile`?`sm`:`md`,slot:`close`,variant:`secondary`,children:`取消`}),(0,U.jsx)(Vg,{size:r===`mobile`?`sm`:`md`,slot:`close`,onPress:()=>{a(m.values)},children:`完成`})]})]})})}),(0,U.jsx)(gR,{device:r,initialMapping:g,isOpen:f,onConfirm:e=>{let t=dR(e),n=[...o],r=u?n.indexOf(u):-1;r>=0?n[r]=t:n.unshift(t),s(pR(n)),l(n=>{let r={...n,[t]:e};return u&&u!==t&&delete r[u],r}),p(!1),d(null)},onOpenChange:p},u||`new`)]})},yR=(e,t)=>{let n=fR(e);if(!n)return null;let r={groupId:n.groupId,botId:n.botId};return t?.groupName&&(r.groupName=t.groupName),t?.groupAvatar&&(r.groupAvatar=t.groupAvatar),t?.botName&&(r.botName=t.botName),t?.botAvatar&&(r.botAvatar=t.botAvatar),t?.isOnline!==void 0&&(r.isOnline=t.isOnline),r},bR=({value:e,disabled:t,itemLabel:n,device:r,onChange:i})=>{let a=(0,v.useMemo)(()=>pR(e),[e]),o=(0,v.useMemo)(()=>e.filter(e=>!fR(e)),[e]),[s,c]=(0,v.useState)([]),[l,u]=(0,v.useState)(!1),[d,f]=(0,v.useState)(!1),p=(0,v.useMemo)(()=>a.map(e=>{let t=fR(e);return yR(e,t?s.find(e=>e.groupId===t.groupId&&e.botId===t.botId):void 0)}).filter(e=>!!e),[s,a]);(0,v.useEffect)(()=>{lR(a.map(fR).filter(e=>!!e)).then(c).catch(()=>c([])).finally(()=>u(!1))},[a]);let m=e=>i(pR(e)),h=`开启【${n}】的推送开关后才能编辑此字段`,g=a.length>0?`已配置 ${a.length} 个推送目标`:`还没有配置推送目标`;return(0,U.jsx)(eR,{disabled:t,device:r,message:h,children:(0,U.jsxs)(`div`,{className:`space-y-3`,children:[(0,U.jsxs)(`div`,{className:`flex items-center justify-between gap-4 rounded-lg border border-default-200 bg-default-50/50 px-4 py-3`,children:[(0,U.jsxs)(`div`,{className:`flex flex-col min-w-0`,children:[(0,U.jsx)(dx,{children:`推送目标`}),(0,U.jsx)(px,{className:`mt-1`,children:g})]}),(0,U.jsxs)(Vg,{isDisabled:t,size:r===`mobile`?`sm`:`md`,variant:r===`mobile`?`primary`:`secondary`,onPress:()=>f(!0),children:[(0,U.jsx)(Vj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`管理`})]})]}),l?(0,U.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-muted`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取推送目标`}),(0,U.jsx)(`span`,{children:`正在读取推送目标`})]}):null,o.length>0?(0,U.jsxs)(`div`,{className:`rounded-lg border border-warning/30 bg-warning/10 p-3 text-sm`,children:[(0,U.jsxs)(`div`,{className:`flex items-center gap-2 font-medium text-warning`,children:[(0,U.jsx)(qj,{className:`size-4`}),(0,U.jsxs)(`span`,{children:[`发现 `,o.length,` 条旧格式或错误格式`]})]}),(0,U.jsx)(px,{className:`mt-1`,children:`建议删除后用可视化选择重新添加,避免后端解析异常。`})]}):null,(0,U.jsx)(vR,{device:r,isOpen:d,mappings:p,values:a,onApply:m,onOpenChange:f})]})})},xR=({disabled:e,itemLabel:t,device:n,value:r,onChange:i})=>(0,U.jsx)(bR,{disabled:e,device:n,itemLabel:t,value:r,onChange:i}),SR=({disabled:e,itemLabel:t,device:n,options:r,value:i,onChange:a})=>(0,U.jsx)(eR,{disabled:e,device:n,message:`开启【${t}】的推送开关后才能编辑此字段`,children:(0,U.jsxs)(c_,{"aria-label":`推送类型`,isDisabled:e,value:i,onChange:e=>a(e),children:[(0,U.jsx)(dx,{children:`推送类型`}),(0,U.jsx)(px,{children:`选择要推送的内容类型`}),(0,U.jsx)(`div`,{className:`mt-2 ${tR(n)}`,children:r.map(e=>(0,U.jsxs)(m_,{value:e.value,variant:`secondary`,children:[(0,U.jsxs)(m_.Content,{children:[(0,U.jsx)(m_.Control,{children:(0,U.jsx)(m_.Indicator,{})}),e.label]}),(0,U.jsx)(px,{children:e.description})]},e.value))})]})}),CR=({disabled:e,itemLabel:t,device:n,value:r,onChange:i})=>(0,U.jsx)(eR,{disabled:e,device:n,message:`开启【${t}】的推送开关后才能编辑此字段`,children:(0,U.jsxs)(Ax,{fullWidth:!0,isDisabled:e,value:r,onChange:e=>{e&&!Array.isArray(e)&&i(e)},children:[(0,U.jsx)(dx,{children:`过滤模式`}),(0,U.jsxs)(Ax.Trigger,{children:[(0,U.jsx)(Ax.Value,{}),(0,U.jsx)(Ax.Indicator,{})]}),(0,U.jsx)(px,{children:`设置关键词/标签的过滤方式`}),(0,U.jsx)(Ax.Popover,{children:(0,U.jsx)(wx,{children:iR.map(e=>(0,U.jsxs)(wx.Item,{id:e.value,textValue:e.label,children:[(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(dx,{children:e.label}),(0,U.jsx)(px,{children:e.description})]}),(0,U.jsx)(wx.ItemIndicator,{})]},e.value))})})]})}),wR=({disabled:e,itemLabel:t,device:n,keywords:r,tags:i,onKeywordsChange:a,onTagsChange:o})=>{let s=`开启【${t}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(eR,{disabled:e,device:n,message:s,children:(0,U.jsx)(`div`,{children:(0,U.jsx)(aR,{label:`关键词`,description:`多个关键词用于内容过滤`,disabled:e,items:r,onAdd:e=>a([...r,e]),onRemove:e=>a(r.filter(t=>t!==e))})})}),(0,U.jsx)(eR,{disabled:e,device:n,message:s,children:(0,U.jsx)(`div`,{children:(0,U.jsx)(aR,{label:`标签`,description:`多个标签用于内容过滤`,disabled:e,items:i,onAdd:e=>o([...i,e]),onRemove:e=>o(i.filter(t=>t!==e))})})})]})},TR=({onDelete:e})=>(0,U.jsxs)(Vg,{className:`w-full`,variant:`danger`,onPress:e,children:[(0,U.jsx)(Kj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`删除此推送项`})]}),ER=({item:e,index:t,list:n,onChange:r,device:i})=>{let a=i=>{let a=[...n];a[t]={...e,...i},r(a)},o=!e.switch,s=e.remark||`UID: ${e.host_mid}`||`未命名`,c=`开启【${s}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(Fc.Item,{id:`bilibili-${t}`,children:[(0,U.jsx)(Fc.Heading,{children:(0,U.jsxs)(Fc.Trigger,{children:[(0,U.jsxs)(`div`,{className:`flex flex-1 items-center gap-3`,children:[(0,U.jsx)(`div`,{onClick:e=>e.stopPropagation(),onPointerDown:e=>e.stopPropagation(),children:(0,U.jsx)(ob,{"aria-label":`推送开关`,isSelected:e.switch,onChange:e=>a({switch:e}),children:(0,U.jsx)(ob.Content,{children:(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})})})})}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(`span`,{className:`font-medium`,children:e.remark||`UID: ${e.host_mid}`||`推送项 ${t+1}`}),(0,U.jsxs)(px,{className:`text-xs`,children:[`B站 UID: `,e.host_mid]})]})]}),(0,U.jsx)(Fc.Indicator,{children:(0,U.jsx)(Pj,{className:`size-5`})})]})}),(0,U.jsx)(Fc.Panel,{children:(0,U.jsx)(Fc.Body,{children:(0,U.jsxs)(`div`,{className:`space-y-4`,children:[(0,U.jsxs)(`div`,{className:tR(i),children:[(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,isRequired:!0,type:`number`,value:String(e.host_mid),onChange:e=>a({host_mid:Number(e)||0}),children:[(0,U.jsx)(dx,{children:`B站 UID`}),(0,U.jsx)(cx,{placeholder:`UP主的 UID`}),(0,U.jsx)(px,{children:`B站用户的唯一标识,必填`})]})}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.remark,onChange:e=>a({remark:e}),children:[(0,U.jsx)(dx,{children:`备注名称`}),(0,U.jsx)(cx,{placeholder:`可选,用于识别该推送项`}),(0,U.jsx)(px,{children:`方便识别的名称,如:UP主昵称`})]})})]}),(0,U.jsx)(xR,{disabled:o,device:i,itemLabel:s,value:e.group_id,onChange:e=>a({group_id:e})}),(0,U.jsx)(SR,{disabled:o,device:i,itemLabel:s,options:rR,value:e.pushTypes||[],onChange:e=>a({pushTypes:e})}),(0,U.jsx)(CR,{disabled:o,device:i,itemLabel:s,value:e.filterMode||`blacklist`,onChange:e=>a({filterMode:e})}),(0,U.jsx)(wR,{disabled:o,device:i,itemLabel:s,keywords:e.Keywords||[],tags:e.Tags||[],onKeywordsChange:e=>a({Keywords:e}),onTagsChange:e=>a({Tags:e})}),(0,U.jsx)(TR,{onDelete:()=>r(n.filter((e,n)=>n!==t))})]})})})]},t)},DR=({item:e,index:t,list:n,onChange:r,device:i})=>{let a=i=>{let a=[...n];a[t]={...e,...i},r(a)},o=!e.switch,s=e.remark||e.short_id||e.sec_uid||`未命名`,c=`开启【${s}】的推送开关后才能编辑此字段`;return(0,U.jsxs)(Fc.Item,{id:`douyin-${t}`,children:[(0,U.jsx)(Fc.Heading,{children:(0,U.jsxs)(Fc.Trigger,{children:[(0,U.jsxs)(`div`,{className:`flex flex-1 items-center gap-3`,children:[(0,U.jsx)(`div`,{onClick:e=>e.stopPropagation(),onPointerDown:e=>e.stopPropagation(),children:(0,U.jsx)(ob,{"aria-label":`推送开关`,isSelected:e.switch,onChange:e=>a({switch:e}),children:(0,U.jsx)(ob.Content,{children:(0,U.jsx)(ob.Control,{children:(0,U.jsx)(ob.Thumb,{})})})})}),(0,U.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,U.jsx)(`span`,{className:`font-medium`,children:e.remark||e.short_id||e.sec_uid||`推送项 ${t+1}`}),(0,U.jsxs)(px,{className:`text-xs`,children:[e.short_id&&`抖音号: ${e.short_id}`,e.sec_uid&&!e.short_id&&`sec_uid: ${e.sec_uid.slice(0,20)}...`]})]})]}),(0,U.jsx)(Fc.Indicator,{children:(0,U.jsx)(Pj,{className:`size-5`})})]})}),(0,U.jsx)(Fc.Panel,{children:(0,U.jsx)(Fc.Body,{children:(0,U.jsxs)(`div`,{className:`space-y-4`,children:[(0,U.jsxs)(`div`,{className:tR(i),children:[(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,isRequired:!0,value:e.short_id,onChange:e=>a({short_id:e}),children:[(0,U.jsx)(dx,{children:`抖音号`}),(0,U.jsx)(cx,{placeholder:`用户的抖音号`,variant:`secondary`}),(0,U.jsx)(px,{children:`用户的抖音号(short_id),必填`})]})}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.sec_uid,onChange:e=>a({sec_uid:e}),children:[(0,U.jsx)(dx,{children:`sec_uid`}),(0,U.jsx)(cx,{placeholder:`选填,会根据抖音号自动获取`,variant:`secondary`}),(0,U.jsx)(px,{children:`用户的 sec_uid,可从分享链接获取。选填,推送时会自动获取`})]})})]}),(0,U.jsx)(eR,{disabled:o,device:i,message:c,children:(0,U.jsxs)(lx,{fullWidth:!0,isDisabled:o,value:e.remark,onChange:e=>a({remark:e}),children:[(0,U.jsx)(dx,{children:`备注名称`}),(0,U.jsx)(cx,{placeholder:`可选,用于识别该推送项`,variant:`secondary`}),(0,U.jsx)(px,{children:`方便识别的名称,如:博主昵称`})]})}),(0,U.jsx)(xR,{disabled:o,device:i,itemLabel:s,value:e.group_id,onChange:e=>a({group_id:e})}),(0,U.jsx)(SR,{disabled:o,device:i,itemLabel:s,options:nR,value:e.pushTypes||[],onChange:e=>a({pushTypes:e})}),(0,U.jsx)(CR,{disabled:o,device:i,itemLabel:s,value:e.filterMode||`blacklist`,onChange:e=>a({filterMode:e})}),(0,U.jsx)(wR,{disabled:o,device:i,itemLabel:s,keywords:e.Keywords||[],tags:e.Tags||[],onKeywordsChange:e=>a({Keywords:e}),onTagsChange:e=>a({Tags:e})}),(0,U.jsx)(TR,{onDelete:()=>r(n.filter((e,n)=>n!==t))})]})})})]},t)},OR=()=>({switch:!0,sec_uid:``,short_id:``,group_id:[],remark:``,pushTypes:[`post`],filterMode:`blacklist`,Keywords:[],Tags:[]}),kR=()=>({switch:!0,host_mid:0,group_id:[],remark:``,pushTypes:[`video`],filterMode:`blacklist`,Keywords:[],Tags:[]}),AR=({platform:e})=>(0,U.jsx)(`div`,{className:`rounded-lg border-2 border-dashed border-gray-300 p-8 text-center`,children:(0,U.jsxs)(`p`,{className:`text-muted`,children:[`暂无`,e===`douyin`?`抖音`:`B站`,`推送项,点击上方按钮添加`]})});function jR({douyinList:e,bilibiliList:t,onDouyinChange:n,onBilibiliChange:r,device:i}){let[a,o]=(0,v.useState)(`douyin`);return(0,U.jsx)(`div`,{className:`space-y-4`,children:(0,U.jsxs)(kb,{selectedKey:a,onSelectionChange:e=>o(e),children:[(0,U.jsx)(kb.ListContainer,{children:(0,U.jsxs)(kb.List,{children:[(0,U.jsxs)(kb.Tab,{id:`douyin`,children:[(0,U.jsx)(`span`,{children:`抖音推送`}),(0,U.jsx)(kb.Indicator,{})]}),(0,U.jsxs)(kb.Tab,{id:`bilibili`,children:[(0,U.jsx)(`span`,{children:`B站推送`}),(0,U.jsx)(kb.Indicator,{})]})]})}),(0,U.jsx)(kb.Panel,{id:`douyin`,children:(0,U.jsxs)(`div`,{className:`space-y-4 pt-4`,children:[(0,U.jsxs)(Vg,{className:`w-full`,variant:`primary`,size:`sm`,onPress:()=>n([...e,OR()]),children:[(0,U.jsx)(Hj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`添加抖音推送项`})]}),e.length>0?(0,U.jsx)(Fc,{variant:`surface`,"aria-label":`抖音推送列表`,children:e.map((t,r)=>(0,U.jsx)(DR,{device:i,index:r,item:t,list:e,onChange:n},r))}):(0,U.jsx)(AR,{platform:`douyin`})]})}),(0,U.jsx)(kb.Panel,{id:`bilibili`,children:(0,U.jsxs)(`div`,{className:`space-y-4 pt-4`,children:[(0,U.jsxs)(Vg,{className:`w-full`,variant:`primary`,onPress:()=>r([...t,kR()]),children:[(0,U.jsx)(Hj,{className:`size-4`}),(0,U.jsx)(`span`,{children:`添加B站推送项`})]}),t.length>0?(0,U.jsx)(Fc,{variant:`surface`,"aria-label":`B站推送列表`,children:t.map((e,n)=>(0,U.jsx)(ER,{device:i,index:n,item:e,list:t,onChange:r},n))}):(0,U.jsx)(AR,{platform:`bilibili`})]})})]})})}var MR=({config:e,device:t,renderers:n,updateConfigValue:r})=>{let{renderPageHeader:i}=n;return(0,U.jsxs)(U.Fragment,{children:[i(`推送列表`,`管理「抖音」与「哔哩哔哩」的推送订阅。`),(0,U.jsx)(jR,{douyinList:e.pushlist?.douyin||[],bilibiliList:e.pushlist?.bilibili||[],onDouyinChange:e=>{r([`pushlist`,`douyin`],e)},onBilibiliChange:e=>{r([`pushlist`,`bilibili`],e)},device:t})]})},NR=({config:e,renderers:t,classes:n})=>{let{renderCheckboxGroup:r,renderPageHeader:i,renderSelectField:a,renderSubSection:o,renderSwitch:s,renderTextField:c}=t,l=Q(e,[`xiaohongshu`,`switch`],!1),u=Q(e,[`xiaohongshu`,`sendContent`],[]),d=Q(e,[`xiaohongshu`,`videoQuality`],`adapt`);return(0,U.jsxs)(U.Fragment,{children:[i(`小红书`,`小红书解析基础设置。`),(0,U.jsxs)(`div`,{className:n.topLevelFields,"data-config-section":!0,children:[s([`xiaohongshu`,`switch`],`解析开关`,`小红书解析开关,此开关为单独开关。`),r([`xiaohongshu`,`sendContent`],`解析时发送的内容`,`若什么都不选,可能不会返回任何解析结果。`,jL,!l),c([`xiaohongshu`,`numcomment`],`评论解析数量`,`小红书评论解析数量。`,{type:`number`,fallback:5,min:1,disabled:!l||!_L(u,`comment`)})]}),o(`渲染与画质设置`,(0,U.jsxs)(U.Fragment,{children:[a([`xiaohongshu`,`videoQuality`],`画质偏好`,`解析视频的分辨率偏好。`,NL,e=>e,!l),c([`xiaohongshu`,`maxAutoVideoSize`],`视频体积上限(MB)`,`根据该值自动选择分辨率进行下载。仅在「画质偏好」 为 "自动选择" 时生效。`,{type:`number`,fallback:50,min:1,max:2e4,disabled:!l||d!==`adapt`})]}))]})},/*KKK-QQ-START*/KKKQQConfig=({config:e,renderers:t})=>{let{renderPageHeader:n,renderSubSection:r,renderSwitch:i,renderTextField:a}=t;return(0,U.jsxs)(U.Fragment,{children:[n(`QQ 适配器`,`这些设置只对 QQ 平台生效,其它平台不受影响。改完点右下角保存即可,不用重启。`),r(`解析面板`,(0,U.jsx)(U.Fragment,{children:[i([`qq`,`qqPanel`],`链接解析面板`,`QQ 里收到链接时先回一条带按钮的面板,让用户自己挑解析内容和画质,点一下才开始下载。关掉就直接按默认配置解析。`),a([`qq`,`qqFileLimitMB`],`画质档体积上限(MB)`,`面板里「清晰度」(= 发到 QQ)这一列的体积上限:超过它的画质档不给发送按钮,那一格标「超上限」。QQ 单个视频上限 200MB,选了也发不出去,所以默认 200。**在线播放模式下画质档位不再按这个值过滤**:视频根本不发到 QQ,所有档位都会列出来,超过这个值的档位只是不能发到 QQ,右边的「在线看」照常可用(它受「在线播放最大文件」约束)。`,{type:`number`,fallback:200,min:1,max:2000}),i([`qq`,`qqPanelDanmaku`],`面板显示「烧录弹幕」列`,`只对**烧录模式**生效(通用里把「弹幕重定向在线播放器」关掉之后):打开后,QQ 里的解析面板会多一列「烧录弹幕」,用户点它就按那一档画质把弹幕烧进视频再发。在线播放模式下那一列由「弹幕重定向在线播放器」自己控制(开着就有),不需要在这里开。`),i([`qq`,`qqPanelSourceLink`],`面板带「打开原站」链接`,`打开后,解析面板(以及番剧选集面板)的下方会多一个「打开原站」按钮,点一下直接跳到抖音 / B站的原作品页;关掉就不显示。`)]})),r(`番剧选集面板`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`bangumiPanelCols`],`表格列数`,`番剧分集面板每行放几个集数,默认 5。`,{type:`number`,fallback:5,min:1,max:10}),a([`qq`,`bangumiPanelRows`],`表格行数`,`番剧分集面板每页几行(含表头那一行),默认 4 行。列数 × 行数就是每页的集数。`,{type:`number`,fallback:4,min:1,max:10})]})),r(`图片发送`,(0,U.jsx)(U.Fragment,{children:[i([`qq`,`sliceImageOnDemand`],`超大图片自动切片`,`长图(评论区那种)默认按普通图片发;只有超过 20MB 或者发送失败(拿不到消息 ID)时才自动切成几片,再用一条 markdown 拼回一整张。关掉就一律按普通图片发。`),a([`qq`,`sliceImageHeight`],`切片高度(像素)`,`切片时每片的高度,默认 2000。越大片数越少、字越小;越小越清晰、片数越多。`,{type:`number`,fallback:2000,min:500,max:4000})]})),r(`卡片识别`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`ocrApiKey`],`卡片文字识别密钥`,`群里转发过来的分享卡片没有链接,只能靠截图识别出标题和作者再去搜索。填自己的免费密钥更稳定:https://ocr.space/ocrapi 。留空会用公共测试密钥,容易被限流。`,{type:`password`,placeholder:`留空则使用公共测试密钥`})]})),r(`视频发送`,(0,U.jsx)(U.Fragment,{children:[a([`qq`,`qqGroupFileLimitMB`],`群文件发送阈值(MB)`,`视频体积超过这个值时,改用「群文件」发送。QQ 对富媒体视频会压缩、改名甚至丢掉后缀,走群文件才能原样发出去;填 0 表示不启用。`,{type:`number`,fallback:30,min:0,max:2000})]}))]})}/*KKK-QQ-END*/,PR=e=>{switch(e.activeFile){case`amagi`:return(0,U.jsx)(YL,{...e});case`app`:return(0,U.jsx)(XL,{...e});case`douyin`:return(0,U.jsx)(QL,{...e});case`bilibili`:return(0,U.jsx)(ZL,{...e});case`kuaishou`:return(0,U.jsx)($L,{...e});case`xiaohongshu`:return(0,U.jsx)(NR,{...e});case`pushlist`:return(0,U.jsx)(MR,{...e});case`qq`:return(0,U.jsx)(KKKQQConfig,{...e})}},FR=(e,t)=>{let n=Number(e);return Number.isFinite(n)?t.min!==void 0&&n<t.min?t.error||`${t.label} 不能小于 ${t.min}`:t.max!==void 0&&n>t.max?t.error||`${t.label} 不能大于 ${t.max}`:``:`${t.label} 必须是数字`},IR=(e,t,n)=>{if(n.disabled)return;let r=FR(Q(t,n.path,0),n);r&&(e[pL(n.path)]=r)},LR=e=>typeof e==`string`&&/.+:.+/.test(e),RR=(e,t,n)=>{if(!Array.isArray(n)){e[`pushlist.${t}`]=`${t} 推送列表必须是数组`;return}let r=n.findIndex(e=>{if(!mL(e))return!0;let n=e.group_id,r=t===`douyin`?e.short_id:e.host_mid;return r==null||String(r).trim()===``||!Array.isArray(n)||n.length===0||n.some(e=>!LR(e))});r>=0&&(e[`pushlist.${t}`]=`${t} 推送列表第 ${r+1} 项缺少必填 UID/抖音号,或 group_id 未使用「群号:机器人账号」格式`)},zR=e=>{if(!e)return{};let t={},n=Q(e,[`app`,`livePhotoMode`],`video_and_livephoto`),r=Q(e,[`amagi`,`APIServerMount`],!1),i=Q(e,[`app`,`videoSendMode`],`file`),a=Q(e,[`app`,`usegroupfile`],!1),o=Q(e,[`app`,`usefilelimit`],!1),s=Q(e,[`app`,`compress`],!1),c=Q(e,[`app`,`downloadThrottle`],!1),l=Q(e,[`app`,`downloadAutoReduce`],!1),u=Q(e,[`amagi`,`proxy`,`switch`],!1),d=Q(e,[`douyin`,`switch`],!1),f=Q(e,[`douyin`,`sendContent`],[]),p=Q(e,[`douyin`,`burnDanmaku`],!1),m=Q(e,[`douyin`,`videoQuality`],`adapt`),h=Q(e,[`douyin`,`push`,`switch`],!1),g=Q(e,[`douyin`,`push`,`pushVideoQuality`],`adapt`),_=Q(e,[`bilibili`,`switch`],!1),v=Q(e,[`bilibili`,`sendContent`],[]),y=Q(e,[`bilibili`,`burnDanmaku`],!1),b=Q(e,[`bilibili`,`videoQuality`],0),x=Q(e,[`bilibili`,`push`,`switch`],!1),S=Q(e,[`bilibili`,`push`,`parsedynamic`],!1),C=Q(e,[`bilibili`,`push`,`pushVideoQuality`],0),w=Q(e,[`kuaishou`,`switch`],!1),T=Q(e,[`kuaishou`,`comment`],!1),E=Q(e,[`xiaohongshu`,`switch`],!1),D=Q(e,[`xiaohongshu`,`sendContent`],[]),O=Q(e,[`xiaohongshu`,`videoQuality`],`adapt`);return[{path:[`app`,`renderScale`],label:`渲染精度`,min:50,max:200},{path:[`app`,`ambientCover`,`coverOpacity`],label:`封面氛围强度`,min:0,max:1},{path:[`app`,`ambientCover`,`overlayEdgeOpacity`],label:`氛围压色(顶部/底部)`,min:0,max:1},{path:[`app`,`ambientCover`,`overlayMiddleOpacity`],label:`氛围压色(中间带)`,min:0,max:1},{path:[`app`,`RenderWaitTime`],label:`渲染图片的等待时间`,min:0},{path:[`app`,`multiPageHeight`],label:`分页渲染时,每页的高度`,min:1e3,max:2e4,disabled:!Q(e,[`app`,`multiPageRender`],!0),error:`请输入一个范围在 1000 到 20000 之间的数字`},{path:[`amagi`,`APIServerPort`],label:`API服务端口`,min:1024,max:65535,disabled:r,error:`请输入一个范围在 1024 到 65535 之间的数字`},{path:[`app`,`groupfilevalue`],label:`群文件上传阈值`,min:1,disabled:!a||i===`base64`},{path:[`app`,`filelimit`],label:`视频拦截阈值`,min:1,disabled:!o},{path:[`app`,`compresstrigger`],label:`压缩触发阈值`,min:1,disabled:!s},{path:[`app`,`compressvalue`],label:`压缩后的值`,min:1,disabled:!s},{path:[`app`,`downloadMaxSpeed`],label:`最大下载速度`,min:1,max:1e3,disabled:!c,error:`请输入一个范围在 1 到 1000 之间的数字`},{path:[`app`,`downloadMinSpeed`],label:`最低下载速度`,min:.1,max:100,disabled:!c||!l,error:`请输入一个范围在 0.1 到 100 之间的数字`},{path:[`amagi`,`timeout`],label:`请求超时时间`,min:1e3,max:3e5,error:`请输入一个范围在 1000 到 300000 之间的数字`},{path:[`amagi`,`proxy`,`port`],label:`代理端口`,min:1,max:65535,disabled:!u,error:`请输入一个范围在 1 到 65535 之间的数字`},{path:[`douyin`,`numcomment`],label:`评论解析数量`,min:1,disabled:!d||!_L(f,`comment`)},{path:[`douyin`,`subCommentLimit`],label:`次级评论解析数量`,min:1,max:20,disabled:!d||!_L(f,`comment`)},{path:[`douyin`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!d||m!==`adapt`},{path:[`douyin`,`danmakuOpacity`],label:`弹幕透明度`,min:0,max:100,disabled:!d||!p},{path:[`douyin`,`push`,`pushMaxAutoVideoSize`],label:`推送视频体积上限(MB)`,min:1,max:2e4,disabled:!h||g!==`adapt`},{path:[`bilibili`,`numcomment`],label:`评论解析数量`,min:1,disabled:!_||!_L(v,`comment`)},{path:[`bilibili`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!_||Number(b)!==0},{path:[`bilibili`,`danmakuOpacity`],label:`弹幕透明度`,min:0,max:100,disabled:!_||!y},{path:[`bilibili`,`push`,`pushMaxAutoVideoSize`],label:`视频动态的视频体积上限(MB)`,min:1,max:2e4,disabled:!x||!S||Number(C)!==0},{path:[`kuaishou`,`numcomment`],label:`评论解析数量`,min:1,disabled:!w||!T},{path:[`xiaohongshu`,`numcomment`],label:`评论解析数量`,min:1,disabled:!E||!_L(D,`comment`)},{path:[`xiaohongshu`,`maxAutoVideoSize`],label:`视频体积上限(MB)`,min:1,max:2e4,disabled:!E||O!==`adapt`}].forEach(n=>IR(t,e,n)),n===`video_only`&&delete t[`app.livePhotoSystem`],RR(t,`douyin`,e.pushlist?.douyin||[]),RR(t,`bilibili`,e.pushlist?.bilibili||[]),t},BR=({device:e=`desktop`})=>{let t=(0,v.useRef)(null),[n,r]=JT(),i=Px(),a=n.get(`file`),[o,s]=GS({config:null,savedConfig:null,activeFile:a&&HL.some(e=>e.key===a)?a:`amagi`}),{activeFile:c,config:l,savedConfig:u}=o,d=(0,v.useMemo)(()=>JL(e),[e]),f=e===`mobile`?`sm`:`md`,{loading:p,run:m}=HS(iI,{onSuccess:e=>{s({config:structuredClone(e),savedConfig:structuredClone(e)})},onError:e=>{Ny.danger(`加载配置失败`,{description:e.message})}}),{loading:h,runAsync:g}=HS(aI,{manual:!0}),_=(0,v.useMemo)(()=>!l||!u?!1:!(0,mE.default)(yL(l),yL(u)),[l,u]),y=(0,v.useMemo)(()=>zR(l),[l]),b=(0,v.useMemo)(()=>Object.values(y).some(Boolean),[y]),x=(0,v.useMemo)(()=>_&&!b&&!p,[_,b,p]),S=Ux((e,t)=>{s(n=>n.config?{config:hL(n.config,e,t)}:null)}),C=Ux(()=>{if(!l||b)return;let e=l,t=g(e).then(()=>{s({savedConfig:e})});Ny.promise(t,{loading:`正在保存配置...`,success:`配置已保存`,error:e=>e instanceof Error?e.message:`保存配置失败`})}),w=Ux(()=>{m()}),T=Ux(e=>{r({file:e})}),E=Ux(e=>{e.preventDefault(),C()});(0,v.useEffect)(()=>{let e=n.get(`file`);e&&HL.some(t=>t.key===e)&&e!==c&&s({activeFile:e})},[n,c,s]),(0,v.useEffect)(()=>{let e=t.current?.querySelector(`[data-config-tabs-scroll="true"]`);if(!e)return;let n=t=>{let n=Math.abs(t.deltaX)>Math.abs(t.deltaY)?t.deltaX:t.deltaY;n&&(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),!(e.scrollWidth<=e.clientWidth)&&(e.scrollLeft+=n))};return e.addEventListener(`wheel`,n,{passive:!1}),()=>{e.removeEventListener(`wheel`,n)}},[l]);let D=Ux(()=>{t.current&&Sj.fromTo(t.current.querySelectorAll(`[data-config-section]`),uI,{...dI,duration:sI(.35),stagger:cI(.03)})});(0,v.useEffect)(()=>{!l||t.current?.dataset.animated===`true`||(t.current&&(t.current.dataset.animated=`true`),D())},[l,D]),Wx(()=>{D()},[c]);let O=(0,v.useMemo)(()=>l?GL({config:l,device:e,classes:d,validationErrors:y,updateConfigValue:S}):{},[l,e,d,y,S]);if(p||!l)return(0,U.jsxs)(`div`,{className:`${d.root} ${d.loading}`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在读取配置`}),(0,U.jsx)(`span`,{children:`正在读取配置`})]});let k=(0,U.jsx)(`div`,{className:d.floatingActions,children:(0,U.jsxs)(`div`,{className:d.actionControls,children:[(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`重新读取配置`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:f,variant:`secondary`,isDisabled:p||h,onPress:w,children:(0,U.jsx)(Uj,{size:16,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`bottom`,children:[(0,U.jsx)(tx.Arrow,{}),`重新读取`]})]}),(0,U.jsxs)(tx,{delay:0,children:[(0,U.jsx)(tx.Trigger,{"aria-label":`查看配置变更`,children:(0,U.jsx)(Vg,{isIconOnly:!0,size:f,variant:`secondary`,isDisabled:!_,onPress:i.open,children:(0,U.jsx)(Lj,{size:16,"aria-hidden":`true`})})}),(0,U.jsxs)(tx.Content,{showArrow:!0,placement:`bottom`,children:[(0,U.jsx)(tx.Arrow,{}),`查看变更`]})]}),(0,U.jsxs)(Vg,{size:f,isDisabled:!x,isPending:h,onPress:C,variant:`primary`,children:[(0,U.jsx)(Wj,{size:16,"aria-hidden":`true`}),(0,U.jsx)(`span`,{children:`保存`})]})]})});return(0,U.jsxs)(`div`,{ref:t,className:d.root,children:[(0,U.jsx)(TL,{device:e,original:u,current:l,isOpen:i.isOpen,onOpenChange:i.setOpen}),(0,U.jsxs)(_x,{className:d.form,onSubmit:E,children:[(0,U.jsx)(kb,{className:`w-full min-w-0 max-w-full`,selectedKey:c,onSelectionChange:T,children:(0,U.jsx)(kb.ListContainer,{className:d.tabsListContainer,"data-config-tabs-scroll":`true`,"data-scrollbar":`none`,children:(0,U.jsx)(kb.List,{"aria-label":`配置文件选择`,className:d.tabsList,children:HL.map((e,t)=>(0,U.jsxs)(kb.Tab,{id:e.key,children:[t>0?(0,U.jsx)(kb.Separator,{}):null,(0,U.jsx)(`span`,{className:`whitespace-nowrap`,children:e.label}),(0,U.jsx)(kb.Indicator,{})]},e.key))})})}),(0,U.jsxs)(`div`,{className:`relative min-w-0 max-w-full`,children:[k,(0,U.jsx)(PR,{activeFile:c,classes:d,config:l,device:e,renderers:O,updateConfigValue:S},c)]})]})]})},VR=({onLogin:e})=>{let[t,n]=GS({authKey:``,loading:!1,error:``}),[r,{toggle:i}]=WS(!1),a=r?`隐藏密钥`:`显示密钥`,o=Ux(async r=>{r.preventDefault();let i=t.authKey.trim();if(!i){n({error:`请输入 Koishi HTTP 鉴权密钥`});return}try{n({loading:!0,error:``}),await tI(i),e()}catch(e){n({error:e instanceof Error?e.message:`登录失败`})}finally{n({loading:!1})}});return(0,U.jsx)(Ev,{className:`flex min-h-screen items-center justify-center px-4 py-8`,children:(0,U.jsxs)(Wg,{className:`w-full max-w-105`,children:[(0,U.jsxs)(Wg.Header,{className:`gap-4 p-6`,children:[(0,U.jsx)(zj,{className:`size-8 shrink-0`,"aria-hidden":`true`}),(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(Wg.Title,{children:`Koishi 鉴权`}),(0,U.jsx)(Wg.Description,{children:`使用 Koishi HTTP 鉴权密钥登录后管理 KKK 配置。`})]})]}),(0,U.jsx)(Wg.Content,{className:`p-6`,children:(0,U.jsxs)(_x,{className:`flex flex-col gap-6`,onSubmit:o,children:[(0,U.jsxs)(lx,{fullWidth:!0,isInvalid:!!t.error,value:t.authKey,onChange:e=>{n({authKey:e,error:t.error?``:t.error})},children:[(0,U.jsx)(dx,{children:`HTTP 鉴权密钥`}),(0,U.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,U.jsx)(cx,{autoComplete:`current-password`,className:`min-w-0 flex-1`,placeholder:`请输入 Koishi 的 HTTP_AUTH_KEY`,type:r?`text`:`password`}),(0,U.jsx)(Vg,{isIconOnly:!0,"aria-label":a,type:`button`,variant:`tertiary`,onPress:i,children:r?(0,U.jsx)(Fj,{className:`size-4`,"aria-hidden":`true`}):(0,U.jsx)(Ij,{className:`size-4`,"aria-hidden":`true`})})]}),(0,U.jsx)(px,{children:t.error||`生产环境会复用 Koishi 主 Web 已保存的登录凭据。`})]}),(0,U.jsx)(Vg,{fullWidth:!0,isPending:t.loading,type:`submit`,children:({isPending:e})=>(0,U.jsxs)(U.Fragment,{children:[e?(0,U.jsx)(Tv,{color:`current`,size:`sm`,"aria-label":`登录中`}):(0,U.jsx)(Bj,{className:`size-4`,"aria-hidden":`true`}),(0,U.jsx)(`span`,{children:`登录`})]})})]})})]})})},HR=`theme`,UR=`kkk-theme-changed`,WR=`karin-theme-change`,GR={light:`light`,dark:`dark`,system:`system`,inverse:`inverse`},KR=e=>e===GR.system||e===GR.inverse,qR=e=>e===GR.light||e===GR.dark,JR=e=>!e||typeof e!=`object`?!1:e.type===WR,YR=()=>{let e=localStorage.getItem(HR);if(KR(e))return e;try{let t=JSON.parse(e??``);if(KR(t))return t}catch{}return localStorage.setItem(HR,GR.system),GR.system},XR=()=>window.matchMedia(`(prefers-color-scheme: dark)`).matches?GR.dark:GR.light,ZR=()=>window.matchMedia(`(prefers-color-scheme: dark)`).matches?GR.light:GR.dark,QR=e=>e===GR.system?XR():ZR(),$R=e=>ez(QR(e)),ez=e=>(document.documentElement.classList.remove(GR.light,GR.dark),document.documentElement.classList.add(e),document.documentElement.dataset.theme=e,e),tz=()=>{let[e,t]=(0,v.useState)(()=>YR()),[n,r]=(0,v.useState)(()=>QR(e)),i=(0,v.useRef)(!1),a=(0,v.useCallback)(e=>{localStorage.setItem(HR,e),t(e),r($R(e)),window.dispatchEvent(new CustomEvent(UR,{detail:e}))},[]),o=(0,v.useCallback)(()=>{a(GR.system)},[a]),s=(0,v.useCallback)(()=>{a(GR.inverse)},[a]),c=(0,v.useCallback)(()=>{a(e===GR.system?GR.inverse:GR.system)},[a,e]);return(0,v.useEffect)(()=>{i.current?i.current=!1:r($R(e));let n=window.matchMedia(`(prefers-color-scheme: dark)`),a=()=>{r($R(e))},o=e=>{if(e.key!==HR||window.self!==window.top)return;let n=YR();t(n),r($R(n))},s=e=>{let n=e.detail;KR(n)&&(t(n),r($R(n)))},c=e=>{if(!JR(e.data))return;let n=e.data.theme,a=KR(n??null)?n:YR(),o=qR(e.data.appliedTheme)?e.data.appliedTheme:QR(a);i.current=!0,localStorage.setItem(HR,a),t(a),r(ez(o))};return n.addEventListener(`change`,a),window.addEventListener(`storage`,o),window.addEventListener(UR,s),window.addEventListener(`message`,c),()=>{n.removeEventListener(`change`,a),window.removeEventListener(`storage`,o),window.removeEventListener(UR,s),window.removeEventListener(`message`,c)}},[e]),{theme:e,appliedTheme:n,isDark:(0,v.useMemo)(()=>n===GR.dark,[n]),isLight:(0,v.useMemo)(()=>n===GR.light,[n]),isSystem:e===GR.system,isInverse:e===GR.inverse,setSystemTheme:o,setInverseTheme:s,toggleTheme:c}},nz=()=>document.documentElement.clientWidth||window.innerWidth,rz=(e=nz())=>e<=768?`mobile`:`desktop`,iz=()=>{let e=navigator.userAgent.toLowerCase();return[`android`,`webos`,`iphone`,`ipad`,`ipod`,`blackberry`,`windows phone`,`mobile`].some(t=>e.includes(t))},az=()=>{let e=rz();return iz()||e===`mobile`?`mobile`:`desktop`},oz=()=>YS(()=>import(`./DesktopLayout-iI43ij11.js`),__vite__mapDeps([2,1,3])),sz=()=>YS(()=>import(`./MobileLayout-CziU8MCR.js`),__vite__mapDeps([4,3])),cz={config:`/kkk/assets/config`,about:`/kkk/assets/about`},lz={"/kkk/assets/config":`config`,"/kkk/assets/about":`about`},uz=({device:e})=>(0,U.jsxs)(Ev,{className:`h-screen overflow-hidden bg-background`,children:[(0,U.jsx)(qy.Provider,{placement:`top`}),(0,U.jsx)(bv,{hideScrollBar:!0,className:`h-full px-3 py-3 sm:px-5 sm:py-4 ${e===`mobile`?`data-[top-scroll=true]:mask-none data-[top-scroll=true]:[-webkit-mask-image:none] data-[top-bottom-scroll=true]:mask-[linear-gradient(180deg,black_calc(100%-var(--scroll-shadow-size)),transparent)] data-[top-bottom-scroll=true]:[-webkit-mask-image:linear-gradient(180deg,black_calc(100%-var(--scroll-shadow-size)),transparent)]`:``}`,size:56,children:(0,U.jsx)(BR,{device:e})})]}),dz=({LayoutComponent:e})=>{let t=vw(),n=xw(),r=lz[t.pathname]||`config`,i=Ux(e=>{n(cz[e])});return e?(0,U.jsxs)(`div`,{children:[(0,U.jsx)(qy.Provider,{placement:`top`}),(0,U.jsx)(e,{activeMenu:r,onMenuChange:i})]}):(0,U.jsxs)(Ev,{className:`flex min-h-screen items-center justify-center gap-4`,children:[(0,U.jsx)(Tv,{size:`sm`,"aria-label":`正在加载布局`}),(0,U.jsx)(px,{children:`正在加载`})]})},fz=()=>{tz();let[e,t]=GS({authenticated:uE(),device:az(),LayoutComponent:null}),{authenticated:n,device:r,LayoutComponent:i}=e;(0,v.useEffect)(()=>{let e=()=>{t({authenticated:uE()})};return window.addEventListener(oE,e),window.addEventListener(`storage`,e),()=>{window.removeEventListener(oE,e),window.removeEventListener(`storage`,e)}},[t]);let a=Ux(()=>{let e=az();t(t=>t.device===e?null:{device:e,LayoutComponent:null})});(0,v.useEffect)(()=>{let e=0,t=()=>{window.cancelAnimationFrame(e),e=window.requestAnimationFrame(a)};return window.addEventListener(`resize`,t),window.addEventListener(`orientationchange`,t),()=>{window.cancelAnimationFrame(e),window.removeEventListener(`resize`,t),window.removeEventListener(`orientationchange`,t)}},[a]),(0,v.useEffect)(()=>{if(!n){t({LayoutComponent:null});return}let e=!1;return(async()=>{if(r===`mobile`){let n=await sz();e||t({LayoutComponent:n.default})}else{let n=await oz();e||t({LayoutComponent:n.default})}})(),()=>{e=!0}},[n,r,t]);let o=Ux(()=>{t({authenticated:!0})});return n?(0,U.jsxs)(Yw,{children:[(0,U.jsx)(qw,{path:`/kkk/assets/karin-config`,element:(0,U.jsx)(uz,{device:r})}),(0,U.jsx)(qw,{path:`/kkk/assets/config`,element:(0,U.jsx)(dz,{LayoutComponent:i})}),(0,U.jsx)(qw,{path:`/kkk/assets/about`,element:(0,U.jsx)(dz,{LayoutComponent:i})}),(0,U.jsx)(qw,{path:`/kkk/assets`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`/kkk`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`/kkk/login`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})}),(0,U.jsx)(qw,{path:`*`,element:(0,U.jsx)(Kw,{to:`/kkk/assets/config`,replace:!0})})]}):(0,U.jsxs)(Yw,{children:[(0,U.jsx)(qw,{path:`/kkk/login`,element:(0,U.jsx)(VR,{onLogin:o})}),(0,U.jsx)(qw,{path:`*`,element:(0,U.jsx)(Kw,{to:`/kkk/login`,replace:!0})})]})};(0,y.createRoot)(document.getElementById(`root`)).render((0,U.jsx)(v.StrictMode,{children:(0,U.jsx)(()=>(0,U.jsx)(RT,{children:(0,U.jsx)(fz,{})}),{})}));export{Rs as $,hm as A,Le as At,rd as B,l as Bt,Wg as C,wt as Ct,jh as D,H as Dt,Ph as E,rt as Et,_f as F,E as Ft,Y as G,Vl as H,gf as I,M as It,tc as J,J as K,pf as L,O as Lt,om as M,ke as Mt,am as N,we as Nt,Sm as O,V as Ot,vf as P,R as Pt,qs as Q,df as R,h as Rt,Jg as S,kt as St,Ig as T,at as Tt,kc as U,ed as V,Ac as W,ec as X,nc as Y,Js as Z,gv as _,ga as _t,pE as a,Do as at,b_ as b,Yt as bt,Ax as c,q as ct,dx as d,Ja as dt,Es as et,lx as f,Qa as ft,Ev as g,ma as gt,kb as h,Xa as ht,Sj as i,Mo as it,sm as j,B as jt,mm as k,He as kt,wx as l,qa as lt,tx as m,$a as mt,BR as n,cs as nt,WS as o,wo as ot,cx as p,K as pt,sc as q,Mj as r,jo as rt,Ux as s,yo as st,tz as t,Ss as tt,px as u,Za as ut,pv as v,nn as vt,Vg as w,st as wt,S_ as x,Zt as xt,C_ as y,$t as yt,lf as z,d as zt};
@@ -344,6 +344,16 @@ const handleKuaishou = (0, ParseForward_1.withParseForward)((0, ErrorHandler_1.w
344
344
  const startedAt = Date.now();
345
345
  // 解析参数(--q= 画质等):之前这个分支没解析参数,面板选的画质从来没生效过
346
346
  const flags = (0, ParseOverride_1.parseParseFlags)(e);
347
+ /**
348
+ * 短时间不重复解析(通用 →「短时间不重复解析」,默认开):
349
+ * 连点 / 重复投递的同一条链接只放行一次;用链接本身当作品标识,
350
+ * 这样连「跟随短链」的那次请求都能省掉。
351
+ */
352
+ const kuaishouKey = ['kuaishou', e.contact?.peer ?? '', e.userId, String(kuaishouUrl), flags.override.xiaohongshuQuality ?? ''].join(':');
353
+ if (!(0, ParseLock_1.acquireParseLock)(kuaishouKey)) {
354
+ node_karin_1.logger.debug('短时间内重复的快手解析请求,已忽略: %s', kuaishouKey);
355
+ return;
356
+ }
347
357
  const iddata = await (0, kuaishou_1.getKuaishouID)(String(kuaishouUrl));
348
358
  const WorkData = await (0, kuaishou_1.fetchKuaishouData)(iddata.type, iddata);
349
359
  const kuaishou = new kuaishou_1.Kuaishou(e, iddata);
@@ -378,6 +388,12 @@ const handleXiaohongshu = (0, ParseForward_1.withParseForward)((0, ErrorHandler_
378
388
  const startedAt = Date.now();
379
389
  // 同上:补上解析参数与面板标记
380
390
  const flags = (0, ParseOverride_1.parseParseFlags)(e);
391
+ /** 短时间不重复解析(通用 →「短时间不重复解析」,默认开):同一条笔记只放行一次 */
392
+ const xiaohongshuKey = ['xiaohongshu', e.contact?.peer ?? '', e.userId, url, flags.override.xiaohongshuQuality ?? ''].join(':');
393
+ if (!(0, ParseLock_1.acquireParseLock)(xiaohongshuKey)) {
394
+ node_karin_1.logger.debug('短时间内重复的小红书解析请求,已忽略: %s', xiaohongshuKey);
395
+ return;
396
+ }
381
397
  const iddata = await (0, xiaohongshu_1.getXiaohongshuID)(url);
382
398
  const xiaohongshu = new xiaohongshu_1.Xiaohongshu(e, iddata);
383
399
  await (0, ParseOverride_1.runWithParseOverride)({
@@ -1,32 +1,85 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isParseDedupeEnabled = isParseDedupeEnabled;
4
+ exports.parseDedupeWindowMs = parseDedupeWindowMs;
5
+ exports.acquireParseLock = acquireParseLock;
2
6
  /**
3
- * 解析去重锁。
7
+ * 解析去重锁(「短时间不重复解析」)。
4
8
  *
5
9
  * 同一次点击可能被 QQ 投递两遍(指令按钮既发消息又发交互事件、用户连点、客户端重发),
6
10
  * 而解析本身是重活(取流 + 下载 + 发送),跑两遍的后果是:
7
11
  * 用户看到两次「检测到链接,开始解析」,第二次还会因为缓存已被清理而失败。
8
12
  *
9
- * 这里按「会话 + 作品 + 画质 + 弹幕开关」在短时间内只放行一次;
13
+ * 这里按「会话 + 作品 + 画质 + 弹幕开关」在一段时间内只放行一次;
10
14
  * 换画质/换解析内容属于不同的键,不会被误伤。
15
+ *
16
+ * 两个配置项都在「通用」里(见 src/qqFields.json):
17
+ * - `parseDedupe`(默认开):总开关,关掉后每次都放行(方便反复调试同一条链接);
18
+ * - `parseDedupeMinutes`(默认 1,1~60):去重窗口,单位分钟,只在开关打开时生效。
11
19
  */
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.acquireParseLock = acquireParseLock;
14
- /** 去重窗口(毫秒) */
15
- const WINDOW = 20 * 1000;
20
+ const node_karin_1 = require("../../../compat/node-karin.js");
21
+ const runtime_1 = require("../../../compat/runtime");
22
+ /** 默认窗口(分钟):配置没填 / 填歪了就用它 */
23
+ const DEFAULT_WINDOW_MINUTES = 1;
24
+ /** 允许的范围(分钟):太大会让人以为「插件不理我了」 */
25
+ const MIN_WINDOW_MINUTES = 1;
26
+ const MAX_WINDOW_MINUTES = 60;
16
27
  const recent = new Map();
28
+ /** 读一个配置值(读不到运行时 / 配置时返回 undefined) */
29
+ function readConfig(key) {
30
+ try {
31
+ return (0, runtime_1.tryGetRuntime)()?.config?.[key];
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ /**
38
+ * 「短时间不重复解析」开关是否打开。
39
+ *
40
+ * 缺省即开(老配置里没有这个键时行为与以前一致);读不到运行时(例如单元测试)也按开处理。
41
+ */
42
+ function isParseDedupeEnabled() {
43
+ return readConfig('parseDedupe') !== false;
44
+ }
45
+ /**
46
+ * 去重窗口(毫秒)。
47
+ *
48
+ * 取 `parseDedupeMinutes`(分钟,默认 1):填歪了(非数字 / 空)就是默认值 1;
49
+ * 超出范围**夹到最近的边界**(填 0 → 1 分钟,填 90 → 60 分钟),
50
+ * 免得一个手滑把窗口设成 0(等于没去重)或者 100000(等于再也不解析同一条链接)。
51
+ */
52
+ function parseDedupeWindowMs() {
53
+ const raw = Number(readConfig('parseDedupeMinutes'));
54
+ if (!Number.isFinite(raw))
55
+ return DEFAULT_WINDOW_MINUTES * 60 * 1000;
56
+ const minutes = Math.min(MAX_WINDOW_MINUTES, Math.max(MIN_WINDOW_MINUTES, raw));
57
+ return Math.round(minutes * 60 * 1000);
58
+ }
59
+ /** 关掉开关时只提示一次,别把日志刷爆 */
60
+ let loggedDisabled = false;
17
61
  /**
18
62
  * 尝试取得一次解析许可。
19
63
  * @param key 去重键(建议包含会话、作品 ID、画质与弹幕开关)
20
64
  * @returns true = 可以解析;false = 刚刚已经跑过一次,忽略
21
65
  */
22
66
  function acquireParseLock(key) {
67
+ /** 开关关掉:每次都放行(只提示一次,免得每条消息都刷一行) */
68
+ if (!isParseDedupeEnabled()) {
69
+ if (!loggedDisabled) {
70
+ loggedDisabled = true;
71
+ node_karin_1.logger.debug('[解析去重] 「短时间不重复解析」已关闭,本次不限制重复解析');
72
+ }
73
+ return true;
74
+ }
75
+ const window = parseDedupeWindowMs();
23
76
  const now = Date.now();
24
77
  for (const [item, at] of recent) {
25
- if (now - at > WINDOW)
78
+ if (now - at > window)
26
79
  recent.delete(item);
27
80
  }
28
81
  const last = recent.get(key);
29
- if (last !== undefined && now - last < WINDOW)
82
+ if (last !== undefined && now - last < window)
30
83
  return false;
31
84
  recent.set(key, now);
32
85
  return true;
package/lib/qqFields.json CHANGED
@@ -108,6 +108,26 @@
108
108
  "label": "强制不烧录弹幕",
109
109
  "description": "优先级最高的总开关:打开时无论指令、面板按钮还是平台配置,都不会烧录弹幕,一律按纯视频解析。要用弹幕功能时先把它关掉。"
110
110
  },
111
+ {
112
+ "key": "parseDedupe",
113
+ "group": "通用",
114
+ "renderIn": "app",
115
+ "type": "boolean",
116
+ "default": true,
117
+ "label": "短时间不重复解析",
118
+ "description": "默认开启。同一条链接在下面设定的一段时间内只解析一次:QQ 的指令按钮是「发一条消息 + 再发一个交互事件」,用户连点、客户端重发也会把同一条链接投递两遍,跑两遍就是两次「开始解析」、两次下载、两次发送(第二次还常因为缓存已被清理而失败)。去重键包含会话、作品 ID、画质与弹幕开关,换画质、换作品、换群都不会被误伤。**关掉后每条消息都会解析**,需要反复调试同一条链接时可以临时关掉。"
119
+ },
120
+ {
121
+ "key": "parseDedupeMinutes",
122
+ "group": "通用",
123
+ "renderIn": "app",
124
+ "type": "number",
125
+ "default": 1,
126
+ "min": 1,
127
+ "max": 60,
128
+ "label": "重复解析间隔(分钟)",
129
+ "description": "上面那个开关打开时才生效:同一条链接在这段时间内只解析一次,默认 1 分钟(可填 1 ~ 60)。填得越大越省事(重复投递/连点不会再跑第二遍),但也意味着这段时间里你手动再发一次同一条链接会被忽略;想立刻重解析就把上面的开关关掉。"
130
+ },
111
131
  {
112
132
  "key": "playerEnabled",
113
133
  "group": "通用",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-kkk",
3
- "version": "2.0.0",
3
+ "version": "2.0.1-beta.1",
4
4
  "description": "抖音 / B站 / 快手 / 小红书 视频解析与动态推送,带 QQ 交互面板与弹幕烧录(karin-plugin-kkk 的 Koishi 移植版)",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -73,13 +73,30 @@ const PLAYER_GROUP_OFF = 'Q(e,' + arr(['qq', PLAYER_MASTER_KEY]) + ',!0)===!1'
73
73
  /** 被总开关关掉时补一句说明 */
74
74
  const GROUP_LOCK_HINT = '(这一项要先把上面的「在线播放器总开关」打开才能改)'
75
75
 
76
+ /**
77
+ * 「这一项跟着某个开关走」的联动表(键 = 字段,值 = 它依赖的那个开关字段)。
78
+ *
79
+ * 开关关掉时这一项禁用变灰,视觉与「在线播放器总开关」那把锁完全一致。
80
+ * 目前:重复解析间隔(分钟)只有「短时间不重复解析」打开时才可改。
81
+ */
82
+ const FIELD_DISABLED_BY = {
83
+ parseDedupeMinutes: 'parseDedupe'
84
+ }
85
+
86
+ /** 取字段的 label(联动提示语里要用「短时间不重复解析」这种用户看到的说法) */
87
+ const labelOfField = (key) => (fields.find((item) => item.key === key)?.label) || key
88
+
76
89
  const appFieldCall = (field) => {
77
90
  const path = '[' + [q('qq'), q(field.key)].join(',') + ']'
78
91
  const locked = field.editableWhen === 'danmaku'
79
92
  /** 在线播放器设置这一组里,除总开关以外的字段都跟着总开关联动 */
80
93
  const lockedByGroup = field.section === PLAYER_SECTION && field.key !== PLAYER_MASTER_KEY
81
- const disabled = [locked ? DANMAKU_LOCKED : '', lockedByGroup ? PLAYER_GROUP_OFF : ''].filter(Boolean).join('||')
82
- const description = q(String(field.description) + (locked ? LOCK_HINT : '') + (lockedByGroup ? GROUP_LOCK_HINT : ''))
94
+ /** 这一项依赖的开关(见 FIELD_DISABLED_BY) */
95
+ const dependsOn = FIELD_DISABLED_BY[field.key]
96
+ const dependsOff = dependsOn ? 'Q(e,' + arr(['qq', dependsOn]) + ',!0)===!1' : ''
97
+ const disabled = [locked ? DANMAKU_LOCKED : '', lockedByGroup ? PLAYER_GROUP_OFF : '', dependsOff].filter(Boolean).join('||')
98
+ const dependsHint = dependsOn ? '(这一项要先把上面的「' + labelOfField(dependsOn) + '」打开才能改)' : ''
99
+ const description = q(String(field.description) + (locked ? LOCK_HINT : '') + (lockedByGroup ? GROUP_LOCK_HINT : '') + dependsHint)
83
100
  // renderSwitch 的第 4 个参数、renderTextField 的 options.disabled 都是「不可编辑」
84
101
  if (field.type === 'boolean') {
85
102
  return 's(' + path + ',' + q(field.label) + ',' + description + (disabled ? ',' + disabled : '') + ')'
@@ -0,0 +1,116 @@
1
+ /**
2
+ * 冒烟测试:「短时间不重复解析」开关(通用 →「短时间不重复解析」,默认开)。
3
+ *
4
+ * 覆盖:
5
+ * 1. 字段本身:在 qqFields 里、默认开、归到「通用」分类(WebUI 与控制台共用同一份字段表);
6
+ * 2. 开关开着(默认 / 老配置没这个键):同一个键在窗口内只放行一次,不同键各放行一次;
7
+ * 3. 开关关掉:同一个键连续调用也全部放行(方便反复调试同一条链接);
8
+ * 4. 四个平台都接了这把锁(抖音 / B站 / 快手 / 小红书),并且每条都是先判断再干活。
9
+ *
10
+ * 用法:node scripts/smoke-parse-lock.cjs
11
+ */
12
+ const fs = require('node:fs')
13
+ const path = require('node:path')
14
+
15
+ const pluginRoot = path.resolve(__dirname, '..')
16
+ const runtimeMod = require(path.join(pluginRoot, 'lib/compat/runtime.js'))
17
+ const { acquireParseLock, isParseDedupeEnabled, parseDedupeWindowMs } = require(path.join(pluginRoot, 'lib/karin/module/utils/ParseLock.js'))
18
+
19
+ let failures = 0
20
+ const check = (name, ok, extra = '') => {
21
+ console.log((ok ? '✅' : '❌') + ' ' + name + (extra ? ' | ' + extra : ''))
22
+ if (!ok) failures++
23
+ }
24
+
25
+ /** 绑定一个只带 config 的假运行时(ParseLock 只读 config.parseDedupe) */
26
+ const bindConfig = (config) => runtimeMod.bindRuntime({
27
+ ctx: { logger: () => ({ debug () {}, info () {}, warn () {}, error () {} }), config: {} },
28
+ config,
29
+ pluginRoot,
30
+ dataRoot: path.join(pluginRoot, 'data-smoke-lock')
31
+ })
32
+
33
+ console.log('\n[1] 字段本身')
34
+ {
35
+ const { QQ_FIELDS, QQ_DEFAULTS } = require(path.join(pluginRoot, 'lib/qqOptions.js'))
36
+ const field = QQ_FIELDS.find((item) => item.key === 'parseDedupe')
37
+ check('字段 parseDedupe 存在', !!field, field ? field.label : '(没有)')
38
+ check('默认开启(缺省即开,老配置行为不变)', QQ_DEFAULTS.parseDedupe === true, 'default=' + QQ_DEFAULTS.parseDedupe)
39
+ check('渲染在「通用」分类里(renderIn=app)', field?.renderIn === 'app' && field?.group === '通用',
40
+ JSON.stringify({ group: field?.group, renderIn: field?.renderIn, section: field?.section }))
41
+ check('是开关类型且说明写清了「关掉后每条消息都会解析」',
42
+ field?.type === 'boolean' && /关掉后每条消息都会解析/.test(field?.description ?? ''),
43
+ (field?.description ?? '').slice(0, 60))
44
+
45
+ /** 时间可自定义:单位分钟,默认 1,范围 1~60(用户要求「开启之后可以自定义时间单位分钟」) */
46
+ const minutes = QQ_FIELDS.find((item) => item.key === 'parseDedupeMinutes')
47
+ check('有「重复解析间隔(分钟)」这一项', !!minutes, minutes ? minutes.label : '(没有)')
48
+ check('默认 1 分钟、范围 1~60、同样在「通用」分类里',
49
+ minutes?.type === 'number' && minutes?.default === 1 && minutes?.min === 1 && minutes?.max === 60 &&
50
+ minutes?.renderIn === 'app' && minutes?.group === '通用',
51
+ JSON.stringify({ type: minutes?.type, default: minutes?.default, min: minutes?.min, max: minutes?.max }))
52
+ check('说明里写明只在开关打开时生效', /打开时才生效/.test(minutes?.description ?? ''),
53
+ (minutes?.description ?? '').slice(0, 50))
54
+ }
55
+
56
+ console.log('\n[1b] 去重窗口(分钟)')
57
+ {
58
+ bindConfig({})
59
+ check('默认窗口 = 1 分钟', parseDedupeWindowMs() === 60 * 1000, parseDedupeWindowMs() + 'ms')
60
+ bindConfig({ parseDedupeMinutes: 5 })
61
+ check('填 5 → 5 分钟', parseDedupeWindowMs() === 5 * 60 * 1000, parseDedupeWindowMs() + 'ms')
62
+ bindConfig({ parseDedupeMinutes: 60 })
63
+ check('填 60 → 60 分钟(上限)', parseDedupeWindowMs() === 60 * 60 * 1000, parseDedupeWindowMs() + 'ms')
64
+ /** 超范围夹到最近的边界;填歪了(非数字 / 空)才回落到默认值 */
65
+ bindConfig({ parseDedupeMinutes: 90 })
66
+ check('填 90 → 夹到上限 60 分钟', parseDedupeWindowMs() === 60 * 60 * 1000, parseDedupeWindowMs() + 'ms')
67
+ for (const bad of [0, -3]) {
68
+ bindConfig({ parseDedupeMinutes: bad })
69
+ check('填「' + String(bad) + '」→ 夹到下限 1 分钟', parseDedupeWindowMs() === 60 * 1000, parseDedupeWindowMs() + 'ms')
70
+ }
71
+ for (const bad of ['abc', null, undefined, '']) {
72
+ bindConfig({ parseDedupeMinutes: bad })
73
+ check('填「' + String(bad) + '」→ 回落到默认 1 分钟', parseDedupeWindowMs() === 60 * 1000, parseDedupeWindowMs() + 'ms')
74
+ }
75
+ }
76
+
77
+ console.log('\n[2] 开关开着(默认):窗口内只放行一次')
78
+ {
79
+ bindConfig({})
80
+ check('读不到这个键时按「开」处理(老配置)', isParseDedupeEnabled() === true)
81
+ const first = acquireParseLock('bilibili:456:12345:BV1xx411c7mD:80')
82
+ const second = acquireParseLock('bilibili:456:12345:BV1xx411c7mD:80')
83
+ check('同一个键:第一次放行、第二次拦住', first === true && second === false,
84
+ '第一次=' + first + ' 第二次=' + second)
85
+ const otherQuality = acquireParseLock('bilibili:456:12345:BV1xx411c7mD:116')
86
+ const otherWork = acquireParseLock('bilibili:456:12345:BV1yy411c7mE:80')
87
+ const otherGroup = acquireParseLock('bilibili:789:12345:BV1xx411c7mD:80')
88
+ check('换画质 / 换作品 / 换群都不会被误伤',
89
+ otherQuality === true && otherWork === true && otherGroup === true,
90
+ [otherQuality, otherWork, otherGroup].join(' / '))
91
+ check('显式写着 true 时同样生效', (() => { bindConfig({ parseDedupe: true }); return acquireParseLock('k') === true && acquireParseLock('k') === false })())
92
+ }
93
+
94
+ console.log('\n[3] 开关关掉:每次都放行')
95
+ {
96
+ bindConfig({ parseDedupe: false })
97
+ check('isParseDedupeEnabled() 变成 false', isParseDedupeEnabled() === false)
98
+ const results = [acquireParseLock('bilibili:456:12345:BV1xx411c7mD:80'), acquireParseLock('bilibili:456:12345:BV1xx411c7mD:80'), acquireParseLock('bilibili:456:12345:BV1xx411c7mD:80')]
99
+ check('同一个键连续三次全部放行', results.every((item) => item === true), results.join(' / '))
100
+ }
101
+
102
+ console.log('\n[4] 四个平台都接了这把锁')
103
+ {
104
+ bindConfig({})
105
+ const source = fs.readFileSync(path.join(pluginRoot, 'src/karin/apps/tools.ts'), 'utf-8')
106
+ // import 那一行长这样:import { acquireParseLock } from …(名字后面没有括号),所以只数调用
107
+ const usages = source.split('acquireParseLock(').length - 1
108
+ check('tools.ts 里有 4 处调用(抖音 / B站 / 快手 / 小红书)', usages === 4, '调用 ' + usages + ' 次')
109
+ check('并且是从 ParseLock 里 import 进来的', /import \{ acquireParseLock \} from '@\/module\/utils\/ParseLock'/.test(source))
110
+ for (const [name, pattern] of [['抖音', /douyinKey/], ['B站', /biliKey/], ['快手', /kuaishouKey/], ['小红书', /xiaohongshuKey/]]) {
111
+ check(name + ' 有去重键', pattern.test(source))
112
+ }
113
+ }
114
+
115
+ console.log('\n=== ' + (failures ? '失败 ' + failures + ' 项' : '全部通过') + ' ===')
116
+ process.exit(failures ? 1 : 0)
@@ -252,10 +252,30 @@ const makeVideo = (name) => {
252
252
  /** 收集回复消息的假事件对象 */
253
253
  const collector = (sent) => ({ reply: async (content) => { sent.push(String(content)) } })
254
254
 
255
+ /**
256
+ * 等插件把在线播放器初始化完(存储 + 路由)再开跑。
257
+ *
258
+ * 原来是写死 setTimeout 5 秒 —— 机器一忙(比如宿主 koishi 同时在跑)插件还没初始化完,
259
+ * 就会出现「[在线播放] 存储尚未初始化」和 15200 端口连不上这种假失败。
260
+ * playerStoreDir() 在 setupPlayerStore 之前是空串,正好当就绪信号用。
261
+ */
262
+ const waitForPlayerReady = async (store, timeoutMs = 90000) => {
263
+ const deadline = Date.now() + timeoutMs
264
+ while (Date.now() < deadline) {
265
+ try {
266
+ if (store.playerStoreDir()) return true
267
+ } catch { /* 还没准备好 */ }
268
+ await new Promise((resolve) => setTimeout(resolve, 500))
269
+ }
270
+ return false
271
+ }
272
+
255
273
  setTimeout(async () => {
256
274
  try {
257
275
  const store = require(path.join(pluginRoot, 'lib/player/index.js'))
258
276
  const runtime = require(path.join(pluginRoot, 'lib/compat/runtime.js')).getRuntime()
277
+ const ready = await waitForPlayerReady(store)
278
+ console.log(' 在线播放器就绪: ' + ready + '(存储目录 ' + (store.playerStoreDir() || '(空)') + ')')
259
279
  const { QQ_DEFAULTS } = require(path.join(pluginRoot, 'lib/qqOptions.js'))
260
280
 
261
281
  console.log('\n[1] 默认配置:总开关就是开启的')
@@ -350,6 +350,16 @@ const handleKuaishou = withParseForward(wrapWithErrorHandler(
350
350
  const startedAt = Date.now()
351
351
  // 解析参数(--q= 画质等):之前这个分支没解析参数,面板选的画质从来没生效过
352
352
  const flags = parseParseFlags(e)
353
+ /**
354
+ * 短时间不重复解析(通用 →「短时间不重复解析」,默认开):
355
+ * 连点 / 重复投递的同一条链接只放行一次;用链接本身当作品标识,
356
+ * 这样连「跟随短链」的那次请求都能省掉。
357
+ */
358
+ const kuaishouKey = ['kuaishou', e.contact?.peer ?? '', e.userId, String(kuaishouUrl), flags.override.xiaohongshuQuality ?? ''].join(':')
359
+ if (!acquireParseLock(kuaishouKey)) {
360
+ logger.debug('短时间内重复的快手解析请求,已忽略: %s', kuaishouKey)
361
+ return
362
+ }
353
363
  const iddata = await getKuaishouID(String(kuaishouUrl))
354
364
  const WorkData = await fetchKuaishouData(iddata.type, iddata)
355
365
  const kuaishou = new Kuaishou(e, iddata)
@@ -392,6 +402,12 @@ const handleXiaohongshu = withParseForward(wrapWithErrorHandler(
392
402
  const startedAt = Date.now()
393
403
  // 同上:补上解析参数与面板标记
394
404
  const flags = parseParseFlags(e)
405
+ /** 短时间不重复解析(通用 →「短时间不重复解析」,默认开):同一条笔记只放行一次 */
406
+ const xiaohongshuKey = ['xiaohongshu', e.contact?.peer ?? '', e.userId, url, flags.override.xiaohongshuQuality ?? ''].join(':')
407
+ if (!acquireParseLock(xiaohongshuKey)) {
408
+ logger.debug('短时间内重复的小红书解析请求,已忽略: %s', xiaohongshuKey)
409
+ return
410
+ }
395
411
  const iddata = await getXiaohongshuID(url)
396
412
  const xiaohongshu = new Xiaohongshu(e, iddata)
397
413
  await runWithParseOverride(
@@ -1,31 +1,85 @@
1
1
  /**
2
- * 解析去重锁。
2
+ * 解析去重锁(「短时间不重复解析」)。
3
3
  *
4
4
  * 同一次点击可能被 QQ 投递两遍(指令按钮既发消息又发交互事件、用户连点、客户端重发),
5
5
  * 而解析本身是重活(取流 + 下载 + 发送),跑两遍的后果是:
6
6
  * 用户看到两次「检测到链接,开始解析」,第二次还会因为缓存已被清理而失败。
7
7
  *
8
- * 这里按「会话 + 作品 + 画质 + 弹幕开关」在短时间内只放行一次;
8
+ * 这里按「会话 + 作品 + 画质 + 弹幕开关」在一段时间内只放行一次;
9
9
  * 换画质/换解析内容属于不同的键,不会被误伤。
10
+ *
11
+ * 两个配置项都在「通用」里(见 src/qqFields.json):
12
+ * - `parseDedupe`(默认开):总开关,关掉后每次都放行(方便反复调试同一条链接);
13
+ * - `parseDedupeMinutes`(默认 1,1~60):去重窗口,单位分钟,只在开关打开时生效。
10
14
  */
15
+ import { logger } from 'node-karin'
16
+
17
+ import { tryGetRuntime } from '../../../compat/runtime'
11
18
 
12
- /** 去重窗口(毫秒) */
13
- const WINDOW = 20 * 1000
19
+ /** 默认窗口(分钟):配置没填 / 填歪了就用它 */
20
+ const DEFAULT_WINDOW_MINUTES = 1
21
+ /** 允许的范围(分钟):太大会让人以为「插件不理我了」 */
22
+ const MIN_WINDOW_MINUTES = 1
23
+ const MAX_WINDOW_MINUTES = 60
14
24
 
15
25
  const recent = new Map<string, number>()
16
26
 
27
+ /** 读一个配置值(读不到运行时 / 配置时返回 undefined) */
28
+ function readConfig (key: string): any {
29
+ try {
30
+ return (tryGetRuntime()?.config as any)?.[key]
31
+ } catch {
32
+ return undefined
33
+ }
34
+ }
35
+
36
+ /**
37
+ * 「短时间不重复解析」开关是否打开。
38
+ *
39
+ * 缺省即开(老配置里没有这个键时行为与以前一致);读不到运行时(例如单元测试)也按开处理。
40
+ */
41
+ export function isParseDedupeEnabled (): boolean {
42
+ return readConfig('parseDedupe') !== false
43
+ }
44
+
45
+ /**
46
+ * 去重窗口(毫秒)。
47
+ *
48
+ * 取 `parseDedupeMinutes`(分钟,默认 1):填歪了(非数字 / 空)就是默认值 1;
49
+ * 超出范围**夹到最近的边界**(填 0 → 1 分钟,填 90 → 60 分钟),
50
+ * 免得一个手滑把窗口设成 0(等于没去重)或者 100000(等于再也不解析同一条链接)。
51
+ */
52
+ export function parseDedupeWindowMs (): number {
53
+ const raw = Number(readConfig('parseDedupeMinutes'))
54
+ if (!Number.isFinite(raw)) return DEFAULT_WINDOW_MINUTES * 60 * 1000
55
+ const minutes = Math.min(MAX_WINDOW_MINUTES, Math.max(MIN_WINDOW_MINUTES, raw))
56
+ return Math.round(minutes * 60 * 1000)
57
+ }
58
+
59
+ /** 关掉开关时只提示一次,别把日志刷爆 */
60
+ let loggedDisabled = false
61
+
17
62
  /**
18
63
  * 尝试取得一次解析许可。
19
64
  * @param key 去重键(建议包含会话、作品 ID、画质与弹幕开关)
20
65
  * @returns true = 可以解析;false = 刚刚已经跑过一次,忽略
21
66
  */
22
67
  export function acquireParseLock (key: string): boolean {
68
+ /** 开关关掉:每次都放行(只提示一次,免得每条消息都刷一行) */
69
+ if (!isParseDedupeEnabled()) {
70
+ if (!loggedDisabled) {
71
+ loggedDisabled = true
72
+ logger.debug('[解析去重] 「短时间不重复解析」已关闭,本次不限制重复解析')
73
+ }
74
+ return true
75
+ }
76
+ const window = parseDedupeWindowMs()
23
77
  const now = Date.now()
24
78
  for (const [item, at] of recent) {
25
- if (now - at > WINDOW) recent.delete(item)
79
+ if (now - at > window) recent.delete(item)
26
80
  }
27
81
  const last = recent.get(key)
28
- if (last !== undefined && now - last < WINDOW) return false
82
+ if (last !== undefined && now - last < window) return false
29
83
  recent.set(key, now)
30
84
  return true
31
85
  }
package/src/qqFields.json CHANGED
@@ -108,6 +108,26 @@
108
108
  "label": "强制不烧录弹幕",
109
109
  "description": "优先级最高的总开关:打开时无论指令、面板按钮还是平台配置,都不会烧录弹幕,一律按纯视频解析。要用弹幕功能时先把它关掉。"
110
110
  },
111
+ {
112
+ "key": "parseDedupe",
113
+ "group": "通用",
114
+ "renderIn": "app",
115
+ "type": "boolean",
116
+ "default": true,
117
+ "label": "短时间不重复解析",
118
+ "description": "默认开启。同一条链接在下面设定的一段时间内只解析一次:QQ 的指令按钮是「发一条消息 + 再发一个交互事件」,用户连点、客户端重发也会把同一条链接投递两遍,跑两遍就是两次「开始解析」、两次下载、两次发送(第二次还常因为缓存已被清理而失败)。去重键包含会话、作品 ID、画质与弹幕开关,换画质、换作品、换群都不会被误伤。**关掉后每条消息都会解析**,需要反复调试同一条链接时可以临时关掉。"
119
+ },
120
+ {
121
+ "key": "parseDedupeMinutes",
122
+ "group": "通用",
123
+ "renderIn": "app",
124
+ "type": "number",
125
+ "default": 1,
126
+ "min": 1,
127
+ "max": 60,
128
+ "label": "重复解析间隔(分钟)",
129
+ "description": "上面那个开关打开时才生效:同一条链接在这段时间内只解析一次,默认 1 分钟(可填 1 ~ 60)。填得越大越省事(重复投递/连点不会再跑第二遍),但也意味着这段时间里你手动再发一次同一条链接会被忽略;想立刻重解析就把上面的开关关掉。"
130
+ },
111
131
  {
112
132
  "key": "playerEnabled",
113
133
  "group": "通用",