fix(baoyu-post-to-weibo): simplify article image insertion with Backspace-based placeholder deletion

This commit is contained in:
Jim Liu 宝玉
2026-03-08 15:49:54 -05:00
parent d4a5a34865
commit 059ebc759c
@@ -459,7 +459,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
if (charAfter === undefined || !/\\d/.test(charAfter)) {
const parentElement = node.parentElement;
if (parentElement) {
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
parentElement.scrollIntoView({ behavior: 'instant', block: 'center' });
}
const range = document.createRange();
@@ -500,112 +500,56 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
return false;
};
// Step A: Copy image to clipboard first (slow due to Swift compilation)
console.log(`[weibo-article] Copying image to clipboard: ${path.basename(img.localPath)}`);
if (!copyImageToClipboard(img.localPath)) {
console.warn(`[weibo-article] Failed to copy image to clipboard`);
continue;
}
await sleep(500);
// Step B: Select placeholder text (paste will replace the selection)
const selected = await selectPlaceholder(3);
if (!selected) {
console.warn(`[weibo-article] Skipping image - could not select placeholder: ${img.placeholder}`);
continue;
}
console.log(`[weibo-article] Copying image: ${path.basename(img.localPath)}`);
if (!copyImageToClipboard(img.localPath)) {
console.warn(`[weibo-article] Failed to copy image to clipboard`);
continue;
}
await sleep(1000);
// Delete placeholder by replacing selection with empty text
console.log(`[weibo-article] Deleting placeholder...`);
await cdp.send('Runtime.evaluate', {
expression: `(() => {
const sel = window.getSelection();
if (!sel || sel.isCollapsed) return false;
const range = sel.getRangeAt(0);
range.deleteContents();
sel.collapseToStart();
return true;
})()`,
returnByValue: true,
}, { sessionId });
await sleep(300);
// Fallback: send Backspace key if placeholder still exists
const stillExists = await cdp!.send<{ result: { value: boolean } }>('Runtime.evaluate', {
expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return false;
const placeholder = ${JSON.stringify(img.placeholder)};
const regex = new RegExp(placeholder + '(?!\\\\d)');
return regex.test(editor.innerText);
})()`,
returnByValue: true,
}, { sessionId });
if (stillExists.result.value) {
console.log('[weibo-article] Placeholder survived deleteContents, trying Input.insertText replacement...');
// Re-select and replace with empty via Input.insertText
await cdp!.send('Runtime.evaluate', {
expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return false;
const placeholder = ${JSON.stringify(img.placeholder)};
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
let node;
while ((node = walker.nextNode())) {
const text = node.textContent || '';
let searchStart = 0;
let idx;
while ((idx = text.indexOf(placeholder, searchStart)) !== -1) {
const afterIdx = idx + placeholder.length;
const charAfter = text[afterIdx];
if (charAfter === undefined || !/\\d/.test(charAfter)) {
const range = document.createRange();
range.setStart(node, idx);
range.setEnd(node, idx + placeholder.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
return true;
}
searchStart = afterIdx;
}
}
return false;
})()`,
}, { sessionId });
await sleep(200);
await cdp!.send('Input.insertText', { text: '' }, { sessionId });
await sleep(300);
}
await sleep(200);
// Step C: Delete selected placeholder via Backspace (ProseMirror-compatible)
console.log(`[weibo-article] Deleting placeholder via Backspace...`);
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
await sleep(500);
// Verify placeholder was deleted
const afterDelete = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
const placeholderGone = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
expression: `(() => {
const editor = document.querySelector('div[contenteditable="true"]');
if (!editor) return true;
const text = editor.innerText;
const placeholder = ${JSON.stringify(img.placeholder)};
const regex = new RegExp(placeholder + '(?!\\\\d)');
return !regex.test(text);
return !regex.test(editor.innerText);
})()`,
returnByValue: true,
}, { sessionId });
if (afterDelete.result.value) {
if (placeholderGone.result.value) {
console.log(`[weibo-article] Placeholder deleted`);
} else {
console.warn(`[weibo-article] Placeholder may still exist after delete`);
console.warn(`[weibo-article] Placeholder may still exist, trying execCommand delete...`);
// Re-select and delete via execCommand
await selectPlaceholder(1);
await cdp.send('Runtime.evaluate', {
expression: `document.execCommand('delete')`,
}, { sessionId });
await sleep(300);
}
// Focus editor for paste
// Step D: Focus editor and paste image
await cdp.send('Runtime.evaluate', {
expression: `document.querySelector('div[contenteditable="true"]')?.focus()`,
}, { sessionId });
await sleep(300);
await sleep(200);
// Count images before paste
const imgCountBefore = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', {
@@ -613,7 +557,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
returnByValue: true,
}, { sessionId });
// Paste image
// Paste image at cursor position (where placeholder was)
console.log(`[weibo-article] Pasting image...`);
if (pasteFromClipboard('Google Chrome', 5, 1000)) {
console.log(`[weibo-article] Paste keystroke sent for: ${path.basename(img.localPath)}`);