Skip to content

Commit f60d3da

Browse files
committed
test: migrate 2.36.0 beta to Guoba panel
测试版:迁移 Karin 2.36.0 能力并将配置入口改为锅巴面板。 如遇到兼容性或功能问题,请提交 issue 反馈。
1 parent 7d77fb3 commit f60d3da

154 files changed

Lines changed: 9235 additions & 1595 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [2.36.0] - Karin 2.36.0 迁移版
4+
5+
> 测试版:如遇到兼容性或功能问题,请提交 issue 反馈。
6+
7+
### Features
8+
9+
* 完整迁移 Karin 插件 2.36.0 的配置、依赖、API 服务、统计、推送预览、平台扫码登录、错误处理、模板与静态资源。
10+
* 补齐抖音、哔哩哔哩、快手、小红书解析与推送相关能力,并适配 Yunzai 运行时。
11+
* 新增 `other/help``other/changelog``other/handlerError``other/live-photo-tip``other/version_warning`、平台二维码等模板。
12+
* 配置入口迁移到锅巴面板,独立 Web 配置面板不再随 Yunzai 版提供。
13+
314
## [1.9.0](https://github.com/ikenxuan/kkkkkk-10086/compare/v1.8.0...v1.9.0) (2025-09-14)
415

516

apps/admin.js

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Config, Render, Version, Common } from '../module/utils/index.js'
22
import { bilibiliLogin } from '../module/platform/bilibili/login.js'
3-
// import { dylogin } from '../module/platform/douyin/login.js'
3+
import { dylogin } from '../module/platform/douyin/login.js'
44
import fs from 'fs'
55

66
const APPType = {
@@ -46,6 +46,10 @@ const KuaiShouType = {
4646
快手评论数量: 'kuaishounumcomments'
4747
}
4848

49+
const XiaohongshuType = {
50+
小红书解析开关: 'switch'
51+
}
52+
4953
const UploadType = {
5054
发送视频base64: 'sendbase64',
5155
视频上传拦截: 'usefilelimit',
@@ -82,6 +86,8 @@ const NumberCfgType = {
8286
抖音评论数量: { type: 'douyin', key: 'numcomments', limit: '1-50' },
8387
B站评论数量: { type: 'bilibili', key: 'bilibilinumcomments', limit: '1-20' },
8488
快手评论数量: { type: 'kuaishou', key: 'kuaishounumcomments', limit: '1-30' },
89+
小红书评论数量: { type: 'xiaohongshu', key: 'numcomment', limit: '1-50' },
90+
小红书自动画质大小: { type: 'xiaohongshu', key: 'maxAutoVideoSize', limit: '1-200' },
8591
渲染精度: { type: 'app', key: 'renderScale', limit: '50-200' },
8692
优先级: { type: 'app', key: 'priority', limit: '0-10000' },
8793
API服务端口: { type: 'app', key: 'APIServerPort', limit: '1000-65535' },
@@ -102,6 +108,7 @@ const SwitchCfgType = {
102108
...DouYinType,
103109
...BilibiliType,
104110
...KuaiShouType,
111+
...XiaohongshuType,
105112
...UploadType,
106113
...RequestType
107114
}
@@ -111,6 +118,7 @@ const FileWitch = {
111118
douyin: DouYinType,
112119
bilibili: BilibiliType,
113120
kuaishou: KuaiShouType,
121+
xiaohongshu: XiaohongshuType,
114122
upload: UploadType,
115123
request: RequestType
116124
}
@@ -157,6 +165,11 @@ export class kkkAdmin extends plugin {
157165
fnc: 'setksck',
158166
permission: 'master'
159167
},
168+
{
169+
reg: /^#?(kkk)?\s*ck$/i,
170+
fnc: 'setxhsck',
171+
permission: 'master'
172+
},
160173
{
161174
reg: /^#?(kkk)?\s*[Bb]\s*()?\s*$/i,
162175
fnc: 'Blogin',
@@ -242,6 +255,8 @@ export class kkkAdmin extends plugin {
242255
...mapPushConfig('bilibili', _cfg.bilibili.push),
243256
// Kuaishou
244257
...Object.fromEntries(Object.keys(_cfg.kuaishou).map(k => [k, getStatus(_cfg.kuaishou[k])])),
258+
// Xiaohongshu
259+
...Object.fromEntries(Object.keys(_cfg.xiaohongshu).map(k => [`xiaohongshu_${k}`, getStatus(_cfg.xiaohongshu[k])])),
245260
// Upload
246261
...Object.fromEntries(Object.keys(_cfg.upload).map(k => [k, getStatus(_cfg.upload[k])])),
247262
// Request
@@ -260,8 +275,13 @@ export class kkkAdmin extends plugin {
260275
}
261276

262277
async dylogin(e) {
263-
// await dylogin(e)
264-
logger.warn('暂未修复抖音登录问题')
278+
await dylogin(e, {
279+
waitForCode: async prompt => {
280+
await this.reply(prompt, true)
281+
const ctx = await this.awaitContext(false, 60, '验证码输入超时,登录失败')
282+
return ctx?.msg || ''
283+
}
284+
})
265285
return true
266286
}
267287

@@ -304,6 +324,19 @@ export class kkkAdmin extends plugin {
304324
this.finish('saveksck')
305325
return true
306326
}
327+
328+
async setxhsck() {
329+
this.setContext('savexhsck')
330+
this.reply('请在120秒内发送小红书ck')
331+
return true
332+
}
333+
334+
async savexhsck() {
335+
Config.modify('cookies', 'xiaohongshu', String(this.e.msg))
336+
this.reply('设置成功!')
337+
this.finish('savexhsck')
338+
return true
339+
}
307340
}
308341

309342
/**

apps/help.js

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,71 @@
1-
import { Render, Version, Common } from '../module/utils/index.js'
2-
import { markdown } from '@karinjs/md-html'
3-
import { join } from 'node:path'
1+
import { Render, Version, Config } from '../module/utils/index.js'
42
import fs from 'node:fs'
53

4+
const buildHelpMenu = (role) => {
5+
const platformNames = []
6+
if (ConfigSafe('douyin')?.switch ?? ConfigSafe('douyin')?.douyintool) platformNames.push('抖音')
7+
if (ConfigSafe('bilibili')?.switch ?? ConfigSafe('bilibili')?.bilibilitool) platformNames.push('哔哩哔哩')
8+
if (ConfigSafe('kuaishou')?.switch ?? ConfigSafe('kuaishou')?.kuaishoutool) platformNames.push('快手')
9+
if (ConfigSafe('xiaohongshu')?.switch) platformNames.push('小红书')
10+
11+
const groups = [
12+
{
13+
title: '常用功能',
14+
items: [
15+
{ title: '自动识别分享链接进行解析', description: platformNames.length ? `支持「${platformNames.join('」「')}」` : '暂无可用平台', roles: ['member', 'master'] },
16+
{ title: '「#解析」「#kkk解析」「#弹幕解析」', description: '在解析功能关闭时可对引用消息解析,弹幕解析适用于抖音与哔哩哔哩', roles: ['member', 'master'] },
17+
{ title: '#kkk解析统计', description: '查看当前群组的解析统计数据', roles: ['member', 'master'] },
18+
{ title: '#kkk全局解析统计', description: '查看全局解析统计、趋势和群组排行', roles: ['master'] }
19+
]
20+
},
21+
{
22+
title: '推送相关',
23+
items: [
24+
{ title: '#设置抖音推送 + 抖音号', description: '在群聊中订阅或取消订阅抖音博主', roles: pushRole('douyin') },
25+
{ title: '#设置B站推送 + UP主UID', description: '在群聊中订阅或取消订阅 B 站 UP 主', roles: pushRole('bilibili') },
26+
{ title: '#抖音/B站推送列表', description: '查看当前群的订阅推送列表', roles: ['master'] },
27+
{ title: '#抖音/B站全部?强制推送', description: '手动模拟一次推送任务,已推送过的不会重复推送', roles: ['master'] },
28+
{ title: '#设置抖音推送 开启/关闭', description: '开启或关闭抖音推送任务,重启后生效', roles: ['master'] },
29+
{ title: '#设置B站推送 开启/关闭', description: '开启或关闭 B 站推送任务,重启后生效', roles: ['master'] },
30+
{ title: '#kkk推送全局忽略 + 链接', description: '把指定作品或动态标记为已处理,避免继续推送', roles: ['master'] }
31+
]
32+
},
33+
{
34+
title: '设置相关',
35+
items: [
36+
{ title: '#kkk设置推送机器人 + Bot ID', description: '一键更换推送机器人', roles: ['master'] },
37+
{ title: '#抖音登录', description: '使用抖音 APP 扫码登录获取 Cookies', roles: ['master'] },
38+
{ title: '#B站登录', description: '使用哔哩哔哩 APP 扫码登录获取 Cookies', roles: ['master'] },
39+
{ title: '锅巴面板', description: '在锅巴插件管理中配置 kkkkkk-10086', roles: ['master'] }
40+
]
41+
},
42+
{
43+
title: '其他',
44+
items: [
45+
{ title: '「#kkk版本」「#kkk更新日志」「#kkk更新」', description: '查看版本与更新日志', roles: ['member', 'master'] }
46+
]
47+
}
48+
]
49+
50+
return groups.map(group => ({
51+
title: group.title,
52+
items: group.items.filter(item => item.roles.includes(role)).map(({ title, description }) => ({ title, description }))
53+
})).filter(group => group.items.length > 0)
54+
}
55+
56+
const ConfigSafe = (name) => {
57+
try {
58+
return Config?.[name] || null
59+
} catch {
60+
return null
61+
}
62+
}
63+
64+
const pushRole = (name) => {
65+
const permission = ConfigSafe(name)?.push?.permission
66+
return permission === 'all' ? ['member', 'master'] : ['master']
67+
}
68+
669
export class kkkHelp extends plugin {
770
constructor() {
871
super({
@@ -15,7 +78,7 @@ export class kkkHelp extends plugin {
1578
fnc: 'help'
1679
},
1780
{
18-
reg: '^#?kkk版本$',
81+
reg: '^#?kkk(版本|更新日志|更新)$',
1982
fnc: 'version'
2083
}
2184
]
@@ -24,19 +87,22 @@ export class kkkHelp extends plugin {
2487

2588
async version(e) {
2689
const changelogs = fs.readFileSync(Version.pluginPath + '/CHANGELOG.md', 'utf8')
27-
const html = markdown(changelogs, {
28-
gitcss: Common.useDarkTheme() ? 'github-markdown-dark.css' : 'github-markdown-light.css'
90+
const img = await Render('other/changelog', {
91+
title: 'KKK 更新日志',
92+
markdown: changelogs,
93+
version: Version.version
2994
})
30-
fs.mkdirSync(join(Version.pluginPath, 'resources', 'template', 'version', 'html'), { recursive: true })
31-
const htmlPath = join(Version.pluginPath, 'resources', 'template', 'version', 'html', 'index.html')
32-
fs.writeFileSync(htmlPath, html)
33-
const img = await Render('version/index')
3495
await e.reply(img)
3596
return true
3697
}
3798

3899
async help(e) {
39-
const img = await Render('help/index')
100+
const role = e.isMaster ? 'master' : 'member'
101+
const img = await Render('other/help', {
102+
title: 'KKK插件帮助页面',
103+
role,
104+
menu: buildHelpMenu(role)
105+
})
40106
await e.reply(img)
41107
return true
42108
}

apps/push.js

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Bilibilipush } from '../module/platform/bilibili/index.js'
1+
import { bilibiliDB, douyinDB } from '../module/db/index.js'
2+
import { Bilibilipush, getBilibiliID } from '../module/platform/bilibili/index.js'
23
import { getBilibiliData, getDouyinData } from '@ikenxuan/amagi'
3-
import { DouYinpush } from '../module/platform/douyin/index.js'
4+
import { DouYinpush, getDouyinID } from '../module/platform/douyin/index.js'
45
import { Config } from '../module/utils/index.js'
56

67
export class kkkPush extends plugin {
@@ -12,10 +13,11 @@ export class kkkPush extends plugin {
1213
priority: Config.app.defaulttool ? -Infinity : Config.app.priority,
1314
rule: [
1415
{ reg: /^#/, fnc: 'setdyPush', permission: Config.douyin.push.permission },
15-
{ reg: /^#[bB](?:[Uu][Ii][Dd]:)?(\d+)$/, fnc: 'setbiliPush', permission: Config.bilibili.push.permission },
16+
{ reg: /^#[bB]/, fnc: 'setbiliPush', permission: Config.bilibili.push.permission },
1617
{ reg: /^#(|[bB])()?/, fnc: 'forcePush', permission: 'master' },
1718
{ reg: /^#(|[bB])$/, fnc: 'pushlist' },
18-
{ reg: /^#kkk/, fnc: 'changeBotID', permission: 'master' }
19+
{ reg: /^#kkk/, fnc: 'changeBotID', permission: 'master' },
20+
{ reg: /^#kkk/, fnc: 'globalIgnore', permission: 'master' }
1921
]
2022
})
2123

@@ -78,9 +80,17 @@ export class kkkPush extends plugin {
7880
* @returns {Promise<boolean>}
7981
*/
8082
async setdyPush(e) {
83+
const query = e.msg.replace(/^#/, '').trim()
84+
if (query === '开启' || query === '关闭') {
85+
const enable = query === '开启'
86+
Config.modify('douyin', 'push.switch', enable)
87+
await e.reply(`抖音推送已${enable ? '开启' : '关闭'},重启后生效`)
88+
return true
89+
}
90+
8191
// 如果是私聊消息,直接返回true
8292
if (e.isPrivate) return true
83-
const data = await getDouyinData('搜索数据', Config.cookies.douyin, { query: e.msg.replace(/^#/, ''), typeMode: 'strict' })
93+
const data = await getDouyinData('搜索数据', Config.cookies.douyin, { query, typeMode: 'strict' })
8494
await new DouYinpush(e).setting(data.data)
8595
return true
8696
}
@@ -91,6 +101,18 @@ export class kkkPush extends plugin {
91101
* @returns {Promise<boolean>}
92102
*/
93103
async setbiliPush(e) {
104+
const query = e.msg
105+
.replace(/^#[bB]/, '')
106+
.replace(/^(?:[Uu][Ii][Dd]:)?/, '')
107+
.trim()
108+
109+
if (query === '开启' || query === '关闭') {
110+
const enable = query === '开启'
111+
Config.modify('bilibili', 'push.switch', enable)
112+
await e.reply(`B站推送已${enable ? '开启' : '关闭'},重启后生效`)
113+
return true
114+
}
115+
94116
// 如果是私信消息,直接返回true
95117
if (e.isPrivate) return true
96118
// 检查是否配置了B站Cookie,如果没有则提示用户配置
@@ -99,7 +121,7 @@ export class kkkPush extends plugin {
99121
return true
100122
}
101123
// 使用正则表达式匹配消息格式,提取UID
102-
const match = /^#[bB](?:UID:)?(\d+)$/.exec(e.msg)
124+
const match = /^(\d+)$/.exec(query)
103125
if (match && match[1]) {
104126
// 获取B站用户主页数据
105127
const data = await getBilibiliData('用户主页数据', Config.cookies.bilibili, { host_mid: Number(match[1]), typeMode: 'strict' })
@@ -162,4 +184,78 @@ export class kkkPush extends plugin {
162184
return true
163185
}
164186

187+
async globalIgnore(e) {
188+
const url = e.msg.replace(/^#kkk/, '').trim().match(/https?:\/\/[^\s]+/i)?.[0]
189+
if (!url) {
190+
await e.reply('请提供要忽略的抖音作品或B站动态链接')
191+
return true
192+
}
193+
194+
if (/(douyin|iesdouyin)\.com/.test(url)) return await this.ignoreDouyinWork(e, url)
195+
if (/bilibili\.com/.test(url)) return await this.ignoreBilibiliDynamic(e, url)
196+
197+
await e.reply('暂不支持该平台链接')
198+
return true
199+
}
200+
201+
async ignoreDouyinWork(e, url) {
202+
const idData = await getDouyinID(url, false)
203+
if (!idData?.aweme_id) {
204+
await e.reply('无法解析该抖音作品链接')
205+
return true
206+
}
207+
208+
const workInfo = await getDouyinData('聚合解析', Config.cookies.douyin || '', { aweme_id: idData.aweme_id, typeMode: 'strict' })
209+
const aweme = workInfo?.data?.aweme_detail || workInfo?.data?.data?.aweme_detail
210+
const secUid = aweme?.author?.sec_uid
211+
if (!secUid) {
212+
await e.reply('无法获取该作品作者信息')
213+
return true
214+
}
215+
216+
const subscribedItem = Config.pushlist.douyin?.find(item => item.sec_uid === secUid)
217+
if (!subscribedItem) {
218+
await e.reply('该作品对应的博主未在推送订阅中,跳过')
219+
return true
220+
}
221+
222+
const groupIds = (subscribedItem.group_id || []).map(item => String(item).split(':')[0]).filter(Boolean)
223+
for (const groupId of groupIds) {
224+
await douyinDB?.addAwemeCache(idData.aweme_id, secUid, groupId, 'post')
225+
}
226+
227+
await e.reply(`已忽略抖音作品 ${idData.aweme_id},共 ${groupIds.length} 个群组标记为已处理`)
228+
return true
229+
}
230+
231+
async ignoreBilibiliDynamic(e, url) {
232+
const idData = await getBilibiliID(url, false)
233+
if (!idData?.dynamic_id) {
234+
await e.reply('无法解析该B站动态链接')
235+
return true
236+
}
237+
238+
const dynamicInfo = await getBilibiliData('动态详情数据', Config.cookies.bilibili || '', { dynamic_id: idData.dynamic_id, typeMode: 'strict' })
239+
const item = dynamicInfo?.data?.data?.item || dynamicInfo?.data?.item
240+
const hostMid = Number(item?.modules?.module_author?.mid)
241+
if (!hostMid) {
242+
await e.reply('无法获取该动态作者信息')
243+
return true
244+
}
245+
246+
const subscribedItem = Config.pushlist.bilibili?.find(item => Number(item.host_mid) === hostMid)
247+
if (!subscribedItem) {
248+
await e.reply('该动态对应的UP主未在推送订阅中,跳过')
249+
return true
250+
}
251+
252+
const groupIds = (subscribedItem.group_id || []).map(item => String(item).split(':')[0]).filter(Boolean)
253+
for (const groupId of groupIds) {
254+
await bilibiliDB?.addDynamicCache(idData.dynamic_id, hostMid, groupId, item?.type || '')
255+
}
256+
257+
await e.reply(`已忽略B站动态 ${idData.dynamic_id},共 ${groupIds.length} 个群组标记为已处理`)
258+
return true
259+
}
260+
165261
}

0 commit comments

Comments
 (0)