mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-15 06:59:48 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e68aa64a4 | |||
| 059ebc759c |
@@ -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": "1.56.0"
|
"version": "1.56.1"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
English | [中文](./CHANGELOG.zh.md)
|
English | [中文](./CHANGELOG.zh.md)
|
||||||
|
|
||||||
|
## 1.56.1 - 2026-03-08
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- `baoyu-post-to-weibo`: simplify article image insertion with Backspace-based placeholder deletion for ProseMirror compatibility
|
||||||
|
|
||||||
## 1.56.0 - 2026-03-08
|
## 1.56.0 - 2026-03-08
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
[English](./CHANGELOG.md) | 中文
|
[English](./CHANGELOG.md) | 中文
|
||||||
|
|
||||||
|
## 1.56.1 - 2026-03-08
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- `baoyu-post-to-weibo`:简化头条文章图片插入逻辑,使用 Backspace 按键替代复杂的 deleteContents 方案,兼容 ProseMirror 编辑器
|
||||||
|
|
||||||
## 1.56.0 - 2026-03-08
|
## 1.56.0 - 2026-03-08
|
||||||
|
|
||||||
### 新功能
|
### 新功能
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
|||||||
if (charAfter === undefined || !/\\d/.test(charAfter)) {
|
if (charAfter === undefined || !/\\d/.test(charAfter)) {
|
||||||
const parentElement = node.parentElement;
|
const parentElement = node.parentElement;
|
||||||
if (parentElement) {
|
if (parentElement) {
|
||||||
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
parentElement.scrollIntoView({ behavior: 'instant', block: 'center' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
@@ -500,112 +500,56 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
|||||||
return false;
|
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);
|
const selected = await selectPlaceholder(3);
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
console.warn(`[weibo-article] Skipping image - could not select placeholder: ${img.placeholder}`);
|
console.warn(`[weibo-article] Skipping image - could not select placeholder: ${img.placeholder}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[weibo-article] Copying image: ${path.basename(img.localPath)}`);
|
// Step C: Delete selected placeholder via Backspace (ProseMirror-compatible)
|
||||||
|
console.log(`[weibo-article] Deleting placeholder via Backspace...`);
|
||||||
if (!copyImageToClipboard(img.localPath)) {
|
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||||
console.warn(`[weibo-article] Failed to copy image to clipboard`);
|
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||||
continue;
|
await sleep(500);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Verify placeholder was deleted
|
// 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: `(() => {
|
expression: `(() => {
|
||||||
const editor = document.querySelector('div[contenteditable="true"]');
|
const editor = document.querySelector('div[contenteditable="true"]');
|
||||||
if (!editor) return true;
|
if (!editor) return true;
|
||||||
const text = editor.innerText;
|
|
||||||
const placeholder = ${JSON.stringify(img.placeholder)};
|
const placeholder = ${JSON.stringify(img.placeholder)};
|
||||||
const regex = new RegExp(placeholder + '(?!\\\\d)');
|
const regex = new RegExp(placeholder + '(?!\\\\d)');
|
||||||
return !regex.test(text);
|
return !regex.test(editor.innerText);
|
||||||
})()`,
|
})()`,
|
||||||
returnByValue: true,
|
returnByValue: true,
|
||||||
}, { sessionId });
|
}, { sessionId });
|
||||||
|
|
||||||
if (afterDelete.result.value) {
|
if (placeholderGone.result.value) {
|
||||||
console.log(`[weibo-article] Placeholder deleted`);
|
console.log(`[weibo-article] Placeholder deleted`);
|
||||||
} else {
|
} 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', {
|
await cdp.send('Runtime.evaluate', {
|
||||||
expression: `document.querySelector('div[contenteditable="true"]')?.focus()`,
|
expression: `document.querySelector('div[contenteditable="true"]')?.focus()`,
|
||||||
}, { sessionId });
|
}, { sessionId });
|
||||||
await sleep(300);
|
await sleep(200);
|
||||||
|
|
||||||
// Count images before paste
|
// Count images before paste
|
||||||
const imgCountBefore = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', {
|
const imgCountBefore = await cdp.send<{ result: { value: number } }>('Runtime.evaluate', {
|
||||||
@@ -613,7 +557,7 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
|||||||
returnByValue: true,
|
returnByValue: true,
|
||||||
}, { sessionId });
|
}, { sessionId });
|
||||||
|
|
||||||
// Paste image
|
// Paste image at cursor position (where placeholder was)
|
||||||
console.log(`[weibo-article] Pasting image...`);
|
console.log(`[weibo-article] Pasting image...`);
|
||||||
if (pasteFromClipboard('Google Chrome', 5, 1000)) {
|
if (pasteFromClipboard('Google Chrome', 5, 1000)) {
|
||||||
console.log(`[weibo-article] Paste keystroke sent for: ${path.basename(img.localPath)}`);
|
console.log(`[weibo-article] Paste keystroke sent for: ${path.basename(img.localPath)}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user