2026-02-04 19:56:19 +08:00
|
|
|
|
// pythonBridge.js (Refactored to Electron IPC)
|
|
|
|
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
|
|
import { isElectron, safeElectronCall } from '@/utils/electronBridge';
|
|
|
|
|
|
|
|
|
|
|
|
// Check if we are in Electron environment
|
|
|
|
|
|
const inElectron = isElectron();
|
|
|
|
|
|
|
|
|
|
|
|
export function usePythonBridge() {
|
|
|
|
|
|
// ========== tk爬虫的接口 ==========
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fetchDataConfig (maps to updateStartConfig)
|
|
|
|
|
|
const fetchDataConfig = async (data) => {
|
|
|
|
|
|
if (!inElectron) return null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
return await window.electronAPI.tk.updateStartConfig(data);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('fetchDataConfig error:', e);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// fetchDataCount
|
|
|
|
|
|
const fetchDataCount = async () => {
|
|
|
|
|
|
if (!inElectron) return JSON.stringify({ totalCount: 0 });
|
|
|
|
|
|
try {
|
|
|
|
|
|
return await window.electronAPI.tk.getDataCount();
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('fetchDataCount error:', e);
|
|
|
|
|
|
return JSON.stringify({ totalCount: 0 });
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// loginTikTok
|
|
|
|
|
|
const loginTikTok = async () => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.loginTikTok();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// loginBackStage
|
|
|
|
|
|
const loginBackStage = async (data) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
if (data.index == 0) {
|
|
|
|
|
|
await window.electronAPI.tk.loginBackStage(JSON.stringify(data));
|
|
|
|
|
|
} else if (data.index == 1) {
|
|
|
|
|
|
await window.electronAPI.tk.loginBackStageCopy(JSON.stringify(data));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// givePyAnchorId -> visitAnchor
|
|
|
|
|
|
const givePyAnchorId = async (id) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.visitAnchor(id);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-09 21:04:09 +08:00
|
|
|
|
// 查询后台登录状态(合并接口,通过 account 参数区分)
|
|
|
|
|
|
// account: 公会账号,不传则返回所有账号状态
|
|
|
|
|
|
const backStageloginStatus = async (account) => {
|
2026-02-04 19:56:19 +08:00
|
|
|
|
if (!inElectron) return null;
|
2026-02-09 21:04:09 +08:00
|
|
|
|
try {
|
|
|
|
|
|
const res = await window.electronAPI.tk.checkBackStageLoginStatus(account);
|
|
|
|
|
|
return typeof res === 'string' ? JSON.parse(res) : res;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('backStageloginStatus error:', e);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2026-02-04 19:56:19 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-09 21:04:09 +08:00
|
|
|
|
// 兼容旧接口:查询副账号登录状态(内部调用合并后的接口)
|
|
|
|
|
|
const backStageloginStatusCopy = async (account) => {
|
|
|
|
|
|
return await backStageloginStatus(account);
|
2026-02-04 19:56:19 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// exportToExcel
|
|
|
|
|
|
const exportToExcel = async (data) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.exportData(JSON.stringify(data));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const stopScript = async () => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.stopCrawl();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// getVersion
|
|
|
|
|
|
const getVersion = async () => {
|
|
|
|
|
|
if (!inElectron) return 'Web Mode';
|
|
|
|
|
|
return await window.electronAPI.tk.getVersion();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// getTkLoginStatus
|
|
|
|
|
|
const getTkLoginStatus = async () => {
|
|
|
|
|
|
if (!inElectron) return "false";
|
|
|
|
|
|
return await window.electronAPI.tk.checkTkLoginStatus();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 粉丝助手的接口 ==========
|
|
|
|
|
|
|
|
|
|
|
|
const controlTask = async (data) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
// data is JSON string in original, ensure consistent
|
|
|
|
|
|
await window.electronAPI.tk.controlTask(data);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const getBrotherInfo = async () => {
|
|
|
|
|
|
if (!inElectron) return { total: 0, valid: 0 };
|
|
|
|
|
|
const res = await window.electronAPI.tk.getBrotherInfo();
|
|
|
|
|
|
return JSON.parse(res);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const Specifystreaming = async (data) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.findBigBrother(data);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const storageSetInfos = async (data) => {
|
|
|
|
|
|
// data is { key, data } object
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.storageSet(JSON.stringify(data));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const readSetInfos = async (key) => {
|
|
|
|
|
|
if (!inElectron) return "";
|
|
|
|
|
|
const res = await window.electronAPI.tk.storageRead(JSON.stringify(key));
|
|
|
|
|
|
return JSON.parse(res || '""'); // Handle potential empty string response
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Maps to visitAnchor
|
|
|
|
|
|
const openAnchorIdRooms = async (id) => {
|
|
|
|
|
|
if (!inElectron) return;
|
|
|
|
|
|
await window.electronAPI.tk.openRoom(id);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-09 21:04:09 +08:00
|
|
|
|
// Clipboard helper - 优先使用 Python RPC,fallback 到浏览器 API
|
2026-02-04 19:56:19 +08:00
|
|
|
|
const setClipboards = async (text) => {
|
2026-02-09 21:04:09 +08:00
|
|
|
|
if (inElectron) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const result = await window.electronAPI.tk.setClipboard(text);
|
|
|
|
|
|
if (result.success) return true;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.warn('Electron clipboard failed, fallback to browser:', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Fallback to browser API
|
2026-02-04 19:56:19 +08:00
|
|
|
|
try {
|
|
|
|
|
|
await navigator.clipboard.writeText(text);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('Clipboard failed', e);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-09 21:04:09 +08:00
|
|
|
|
// ========== 新增接口 ==========
|
|
|
|
|
|
|
|
|
|
|
|
// 启动大哥监控(TikTok 登录)
|
|
|
|
|
|
const startBrotherMonitor = async () => {
|
|
|
|
|
|
if (!inElectron) return { success: false, error: 'Not in Electron' };
|
|
|
|
|
|
try {
|
|
|
|
|
|
return await window.electronAPI.tk.startBrotherMonitor();
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('startBrotherMonitor error:', e);
|
|
|
|
|
|
return { success: false, error: String(e) };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取大哥模块 TikTok 登录状态
|
|
|
|
|
|
const getBrotherLoginStatus = async () => {
|
|
|
|
|
|
if (!inElectron) return { isLoggedIn: false };
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await window.electronAPI.tk.getBrotherLoginStatus();
|
|
|
|
|
|
return JSON.parse(res);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('getBrotherLoginStatus error:', e);
|
|
|
|
|
|
return { isLoggedIn: false };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 打开大哥个人主页
|
|
|
|
|
|
const visitGifter = async (data) => {
|
|
|
|
|
|
if (!inElectron) return { success: false };
|
|
|
|
|
|
try {
|
|
|
|
|
|
// data 可以是 { id: 'xxx' } 或 { uniqueId: 'xxx' }
|
|
|
|
|
|
return await window.electronAPI.tk.visitGifter(JSON.stringify(data));
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('visitGifter error:', e);
|
|
|
|
|
|
return { success: false, error: String(e) };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭所有浏览器
|
|
|
|
|
|
const closeAllBrowsers = async () => {
|
|
|
|
|
|
if (!inElectron) return { success: false, error: 'Not in Electron' };
|
|
|
|
|
|
try {
|
|
|
|
|
|
return await window.electronAPI.tk.closeAllBrowsers();
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('closeAllBrowsers error:', e);
|
|
|
|
|
|
return { success: false, error: String(e) };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 加密存储账号信息
|
|
|
|
|
|
const storageAccountInfo = async (data) => {
|
|
|
|
|
|
if (!inElectron) return { success: false, error: 'Not in Electron' };
|
|
|
|
|
|
try {
|
|
|
|
|
|
// data: { key: string, data: object }
|
|
|
|
|
|
return await window.electronAPI.tk.storageAccount(JSON.stringify(data));
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('storageAccountInfo error:', e);
|
|
|
|
|
|
return { success: false, error: String(e) };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 解密读取账号信息
|
|
|
|
|
|
const readAccountInfo = async (key) => {
|
|
|
|
|
|
if (!inElectron) return { status: 'error', message: 'Not in Electron', data: null };
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await window.electronAPI.tk.readAccount(JSON.stringify({ key }));
|
|
|
|
|
|
return JSON.parse(res);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('readAccountInfo error:', e);
|
|
|
|
|
|
return { status: 'error', message: String(e), data: null };
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-04 19:56:19 +08:00
|
|
|
|
return {
|
|
|
|
|
|
fetchDataConfig,
|
|
|
|
|
|
fetchDataCount,
|
|
|
|
|
|
loginBackStage,
|
|
|
|
|
|
loginTikTok,
|
|
|
|
|
|
givePyAnchorId,
|
|
|
|
|
|
backStageloginStatus,
|
|
|
|
|
|
backStageloginStatusCopy,
|
|
|
|
|
|
exportToExcel,
|
|
|
|
|
|
stopScript,
|
|
|
|
|
|
getVersion,
|
|
|
|
|
|
getTkLoginStatus,
|
|
|
|
|
|
// New Fan Workbench exports
|
|
|
|
|
|
controlTask,
|
|
|
|
|
|
getBrotherInfo,
|
|
|
|
|
|
Specifystreaming,
|
|
|
|
|
|
storageSetInfos,
|
|
|
|
|
|
readSetInfos,
|
|
|
|
|
|
openAnchorIdRooms,
|
2026-02-09 21:04:09 +08:00
|
|
|
|
setClipboards,
|
|
|
|
|
|
// 新增接口
|
|
|
|
|
|
startBrotherMonitor,
|
|
|
|
|
|
getBrotherLoginStatus,
|
|
|
|
|
|
visitGifter,
|
|
|
|
|
|
closeAllBrowsers,
|
|
|
|
|
|
storageAccountInfo,
|
|
|
|
|
|
readAccountInfo
|
2026-02-04 19:56:19 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|