Skip to content

Commit 10d62b6

Browse files
authored
Merge branch 'main' into main
2 parents 9f0f2ac + 1e6994c commit 10d62b6

97 files changed

Lines changed: 666 additions & 1366 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.

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ release/
3737
.eslintcache
3838

3939
TROUBLE.md
40-
.env
40+
.env
41+
42+
coverage/

README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,37 @@ AI 助手只支持文本对话,在使用 AI 助手功能前,请先设置好
210210

211211
### 其它
212212

213+
#### 多开/多账号
214+
215+
软件并不支持多开,但是支持设置多个账号,各个账号之间的环境以及任务是独立的,并且能够同时运行。
216+
217+
可以通过软件界面点击右上角的加号按钮添加新账号。新账号除了部分通用设置外的所有设置,包括浏览器上下文环境都是独立的,所以不用担心新旧账号同时运行会产生冲突(除非你连接同一个中控台)
218+
219+
![添加新账号](./screenshot/account_switch.png)
220+
221+
##### 删除账号
222+
223+
可在「应用设置」-「删除账号」中删除当前账号。但是**默认账号**(即第一个账号)无法删除!
224+
225+
> 这里的删除账号是指删除当前账号对应中控台任务的所有设置,并不会真的删除一个平台账号。
226+
213227
#### 软件更新
214228

215-
你可以选择更新源,但是目前最稳定的还是 Github。
229+
当前暂时只通过 Github Release 分发。你可以选择或自定义加速代理源,当然,也只是普通的代理加速。
230+
231+
设置自定义代理加速方式如下:
232+
233+
1. 找到一个能够代理加速 github release 的站点,如 `gh-proxy.com`
234+
2. 查看站点提供的加速地址,如下载 1.5.20-windows-x64 版本的地址可以是 `https://gh-proxy.org/https://github.com/qiutongxue/oba-live-tool/releases/download/v1.5.20/oba-live-tool_1.5.20_windows_x64.exe`
235+
3.`https://github.com/……` 及后面的链接删除,保留前缀 `https://gh-proxy.org/`
236+
4. 将前缀地址复制到自定义更新源输入框中
216237

217238
亲测:Github 绝对可用。`gh-proxy.com` 偶尔可用。其余的github代理基本都不可用。
218239

219240
#### 开发者模式
220241

221242
启用开发者模式后,可以使用鼠标右键菜单,在菜单中可打开开发者工具。
222243

223-
启用开发者模式后,连接到中控台时会关闭浏览器的无头模式。
224-
225244
## 📑 许可证
226245

227246
本项目遵循 MIT 许可证

biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
2+
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
33
"vcs": {
44
"enabled": false,
55
"clientKind": "git",

electron/main/ipc/aichat.ts

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,8 @@ function setupIpcHandlers() {
88
IPC_CHANNELS.tasks.aiChat.chat,
99
async (_, { messages, apiKey, provider, model, customBaseURL }) => {
1010
try {
11-
const aiService = AIChatService.createService(
12-
apiKey,
13-
provider,
14-
customBaseURL,
15-
)
16-
for await (const { content, reasoning } of aiService.chatStream(
17-
messages,
18-
model,
19-
)) {
11+
const aiService = AIChatService.createService(apiKey, provider, customBaseURL)
12+
for await (const { content, reasoning } of aiService.chatStream(messages, model)) {
2013
if (content) {
2114
windowManager.send(IPC_CHANNELS.tasks.aiChat.stream, {
2215
chunk: content,
@@ -34,8 +27,7 @@ function setupIpcHandlers() {
3427
done: true,
3528
})
3629
} catch (error) {
37-
const errorMessage =
38-
error instanceof Error ? error.message : String(error)
30+
const errorMessage = error instanceof Error ? error.message : String(error)
3931

4032
windowManager.send(IPC_CHANNELS.tasks.aiChat.error, {
4133
error: errorMessage,
@@ -48,16 +40,11 @@ function setupIpcHandlers() {
4840
IPC_CHANNELS.tasks.aiChat.normalChat,
4941
async (_, { messages, apiKey, provider, model, customBaseURL }) => {
5042
try {
51-
const aiService = AIChatService.createService(
52-
apiKey,
53-
provider,
54-
customBaseURL,
55-
)
43+
const aiService = AIChatService.createService(apiKey, provider, customBaseURL)
5644
const output = await aiService.chat(messages, model)
5745
return output
5846
} catch (error) {
59-
const errorMessage =
60-
error instanceof Error ? error.message : String(error)
47+
const errorMessage = error instanceof Error ? error.message : String(error)
6148

6249
windowManager.send(IPC_CHANNELS.tasks.aiChat.error, {
6350
error: errorMessage,
@@ -71,18 +58,13 @@ function setupIpcHandlers() {
7158
IPC_CHANNELS.tasks.aiChat.testApiKey,
7259
async (_, { apiKey, provider, customBaseURL }) => {
7360
try {
74-
const aiService = AIChatService.createService(
75-
apiKey,
76-
provider,
77-
customBaseURL,
78-
)
61+
const aiService = AIChatService.createService(apiKey, provider, customBaseURL)
7962
await aiService.checkAPIKey()
8063
return {
8164
success: true,
8265
}
8366
} catch (error) {
84-
const errorMessage =
85-
error instanceof Error ? error.message : String(error)
67+
const errorMessage = error instanceof Error ? error.message : String(error)
8668
return {
8769
success: false,
8870
error: errorMessage,

electron/main/platforms/buyin/constant.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { SELECTORS as DY_SELECTORS } from '../douyin/constant'
22

33
export const URLS = {
44
LIVE_CONTROL_PAGE: 'https://buyin.jinritemai.com/dashboard/live/control',
5-
LOGIN_PAGE:
6-
'https://buyin.jinritemai.com/mpa/account/login?log_out=1&type=24',
5+
LOGIN_PAGE: 'https://buyin.jinritemai.com/mpa/account/login?log_out=1&type=24',
76
/** 百应的电商罗盘主页 */
87
COMPASS_INDEX: 'https://compass.jinritemai.com/talent',
98
COMPASS_SCREEN_WITH_LIVE_ROOM_ID:

electron/main/platforms/douyin-eos/element-finder.ts

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { Result } from '@praha/byethrow'
22
import type { ElementHandle, Page } from 'playwright'
3-
import {
4-
ElementDisabledError,
5-
ElementNotFoundError,
6-
} from '#/errors/PlatformError'
3+
import { ElementDisabledError, ElementNotFoundError } from '#/errors/PlatformError'
74
import { commonElementFinder, type IElementFinder } from './../IElementFinder'
85
import { SELECTORS } from './constant'
96

@@ -22,9 +19,7 @@ export const douyinEosElementFinder: IElementFinder = {
2219
}),
2320
)
2421
}
25-
if (
26-
await sendMessageButton.evaluate(el => el.className.includes('disable'))
27-
) {
22+
if (await sendMessageButton.evaluate(el => el.className.includes('disable'))) {
2823
return Result.fail(
2924
new ElementDisabledError({
3025
elementName: '发送评论按钮',
@@ -35,9 +30,7 @@ export const douyinEosElementFinder: IElementFinder = {
3530
return Result.succeed(sendMessageButton)
3631
},
3732

38-
async getPopUpButtonFromGoodsItem(
39-
item: ElementHandle<SVGElement | HTMLElement>,
40-
) {
33+
async getPopUpButtonFromGoodsItem(item: ElementHandle<SVGElement | HTMLElement>) {
4134
const button = await item.$(SELECTORS.goodsItem.POPUP_BUTTON)
4235
if (!button) {
4336
return Result.fail(
@@ -63,23 +56,14 @@ export const douyinEosElementFinder: IElementFinder = {
6356
},
6457

6558
async getCurrentGoodsItemsList(page: Page) {
66-
return commonElementFinder.getCurrentGoodsItemsList(
67-
page,
68-
SELECTORS.GOODS_ITEM,
69-
)
59+
return commonElementFinder.getCurrentGoodsItemsList(page, SELECTORS.GOODS_ITEM)
7060
},
7161

7262
async getGoodsItemsScrollContainer(page: Page) {
73-
return commonElementFinder.getGoodsItemsScrollContainer(
74-
page,
75-
SELECTORS.GOODS_ITEMS_WRAPPER,
76-
)
63+
return commonElementFinder.getGoodsItemsScrollContainer(page, SELECTORS.GOODS_ITEMS_WRAPPER)
7764
},
7865

7966
async getCommentTextarea(page: Page) {
80-
return commonElementFinder.getCommentTextarea(
81-
page,
82-
SELECTORS.commentInput.TEXTAREA,
83-
)
67+
return commonElementFinder.getCommentTextarea(page, SELECTORS.commentInput.TEXTAREA)
8468
},
8569
}

electron/main/platforms/douyin/element-finder.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { Result } from '@praha/byethrow'
22
import type { ElementHandle, Page } from 'playwright'
3-
import {
4-
ElementDisabledError,
5-
ElementNotFoundError,
6-
} from '#/errors/PlatformError'
3+
import { ElementDisabledError, ElementNotFoundError } from '#/errors/PlatformError'
74
import { commonElementFinder, type IElementFinder } from '../IElementFinder'
85
import { SELECTORS, TEXTS } from './constant'
96

@@ -46,9 +43,7 @@ export const douyinElementFinder: IElementFinder = {
4643
return Result.succeed(submit_btn)
4744
},
4845

49-
async getPopUpButtonFromGoodsItem(
50-
item: ElementHandle<SVGElement | HTMLElement>,
51-
) {
46+
async getPopUpButtonFromGoodsItem(item: ElementHandle<SVGElement | HTMLElement>) {
5247
const goodsAction = await item.$(SELECTORS.goodsItem.ACTION)
5348
if (!goodsAction) {
5449
return Result.fail(
@@ -78,27 +73,18 @@ export const douyinElementFinder: IElementFinder = {
7873
},
7974

8075
async getGoodsItemsScrollContainer(page: Page) {
81-
return commonElementFinder.getGoodsItemsScrollContainer(
82-
page,
83-
SELECTORS.GOODS_ITEMS_WRAPPER,
84-
)
76+
return commonElementFinder.getGoodsItemsScrollContainer(page, SELECTORS.GOODS_ITEMS_WRAPPER)
8577
},
8678

8779
async getCurrentGoodsItemsList(page: Page) {
88-
return commonElementFinder.getCurrentGoodsItemsList(
89-
page,
90-
SELECTORS.GOODS_ITEM,
91-
)
80+
return commonElementFinder.getCurrentGoodsItemsList(page, SELECTORS.GOODS_ITEM)
9281
},
9382

9483
async getIdFromGoodsItem(item: ElementHandle<SVGElement | HTMLElement>) {
9584
return commonElementFinder.getIdFromGoodsItem(item, SELECTORS.goodsItem.ID)
9685
},
9786

9887
async getCommentTextarea(page: Page) {
99-
return commonElementFinder.getCommentTextarea(
100-
page,
101-
SELECTORS.commentInput.TEXTAREA,
102-
)
88+
return commonElementFinder.getCommentTextarea(page, SELECTORS.commentInput.TEXTAREA)
10389
},
10490
}

electron/main/platforms/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { XiaohongshuPgyPlatform } from './xiaohongshu-pgy'
1212
export const platformFactory: Record<LiveControlPlatform, { new (): IPlatform }> = {
1313
buyin: BuyinPlatform,
1414
douyin: DouyinPlatform,
15-
redbook: XiaohongshuPlatform,
15+
xiaohongshu: XiaohongshuPlatform,
1616
wxchannel: WechatChannelPlatform,
1717
taobao: TaobaoPlatform,
1818
kuaishou: KuaishouPlatform,

electron/main/platforms/kuaishou/element-finder.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import { Result } from '@praha/byethrow'
22
import type { ElementHandle, Page } from 'playwright'
3-
import {
4-
ElementDisabledError,
5-
ElementNotFoundError,
6-
} from '#/errors/PlatformError'
3+
import { ElementDisabledError, ElementNotFoundError } from '#/errors/PlatformError'
74
import { commonElementFinder, type IElementFinder } from '../IElementFinder'
85
import { SELECTORS } from './constant'
96

107
export const kuaishouElementFinder: IElementFinder = {
11-
async getPopUpButtonFromGoodsItem(
12-
item: ElementHandle<SVGElement | HTMLElement>,
13-
) {
8+
async getPopUpButtonFromGoodsItem(item: ElementHandle<SVGElement | HTMLElement>) {
149
const button = await item.$(SELECTORS.goodsItem.POPUP_BUTTON)
1510
if (!button) {
1611
return Result.fail(
@@ -28,10 +23,7 @@ export const kuaishouElementFinder: IElementFinder = {
2823
},
2924

3025
async getCurrentGoodsItemsList(page: Page) {
31-
const items = await commonElementFinder.getCurrentGoodsItemsList(
32-
page,
33-
SELECTORS.GOODS_ITEM,
34-
)
26+
const items = await commonElementFinder.getCurrentGoodsItemsList(page, SELECTORS.GOODS_ITEM)
3527
if (Result.isFailure(items)) {
3628
return items
3729
}
@@ -47,17 +39,11 @@ export const kuaishouElementFinder: IElementFinder = {
4739
},
4840

4941
async getGoodsItemsScrollContainer(page: Page) {
50-
return commonElementFinder.getGoodsItemsScrollContainer(
51-
page,
52-
SELECTORS.GOODS_ITEMS_WRAPPER,
53-
)
42+
return commonElementFinder.getGoodsItemsScrollContainer(page, SELECTORS.GOODS_ITEMS_WRAPPER)
5443
},
5544

5645
getCommentTextarea(page: Page) {
57-
return commonElementFinder.getCommentTextarea(
58-
page,
59-
SELECTORS.commentInput.TEXTAREA,
60-
)
46+
return commonElementFinder.getCommentTextarea(page, SELECTORS.commentInput.TEXTAREA)
6147
},
6248

6349
async getClickableSubmitCommentButton(page: Page) {

electron/main/platforms/taobao/element-finder.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import { commonElementFinder, type IElementFinder } from '../IElementFinder'
99
import { SELECTORS } from './constant'
1010

1111
export const taobaoElementFinder: IElementFinder = {
12-
async getPopUpButtonFromGoodsItem(
13-
item: ElementHandle<SVGElement | HTMLElement>,
14-
) {
12+
async getPopUpButtonFromGoodsItem(item: ElementHandle<SVGElement | HTMLElement>) {
1513
const button = await item.$(SELECTORS.goodsItem.POPUP_BUTTON)
1614
if (!button) {
1715
return Result.fail(
@@ -48,24 +46,15 @@ export const taobaoElementFinder: IElementFinder = {
4846
},
4947

5048
async getCurrentGoodsItemsList(page: Page) {
51-
return commonElementFinder.getCurrentGoodsItemsList(
52-
page,
53-
SELECTORS.GOODS_ITEM,
54-
)
49+
return commonElementFinder.getCurrentGoodsItemsList(page, SELECTORS.GOODS_ITEM)
5550
},
5651

5752
async getGoodsItemsScrollContainer(page: Page) {
58-
return commonElementFinder.getGoodsItemsScrollContainer(
59-
page,
60-
SELECTORS.GOODS_ITEMS_WRAPPER,
61-
)
53+
return commonElementFinder.getGoodsItemsScrollContainer(page, SELECTORS.GOODS_ITEMS_WRAPPER)
6254
},
6355

6456
async getCommentTextarea(page: Page) {
65-
return commonElementFinder.getCommentTextarea(
66-
page,
67-
SELECTORS.commentInput.TEXTAREA,
68-
)
57+
return commonElementFinder.getCommentTextarea(page, SELECTORS.commentInput.TEXTAREA)
6958
},
7059

7160
async getClickableSubmitCommentButton(page: Page) {

0 commit comments

Comments
 (0)