dsh-yunpa 0.10.2 → 0.10.3
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 +8 -0
- package/api.js +8 -0
- package/client.js +61 -2
- package/package.json +1 -1
- package/selfcheck-live.mjs +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.10.3 — 2026-11-08
|
|
4
|
+
抽屉从「只能看」变成「能自己走」。
|
|
5
|
+
|
|
6
|
+
- 抽屉加**站点下拉**:选贴吧/NGA/Pixiv/爱丽丝书屋直接跳登录页
|
|
7
|
+
- 抽屉加**地址栏**:输入 URL 回车即导航(自动补 `https://`)
|
|
8
|
+
- 画面取不到时给一行提示,不再静默破图
|
|
9
|
+
- 站点表复用既有的 `/sites` 路由,没为这个下拉新增 host 接口——host 半身改了要重启宿主,能复用就别加
|
|
10
|
+
|
|
3
11
|
## 0.10.2 — 2026-11-08
|
|
4
12
|
发布到 npm 后的两处修正。
|
|
5
13
|
|
package/api.js
CHANGED
|
@@ -116,6 +116,14 @@ export function createApi() {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
if (route === '/live/info') return send(200, { ok: true, ...(await liveInfo()) })
|
|
119
|
+
if (route === '/live/sites') {
|
|
120
|
+
return send(200, {
|
|
121
|
+
ok: true,
|
|
122
|
+
sites: Object.entries(SITES).map(([key, cfg]) => ({
|
|
123
|
+
key, marker: cfg.marker || key, login: cfg.login || '', probe: cfg.probe || '',
|
|
124
|
+
})),
|
|
125
|
+
})
|
|
126
|
+
}
|
|
119
127
|
if (route === '/live/size' && method === 'POST') {
|
|
120
128
|
const b = await readBody()
|
|
121
129
|
const port = await livePort()
|
package/client.js
CHANGED
|
@@ -38,6 +38,11 @@ window.__ModuleLoader__.load({
|
|
|
38
38
|
.yunpa-dock-shot{flex:0 0 auto;overflow:hidden;border-radius:10px;border:.5px solid var(--dsw-alias-border-l2);line-height:0;background:#111}
|
|
39
39
|
.yunpa-dock-shot img{width:100%;height:auto;display:block;cursor:crosshair}
|
|
40
40
|
.yunpa-dock-empty{min-height:180px;display:flex;flex-direction:column;gap:10px;align-items:center;justify-content:center;text-align:center;font-size:12px;color:var(--dsw-alias-label-tertiary);padding:0 10px}
|
|
41
|
+
.yunpa-dock-nav{display:flex;gap:6px;align-items:center}
|
|
42
|
+
.yunpa-dock-nav select,.yunpa-dock-nav input{font:inherit;font-size:11px;padding:5px 6px;border-radius:7px;border:1px solid #2e3036;background:#101114;color:#e6e8ee}
|
|
43
|
+
.yunpa-dock-nav select{max-width:98px}
|
|
44
|
+
.yunpa-dock-nav input{flex:1;min-width:0}
|
|
45
|
+
.yunpa-dock-nav input::placeholder{color:#6b6f7a}
|
|
41
46
|
.yunpa-dock-input{display:flex;gap:6px}
|
|
42
47
|
.yunpa-dock-input input{flex:1;min-width:0;font:inherit;font-size:12px;padding:6px 8px;border-radius:7px;border:1px solid #2e3036;background:#101114;color:#e6e8ee}
|
|
43
48
|
.yunpa-dock-input input::placeholder{color:#737783}
|
|
@@ -314,6 +319,9 @@ window.__ModuleLoader__.load({
|
|
|
314
319
|
const [note, setNote] = useState('')
|
|
315
320
|
const [text, setText] = useState('')
|
|
316
321
|
const [frame, setFrame] = useState({ w: 0, h: 0 })
|
|
322
|
+
const [sites, setSites] = useState([])
|
|
323
|
+
const [addr, setAddr] = useState('')
|
|
324
|
+
const [broken, setBroken] = useState(false)
|
|
317
325
|
const imgRef = React.useRef(null)
|
|
318
326
|
const shotRef = React.useRef(null)
|
|
319
327
|
|
|
@@ -446,6 +454,17 @@ window.__ModuleLoader__.load({
|
|
|
446
454
|
|
|
447
455
|
useEffect(() => { try { localStorage.setItem(DOCK_KEY, open ? '1' : '0') } catch {} }, [open])
|
|
448
456
|
|
|
457
|
+
// 站点表:下拉里能直接跳登录页。走既有的 /sites(设置页「站点」页签用的同一份),
|
|
458
|
+
// 不新增 host 路由——host 半身改了要重启,能复用就别加。
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
get('/sites').then((j) => {
|
|
461
|
+
if (!j || !j.ok || !j.sites) return
|
|
462
|
+
setSites(Object.entries(j.sites).map(([key, c]) => ({
|
|
463
|
+
key, marker: (c && c.marker) || key, login: (c && c.login) || '',
|
|
464
|
+
})))
|
|
465
|
+
}).catch(() => {})
|
|
466
|
+
}, [])
|
|
467
|
+
|
|
449
468
|
// 窗口缩小后把面板拉回可见范围,避免拖到屏幕外找不回来
|
|
450
469
|
useEffect(() => {
|
|
451
470
|
const onResize = () => {
|
|
@@ -664,13 +683,53 @@ window.__ModuleLoader__.load({
|
|
|
664
683
|
h('button', { onPointerDown: stopDrag, onClick: () => setLive((v) => !v), title: live ? '暂停刷新' : '继续刷新' }, live ? '暂停' : '继续'),
|
|
665
684
|
h('button', { onPointerDown: stopDrag, onClick: () => setOpen(false), title: '收起' }, '收起'),
|
|
666
685
|
),
|
|
686
|
+
h('div', { className: 'yunpa-dock-nav' },
|
|
687
|
+
h('select', {
|
|
688
|
+
value: '', title: '跳到该站点登录页',
|
|
689
|
+
onChange: async (e) => {
|
|
690
|
+
const key = e.target.value
|
|
691
|
+
const s = sites.find((x) => x.key === key)
|
|
692
|
+
e.target.value = ''
|
|
693
|
+
if (!s || !s.login) return
|
|
694
|
+
await act('/live/nav', { url: s.login })
|
|
695
|
+
setBroken(false)
|
|
696
|
+
setTick((n) => n + 1)
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
h('option', { value: '' }, '站点'),
|
|
700
|
+
sites.map((s) => h('option', { key: s.key, value: s.key }, s.marker)),
|
|
701
|
+
),
|
|
702
|
+
h('input', {
|
|
703
|
+
value: addr, placeholder: 'https://…(回车跳转)',
|
|
704
|
+
onChange: (e) => setAddr(e.target.value),
|
|
705
|
+
onKeyDown: async (e) => {
|
|
706
|
+
if (e.key !== 'Enter' || !addr.trim()) return
|
|
707
|
+
const url = /^https?:\/\//i.test(addr.trim()) ? addr.trim() : 'https://' + addr.trim()
|
|
708
|
+
await act('/live/nav', { url })
|
|
709
|
+
setAddr('')
|
|
710
|
+
setBroken(false)
|
|
711
|
+
setTick((n) => n + 1)
|
|
712
|
+
},
|
|
713
|
+
}),
|
|
714
|
+
h('button', {
|
|
715
|
+
onClick: async () => {
|
|
716
|
+
if (!addr.trim()) return
|
|
717
|
+
const url = /^https?:\/\//i.test(addr.trim()) ? addr.trim() : 'https://' + addr.trim()
|
|
718
|
+
await act('/live/nav', { url })
|
|
719
|
+
setAddr('')
|
|
720
|
+
setBroken(false)
|
|
721
|
+
setTick((n) => n + 1)
|
|
722
|
+
},
|
|
723
|
+
}, '→'),
|
|
724
|
+
),
|
|
667
725
|
running
|
|
668
726
|
? h('div', { className: 'yunpa-dock-shot', ref: shotRef },
|
|
669
727
|
h('img', {
|
|
670
728
|
ref: imgRef, alt: '受控浏览器画面', draggable: false,
|
|
671
729
|
src: '/api/yunpa/live.png?q=60&t=' + tick + (frame.w ? '&w=' + frame.w + '&h=' + frame.h : ''),
|
|
672
730
|
onClick: clickShot,
|
|
673
|
-
onError: () =>
|
|
731
|
+
onError: () => setBroken(true),
|
|
732
|
+
onLoad: () => setBroken(false),
|
|
674
733
|
style: live ? undefined : { opacity: 0.45 },
|
|
675
734
|
}))
|
|
676
735
|
: h('div', { className: 'yunpa-dock-empty' },
|
|
@@ -698,7 +757,7 @@ window.__ModuleLoader__.load({
|
|
|
698
757
|
}, '发送'),
|
|
699
758
|
h('button', { onClick: () => act('/live/key', { key: 'Enter' }) }, '⏎'),
|
|
700
759
|
),
|
|
701
|
-
|
|
760
|
+
broken ? h('div', { className: 'mono' }, '画面取不到:点「启动」或稍等一帧再试') : null,
|
|
702
761
|
note && running ? h('div', { className: 'mono' }, note) : null,
|
|
703
762
|
)
|
|
704
763
|
}
|
package/package.json
CHANGED
package/selfcheck-live.mjs
CHANGED
|
@@ -119,6 +119,12 @@ for (let round = 1; round <= ROUNDS; round++) {
|
|
|
119
119
|
const wheel = await json('/live/scroll', { method: 'POST', body: JSON.stringify({ dy: 400 }) })
|
|
120
120
|
rec(round, '滚轮转发', wheel.body?.ok === true, JSON.stringify(wheel.body).slice(0, 60))
|
|
121
121
|
|
|
122
|
+
// 4c) 站点表:抽屉里的站点下拉靠它(用既有的 /sites)
|
|
123
|
+
const siteRes = await json('/sites')
|
|
124
|
+
const siteKeys = Object.keys(siteRes.body?.sites || {})
|
|
125
|
+
rec(round, '站点表 /sites', siteRes.body?.ok === true && siteKeys.length > 0,
|
|
126
|
+
siteKeys.join(',') || '空')
|
|
127
|
+
|
|
122
128
|
// 5) 视口跟随面板尺寸:尺寸随请求参数走,截出来就该是这个大小
|
|
123
129
|
// (Emulation 覆盖是会话级的,所以每帧都得在同一个会话里重设 —— 这是 /live.size 单一接口做不到的)
|
|
124
130
|
const target = round % 2 === 0 ? { w: 420, h: 560 } : { w: 480, h: 600 }
|