refactor: restructure plugins per MTSS standard, consolidate assets to res/
Per docs/plugin-audit-report.md (plugins normalized to Trigger(handlers) → Service(services) → Model(repository/models) + utils): - Split monolithic __init__.py into handlers/services/utils across dailywife, deer_pipe, dice, galgame_card, helldivers_tools, huoziyinshua, learning_chat, makeaquote, mc_server_status, ncm_saying, picfinder_take, picstatus, random_jm_code, regif, steam_info, video_analysis, group_tools - Move static assets under res/: deer_pipe font/img, makeaquote font, helldivers img/templates, huoziyinshua HuoZiYinShua - Add config.py + register_config_items to ncm_saying, random_jm_code, group_tools; learning_chat unified config bridge - Remove deprecated: voice_trans plugin, bf_bot/test.py, dead code in dailywife/deer_pipe, empty dirs, debug scripts under helldivers temp - Disable brash_general_supercredits_tools (stub comment only) - bot.py: optional stdout/stderr redirect to log file for Web log viewer, force ANSI colorize on non-TTY sinks - Move runtime data (jm_code.json) out of plugin dir into hexi/data - Docs: plugin-audit-report.md; README reflects removed plugins Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,114 @@ export const hubPluginSaveConfig = async (id: string, values: Record<string, any
|
||||
export const hubSettings = async () => await request('/hub/api/settings')
|
||||
export const hubChangePassword = async (old_password: string, new_password: string) =>
|
||||
await request('/hub/api/settings/password', { method: 'POST', body: { old_password, new_password } })
|
||||
export const hubLogs = async (limit = 500) => await request('/hub/api/logs?limit=' + limit)
|
||||
export const hubBotAction = async (action: 'stop' | 'restart') =>
|
||||
await request('/hub/api/system/bot', { method: 'POST', body: { action } })
|
||||
export const hubBotConfig = async () => await request('/hub/api/system/bot_config')
|
||||
export const hubBotConfigSave = async (values: Record<string, any>) =>
|
||||
await request('/hub/api/system/bot_config', { method: 'POST', body: values })
|
||||
|
||||
export function hubLogStream(opts: {
|
||||
since: number
|
||||
onLine: (line: string) => void
|
||||
onStatus: (s: 'open' | 'reconnecting' | 'closed') => void
|
||||
}): () => void {
|
||||
const controller = new AbortController()
|
||||
let stopped = false
|
||||
let since = opts.since
|
||||
|
||||
const read = async () => {
|
||||
while (!stopped) {
|
||||
try {
|
||||
const res = await fetch('/hub/api/logs/stream?since=' + since, {
|
||||
headers: { Authorization: 'Bearer ' + getToken() },
|
||||
signal: controller.signal,
|
||||
})
|
||||
if (!res.ok || !res.body) throw new Error('HTTP ' + res.status)
|
||||
opts.onStatus('open')
|
||||
const reader = res.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buf = ''
|
||||
while (!stopped) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
buf += decoder.decode(value, { stream: true })
|
||||
let i
|
||||
while ((i = buf.indexOf('\n\n')) !== -1) {
|
||||
const block = buf.slice(0, i)
|
||||
buf = buf.slice(i + 2)
|
||||
for (const ln of block.split('\n')) {
|
||||
if (ln.startsWith('data: ')) {
|
||||
try {
|
||||
const obj = JSON.parse(ln.slice(6))
|
||||
if (obj && obj.line !== undefined) {
|
||||
opts.onLine(obj.line)
|
||||
if (typeof obj.offset === 'number') since = obj.offset
|
||||
}
|
||||
} catch { /* 忽略坏帧 */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!stopped) opts.onStatus('reconnecting')
|
||||
} catch (e: any) {
|
||||
if (stopped || (e && e.name === 'AbortError')) return
|
||||
opts.onStatus('reconnecting')
|
||||
}
|
||||
if (!stopped) await new Promise(res => setTimeout(res, 1500))
|
||||
}
|
||||
}
|
||||
|
||||
read()
|
||||
return () => { stopped = true; controller.abort() }
|
||||
}
|
||||
|
||||
export function hubDashboardStream(opts: {
|
||||
onData: (data: any) => void
|
||||
onStatus?: (s: 'open' | 'reconnecting' | 'closed') => void
|
||||
}): () => void {
|
||||
const controller = new AbortController()
|
||||
let stopped = false
|
||||
|
||||
const read = async () => {
|
||||
while (!stopped) {
|
||||
try {
|
||||
const res = await fetch('/hub/api/dashboard/stream', {
|
||||
headers: { Authorization: 'Bearer ' + getToken() },
|
||||
signal: controller.signal,
|
||||
})
|
||||
if (!res.ok || !res.body) throw new Error('HTTP ' + res.status)
|
||||
opts.onStatus?.('open')
|
||||
const reader = res.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buf = ''
|
||||
while (!stopped) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
buf += decoder.decode(value, { stream: true })
|
||||
let i
|
||||
while ((i = buf.indexOf('\n\n')) !== -1) {
|
||||
const block = buf.slice(0, i)
|
||||
buf = buf.slice(i + 2)
|
||||
for (const ln of block.split('\n')) {
|
||||
if (ln.startsWith('data: ')) {
|
||||
try { opts.onData(JSON.parse(ln.slice(6))) } catch { /* 忽略坏帧 */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!stopped) opts.onStatus?.('reconnecting')
|
||||
} catch (e: any) {
|
||||
if (stopped || (e && e.name === 'AbortError')) return
|
||||
opts.onStatus?.('reconnecting')
|
||||
}
|
||||
if (!stopped) await new Promise(res => setTimeout(res, 2000))
|
||||
}
|
||||
}
|
||||
|
||||
read()
|
||||
return () => { stopped = true; controller.abort() }
|
||||
}
|
||||
|
||||
export const api = (plugin: string) => ({
|
||||
get: (path: string) => request(`/api/${plugin}/${path}`),
|
||||
|
||||
Reference in New Issue
Block a user