fix: update version to 0.5.3 and enhance placeholder selection logic in publishArticle function
This commit is contained in:
parent
6194f71378
commit
fa155da15d
|
|
@ -6,7 +6,7 @@
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||||
"version": "0.5.2"
|
"version": "0.5.3"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -481,52 +481,78 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||||
const img = sortedImages[i]!;
|
const img = sortedImages[i]!;
|
||||||
console.log(`[x-article] [${i + 1}/${sortedImages.length}] Inserting image at placeholder: ${img.placeholder}`);
|
console.log(`[x-article] [${i + 1}/${sortedImages.length}] Inserting image at placeholder: ${img.placeholder}`);
|
||||||
|
|
||||||
// Find, scroll to, and select the placeholder text in DraftEditor
|
// Helper to select placeholder with retry
|
||||||
const placeholderFound = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
|
const selectPlaceholder = async (maxRetries = 3): Promise<boolean> => {
|
||||||
expression: `(() => {
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
// Find, scroll to, and select the placeholder text in DraftEditor
|
||||||
if (!editor) return false;
|
await cdp!.send('Runtime.evaluate', {
|
||||||
|
expression: `(() => {
|
||||||
|
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
||||||
|
if (!editor) return false;
|
||||||
|
|
||||||
const placeholder = ${JSON.stringify(img.placeholder)};
|
const placeholder = ${JSON.stringify(img.placeholder)};
|
||||||
|
|
||||||
// Search through all text nodes in the editor
|
// Search through all text nodes in the editor
|
||||||
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
|
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
|
||||||
let node;
|
let node;
|
||||||
|
|
||||||
while ((node = walker.nextNode())) {
|
while ((node = walker.nextNode())) {
|
||||||
const text = node.textContent || '';
|
const text = node.textContent || '';
|
||||||
const idx = text.indexOf(placeholder);
|
const idx = text.indexOf(placeholder);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
// Found the placeholder - scroll to it first
|
// Found the placeholder - scroll to it first
|
||||||
const parentElement = node.parentElement;
|
const parentElement = node.parentElement;
|
||||||
if (parentElement) {
|
if (parentElement) {
|
||||||
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select it
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
})()`,
|
||||||
|
}, { sessionId });
|
||||||
|
|
||||||
// Select it
|
// Wait for scroll and selection to settle
|
||||||
const range = document.createRange();
|
await sleep(800);
|
||||||
range.setStart(node, idx);
|
|
||||||
range.setEnd(node, idx + placeholder.length);
|
// Verify selection matches the placeholder
|
||||||
const sel = window.getSelection();
|
const selectionCheck = await cdp!.send<{ result: { value: string } }>('Runtime.evaluate', {
|
||||||
sel.removeAllRanges();
|
expression: `window.getSelection()?.toString() || ''`,
|
||||||
sel.addRange(range);
|
returnByValue: true,
|
||||||
return true;
|
}, { sessionId });
|
||||||
}
|
|
||||||
|
const selectedText = selectionCheck.result.value.trim();
|
||||||
|
if (selectedText === img.placeholder) {
|
||||||
|
console.log(`[x-article] Selection verified: "${selectedText}"`);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
})()`,
|
|
||||||
returnByValue: true,
|
|
||||||
}, { sessionId });
|
|
||||||
|
|
||||||
// Wait for scroll animation
|
if (attempt < maxRetries) {
|
||||||
await sleep(500);
|
console.log(`[x-article] Selection attempt ${attempt} got "${selectedText}", retrying...`);
|
||||||
|
await sleep(500);
|
||||||
|
} else {
|
||||||
|
console.warn(`[x-article] Selection failed after ${maxRetries} attempts, got: "${selectedText}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
if (!placeholderFound.result.value) {
|
// Try to select the placeholder
|
||||||
console.warn(`[x-article] Placeholder not found in DOM: ${img.placeholder}`);
|
const selected = await selectPlaceholder(3);
|
||||||
|
if (!selected) {
|
||||||
|
console.warn(`[x-article] Skipping image - could not select placeholder: ${img.placeholder}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[x-article] Placeholder selected, copying image: ${path.basename(img.localPath)}`);
|
console.log(`[x-article] Copying image: ${path.basename(img.localPath)}`);
|
||||||
|
|
||||||
// Copy image to clipboard
|
// Copy image to clipboard
|
||||||
if (!copyImageToClipboard(img.localPath)) {
|
if (!copyImageToClipboard(img.localPath)) {
|
||||||
|
|
@ -535,17 +561,48 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for clipboard to be fully ready
|
// Wait for clipboard to be fully ready
|
||||||
await sleep(800);
|
await sleep(1000);
|
||||||
|
|
||||||
// Delete placeholder by pressing Enter (placeholder is already selected)
|
// Delete placeholder by pressing Backspace (more reliable than Enter for replacing selection)
|
||||||
console.log(`[x-article] Deleting placeholder with Enter...`);
|
console.log(`[x-article] Deleting placeholder...`);
|
||||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13 }, { sessionId });
|
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13 }, { sessionId });
|
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||||
|
|
||||||
|
// Wait and verify placeholder is deleted
|
||||||
|
await sleep(500);
|
||||||
|
|
||||||
|
// Check that placeholder is no longer in editor
|
||||||
|
const afterDelete = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
|
||||||
|
expression: `(() => {
|
||||||
|
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
||||||
|
if (!editor) return true;
|
||||||
|
return !editor.innerText.includes(${JSON.stringify(img.placeholder)});
|
||||||
|
})()`,
|
||||||
|
returnByValue: true,
|
||||||
|
}, { sessionId });
|
||||||
|
|
||||||
|
if (!afterDelete.result.value) {
|
||||||
|
console.warn(`[x-article] Placeholder may not have been deleted, trying again...`);
|
||||||
|
// Try selecting and deleting again
|
||||||
|
await selectPlaceholder(1);
|
||||||
|
await sleep(300);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus editor to ensure cursor is in position
|
||||||
|
await cdp.send('Runtime.evaluate', {
|
||||||
|
expression: `(() => {
|
||||||
|
const editor = document.querySelector('.DraftEditor-editorContainer [contenteditable="true"]');
|
||||||
|
if (editor) editor.focus();
|
||||||
|
})()`,
|
||||||
|
}, { sessionId });
|
||||||
await sleep(300);
|
await sleep(300);
|
||||||
|
|
||||||
// Paste image using paste script (activates Chrome, sends real keystroke)
|
// Paste image using paste script (activates Chrome, sends real keystroke)
|
||||||
console.log(`[x-article] Pasting image...`);
|
console.log(`[x-article] Pasting image...`);
|
||||||
if (pasteFromClipboard('Google Chrome', 5, 800)) {
|
if (pasteFromClipboard('Google Chrome', 5, 1000)) {
|
||||||
console.log(`[x-article] Image pasted: ${path.basename(img.localPath)}`);
|
console.log(`[x-article] Image pasted: ${path.basename(img.localPath)}`);
|
||||||
} else {
|
} else {
|
||||||
console.warn(`[x-article] Failed to paste image after retries`);
|
console.warn(`[x-article] Failed to paste image after retries`);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue