Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Post text, images, videos, and long-form articles to Weibo (微博) via Chrome browser automation.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/weibo-utils.ts
1import { execSync, spawnSync } from 'node:child_process';2import path from 'node:path';3import process from 'node:process';4import { fileURLToPath } from 'node:url';56import {7CdpConnection,8findChromeExecutable as findChromeExecutableBase,9findExistingChromeDebugPort as findExistingChromeDebugPortBase,10getFreePort as getFreePortBase,11launchChrome as launchChromeBase,12resolveSharedChromeProfileDir,13sleep,14waitForChromeDebugPort,15type PlatformCandidates,16} from 'baoyu-chrome-cdp';1718export { CdpConnection, sleep, waitForChromeDebugPort };1920export const CHROME_CANDIDATES: PlatformCandidates = {21darwin: [22'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',23'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',24'/Applications/Chromium.app/Contents/MacOS/Chromium',25],26win32: [27'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',28'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',29],30default: [31'/usr/bin/google-chrome',32'/usr/bin/chromium',33'/usr/bin/chromium-browser',34],35};3637let wslHome: string | null | undefined;38function getWslWindowsHome(): string | null {39if (wslHome !== undefined) return wslHome;40if (!process.env.WSL_DISTRO_NAME) {41wslHome = null;42return null;43}44try {45const raw = execSync('cmd.exe /C "echo %USERPROFILE%"', {46encoding: 'utf-8',47timeout: 5_000,48}).trim().replace(/\r/g, '');49wslHome = execSync(`wslpath -u "${raw}"`, {50encoding: 'utf-8',51timeout: 5_000,52}).trim() || null;53} catch {54wslHome = null;55}56return wslHome;57}5859export function findChromeExecutable(chromePathOverride?: string): string | undefined {60if (chromePathOverride?.trim()) return chromePathOverride.trim();61return findChromeExecutableBase({62candidates: CHROME_CANDIDATES,63envNames: ['WEIBO_BROWSER_CHROME_PATH'],64});65}6667export async function findExistingChromeDebugPort(profileDir: string): Promise<number | null> {68return await findExistingChromeDebugPortBase({ profileDir });69}7071export function killChromeByProfile(profileDir: string): void {72try {73const result = spawnSync('ps', ['aux'], { encoding: 'utf-8', timeout: 5_000 });74if (result.status !== 0 || !result.stdout) return;75for (const line of result.stdout.split('\n')) {76if (!line.includes(profileDir) || !line.includes('--remote-debugging-port=')) continue;77const pid = line.trim().split(/\s+/)[1];78if (pid) {79try {80process.kill(Number(pid), 'SIGTERM');81} catch {}82}83}84} catch {}85}8687export function getDefaultProfileDir(): string {88return resolveSharedChromeProfileDir({89envNames: ['BAOYU_CHROME_PROFILE_DIR', 'WEIBO_BROWSER_PROFILE_DIR'],90wslWindowsHome: getWslWindowsHome(),91});92}9394export async function getFreePort(): Promise<number> {95return await getFreePortBase('WEIBO_BROWSER_DEBUG_PORT');96}9798export async function launchChrome(url: string, profileDir: string, chromePathOverride?: string): Promise<number> {99const chromePath = findChromeExecutable(chromePathOverride);100if (!chromePath) throw new Error('Chrome not found. Set WEIBO_BROWSER_CHROME_PATH env var.');101102const port = await getFreePort();103console.log(`[weibo-cdp] Launching Chrome (profile: ${profileDir})`);104await launchChromeBase({105chromePath,106profileDir,107port,108url,109extraArgs: ['--disable-blink-features=AutomationControlled', '--start-maximized'],110});111return port;112}113114export function getScriptDir(): string {115return path.dirname(fileURLToPath(import.meta.url));116}117118function runBunScript(scriptPath: string, args: string[]): boolean {119const result = spawnSync('npx', ['-y', 'bun', scriptPath, ...args], { stdio: 'inherit' });120return result.status === 0;121}122123export function copyImageToClipboard(imagePath: string): boolean {124const copyScript = path.join(getScriptDir(), 'copy-to-clipboard.ts');125return runBunScript(copyScript, ['image', imagePath]);126}127128export function copyHtmlToClipboard(htmlPath: string): boolean {129const copyScript = path.join(getScriptDir(), 'copy-to-clipboard.ts');130return runBunScript(copyScript, ['html', '--file', htmlPath]);131}132133export function pasteFromClipboard(targetApp?: string, retries = 3, delayMs = 500): boolean {134const pasteScript = path.join(getScriptDir(), 'paste-from-clipboard.ts');135const args = ['--retries', String(retries), '--delay', String(delayMs)];136if (targetApp) args.push('--app', targetApp);137return runBunScript(pasteScript, args);138}139