Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef620109cf |
@@ -3,6 +3,7 @@
|
||||
AiToEarn 自维护的 Chrome/Edge 扩展,也是 Gitea Release 唯一允许打包发布的扩展源码,用于:
|
||||
|
||||
- 从当前网页采集标题、正文和图片。
|
||||
- 在普通 HTTP 采集不足时复用当前 Chrome 标签页,等待动态页面渲染后回传正文、HTML、图片和链接。
|
||||
- 在 AiToEarn 页面提供 `window.AIToEarnDistribution` 分发桥接。
|
||||
- 复用浏览器现有登录状态检测内容平台账号。
|
||||
- 将同一份 Markdown、HTML 或纯文本内容填入平台编辑器。
|
||||
@@ -12,6 +13,8 @@ AiToEarn 自维护的 Chrome/Edge 扩展,也是 Gitea Release 唯一允许打
|
||||
|
||||
扩展弹窗和后台通知中的“成功”只表示平台编辑器已打开并完成内容填充,不表示内容已经公开发布。右键菜单“提取此页面到 AiToEarn”会把最近一次提取结果暂存到浏览器本地,随后打开扩展即可继续选择平台。
|
||||
|
||||
AiToEarn 后台触发浏览器采集时会优先复用同地址标签页;没有现成标签页时才在当前 Chrome 内创建后台标签页。普通采集完成后临时标签页会关闭,遇到登录、验证码或地区访问限制时则保留并激活页面,等待用户处理。
|
||||
|
||||
## 上游来源
|
||||
|
||||
多平台检测与编辑器填充逻辑基于 `doocs/cose`,固定版本和许可证见:
|
||||
|
||||
+122
@@ -1,6 +1,112 @@
|
||||
import './distribution/cose/background.js';
|
||||
|
||||
const PREPARE_BATCH_MESSAGE = 'PREPARE_PLATFORM_BATCH';
|
||||
const CAPTURE_URL_MESSAGE = 'CAPTURE_URL';
|
||||
const CAPTURE_ATTEMPTS = 8;
|
||||
|
||||
function sleep(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
|
||||
function normalizeCaptureUrl(value) {
|
||||
const url = new URL(value);
|
||||
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('只支持采集 HTTP 或 HTTPS 页面');
|
||||
if (url.username || url.password) throw new Error('采集地址不能包含账号或密码');
|
||||
url.hash = '';
|
||||
return url;
|
||||
}
|
||||
|
||||
function comparableUrl(value) {
|
||||
try {
|
||||
return normalizeCaptureUrl(value).href.replace(/\/$/, '');
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForTabReady(tabId) {
|
||||
const deadline = Date.now() + 30000;
|
||||
while (Date.now() < deadline) {
|
||||
const tab = await chrome.tabs.get(tabId);
|
||||
if (tab.status === 'complete') return;
|
||||
await sleep(300);
|
||||
}
|
||||
throw new Error('页面加载超时');
|
||||
}
|
||||
|
||||
async function requestPageExtraction(tabId) {
|
||||
try {
|
||||
return await chrome.tabs.sendMessage(tabId, { action: 'extractContent' });
|
||||
} catch {
|
||||
await chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'] });
|
||||
return chrome.tabs.sendMessage(tabId, { action: 'extractContent' });
|
||||
}
|
||||
}
|
||||
|
||||
async function captureUrl(rawUrl) {
|
||||
const requestedUrl = normalizeCaptureUrl(rawUrl);
|
||||
const requestedComparableUrl = comparableUrl(requestedUrl.href);
|
||||
const tabs = await chrome.tabs.query({});
|
||||
let tab = tabs.find(candidate => candidate.id && comparableUrl(candidate.url) === requestedComparableUrl);
|
||||
const createdTab = !tab;
|
||||
let keepTabOpen = false;
|
||||
|
||||
if (!tab) {
|
||||
tab = await chrome.tabs.create({ url: requestedUrl.href, active: false });
|
||||
}
|
||||
if (!tab.id) throw new Error('无法创建或复用采集标签页');
|
||||
|
||||
try {
|
||||
await waitForTabReady(tab.id);
|
||||
let lastBodyLength = 0;
|
||||
let lastTitle = '';
|
||||
|
||||
for (let attempt = 1; attempt <= CAPTURE_ATTEMPTS; attempt += 1) {
|
||||
const response = await requestPageExtraction(tab.id);
|
||||
if (!response?.success) throw new Error(response?.error || '扩展无法读取页面内容');
|
||||
|
||||
const data = response.data || {};
|
||||
const accessState = data.accessState || { status: 'ok', message: '', requiresUserAction: false };
|
||||
if (accessState.requiresUserAction) {
|
||||
keepTabOpen = true;
|
||||
await chrome.tabs.update(tab.id, { active: true });
|
||||
return {
|
||||
success: false,
|
||||
error: accessState.message || '页面需要人工操作后才能继续采集',
|
||||
requiresUserAction: true,
|
||||
accessState,
|
||||
tabId: tab.id,
|
||||
reusedTab: !createdTab,
|
||||
};
|
||||
}
|
||||
|
||||
const bodyLength = typeof data.body === 'string' ? data.body.trim().length : 0;
|
||||
const minimumLength = data.pageType === 'article' ? 120 : 60;
|
||||
lastBodyLength = bodyLength;
|
||||
lastTitle = data.title || '';
|
||||
if (bodyLength >= minimumLength) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
...data,
|
||||
url: requestedUrl.href,
|
||||
finalUrl: data.url || requestedUrl.href,
|
||||
},
|
||||
tabId: tab.id,
|
||||
reusedTab: !createdTab,
|
||||
};
|
||||
}
|
||||
|
||||
await sleep(Math.min(2500, 600 + attempt * 250));
|
||||
}
|
||||
|
||||
throw new Error(`页面已打开,但动态正文仍未渲染完成(标题:${lastTitle || '未知'},正文 ${lastBodyLength} 字)`);
|
||||
} finally {
|
||||
if (createdTab && !keepTabOpen) {
|
||||
await chrome.tabs.remove(tab.id).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function preparePlatformBatch(platformIds, content) {
|
||||
await chrome.runtime.sendMessage({ type: 'START_SYNC_BATCH' });
|
||||
@@ -86,6 +192,22 @@ chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.type === CAPTURE_URL_MESSAGE) {
|
||||
if (typeof request.url !== 'string' || !request.url.trim()) {
|
||||
sendResponse({ success: false, error: '缺少要采集的页面地址' });
|
||||
return false;
|
||||
}
|
||||
captureUrl(request.url)
|
||||
.then(sendResponse)
|
||||
.catch((error) => {
|
||||
sendResponse({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.type !== PREPARE_BATCH_MESSAGE) return false;
|
||||
|
||||
const platformIds = Array.isArray(request.platformIds)
|
||||
|
||||
+112
-41
@@ -3,17 +3,47 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
if (globalThis.__AI_TO_EARN_CONTENT_SCRIPT__) return;
|
||||
globalThis.__AI_TO_EARN_CONTENT_SCRIPT__ = true;
|
||||
|
||||
const contentSelectors = [
|
||||
'article',
|
||||
'[role="main"]',
|
||||
'main',
|
||||
'.amos-land-page',
|
||||
'.post-content',
|
||||
'.article-content',
|
||||
'.entry-content',
|
||||
'.content-body',
|
||||
'.markdown-body',
|
||||
'.rich_media_content',
|
||||
'#article-content',
|
||||
'#content',
|
||||
'.content',
|
||||
'.post',
|
||||
'.article',
|
||||
'.story-body',
|
||||
'#cnblogs_post_body',
|
||||
'.htmledit_views',
|
||||
'#article_content',
|
||||
'.blog-content-box'
|
||||
];
|
||||
|
||||
// ===== Content Extraction =====
|
||||
function extractPageContent() {
|
||||
const data = {
|
||||
title: '',
|
||||
description: '',
|
||||
body: '',
|
||||
html: '',
|
||||
images: [],
|
||||
links: [],
|
||||
url: window.location.href,
|
||||
siteName: '',
|
||||
author: '',
|
||||
publishDate: ''
|
||||
publishDate: '',
|
||||
pageType: 'article',
|
||||
accessState: { status: 'ok', message: '', requiresUserAction: false }
|
||||
};
|
||||
|
||||
// --- Title ---
|
||||
@@ -43,10 +73,15 @@
|
||||
|| '';
|
||||
|
||||
// --- Body Content ---
|
||||
data.body = extractMainContent();
|
||||
const mainContent = extractMainContent();
|
||||
data.body = mainContent.text.slice(0, 100000);
|
||||
data.html = mainContent.html.slice(0, 900000);
|
||||
|
||||
// --- Images ---
|
||||
data.images = extractImages();
|
||||
data.images = extractImages(mainContent.element);
|
||||
data.links = extractLinks(mainContent.element);
|
||||
data.pageType = detectPageType();
|
||||
data.accessState = detectAccessState(data.body);
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -58,34 +93,12 @@
|
||||
|
||||
// ===== Main Content Extraction =====
|
||||
function extractMainContent() {
|
||||
// Priority selectors for main content areas
|
||||
const contentSelectors = [
|
||||
'article',
|
||||
'[role="main"]',
|
||||
'main',
|
||||
'.post-content',
|
||||
'.article-content',
|
||||
'.entry-content',
|
||||
'.content-body',
|
||||
'.markdown-body',
|
||||
'#article-content',
|
||||
'#content',
|
||||
'.content',
|
||||
'.post',
|
||||
'.article',
|
||||
'.story-body',
|
||||
'#cnblogs_post_body',
|
||||
'.htmledit_views',
|
||||
'#article_content',
|
||||
'.blog-content-box'
|
||||
];
|
||||
|
||||
for (const selector of contentSelectors) {
|
||||
const el = document.querySelector(selector);
|
||||
if (el) {
|
||||
const text = cleanText(el.innerText);
|
||||
if (text.length > 50) {
|
||||
return text;
|
||||
return { text, html: el.outerHTML, element: el };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,16 +110,66 @@
|
||||
.map(p => p.textContent.trim())
|
||||
.filter(t => t.length > 20);
|
||||
if (texts.length > 0) {
|
||||
return cleanText(texts.join('\n\n'));
|
||||
return {
|
||||
text: cleanText(texts.join('\n\n')),
|
||||
html: `<main>${Array.from(paragraphs).map(p => p.outerHTML).join('')}</main>`,
|
||||
element: document.body
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Final fallback
|
||||
return cleanText(document.body.innerText);
|
||||
return {
|
||||
text: cleanText(document.body?.innerText || ''),
|
||||
html: document.body?.innerHTML || '',
|
||||
element: document.body
|
||||
};
|
||||
}
|
||||
|
||||
function detectPageType() {
|
||||
const route = `${window.location.pathname}${window.location.search}`.toLowerCase();
|
||||
if (/\/trending\/|\/topic(?:\/|$)|topic_innerflow/.test(route)
|
||||
|| document.querySelector('.amos-land-page, [data-page-type="topic"]')) {
|
||||
return 'topic';
|
||||
}
|
||||
if (/\/(?:search|tag|category|hot|feed)(?:\/|$)/.test(window.location.pathname.toLowerCase())
|
||||
|| document.querySelector('[data-page-type="listing"]')) {
|
||||
return 'listing';
|
||||
}
|
||||
return 'article';
|
||||
}
|
||||
|
||||
function detectAccessState(extractedBody) {
|
||||
const visible = element => Boolean(element && (element.offsetWidth || element.offsetHeight || element.getClientRects().length));
|
||||
const pageText = cleanText(document.body?.innerText || '').slice(0, 12000);
|
||||
const lowerText = pageText.toLowerCase();
|
||||
const captchaElement = Array.from(document.querySelectorAll(
|
||||
'[class*="captcha"], [id*="captcha"], [class*="verify"], [id*="verify"], iframe[src*="captcha"]'
|
||||
)).find(visible);
|
||||
if (captchaElement || /(验证码|安全验证|人机验证|滑块验证|verify you are human|complete the security check|captcha)/i.test(pageText)) {
|
||||
return { status: 'captcha_required', message: '页面需要完成验证码或安全验证', requiresUserAction: true };
|
||||
}
|
||||
|
||||
const passwordInput = Array.from(document.querySelectorAll('input[type="password"]')).find(visible);
|
||||
const loginRoute = /\/(?:login|signin|passport)(?:\/|$)/i.test(window.location.pathname);
|
||||
if (passwordInput || (loginRoute && /(登录|登陆|sign in|log in)/i.test(pageText))) {
|
||||
return { status: 'login_required', message: '页面需要登录后才能采集', requiresUserAction: true };
|
||||
}
|
||||
|
||||
if (extractedBody.length < 120 && (
|
||||
lowerText.includes('access denied')
|
||||
|| lowerText.includes('forbidden')
|
||||
|| lowerText.includes('not available in your region')
|
||||
|| /(所在地区|当前地区|地区限制|需要.*vpn|网络环境受限)/i.test(pageText)
|
||||
)) {
|
||||
return { status: 'access_restricted', message: '页面存在地区或网络访问限制', requiresUserAction: true };
|
||||
}
|
||||
|
||||
return { status: 'ok', message: '', requiresUserAction: false };
|
||||
}
|
||||
|
||||
// ===== Image Extraction =====
|
||||
function extractImages() {
|
||||
function extractImages(mainElement) {
|
||||
const images = new Set();
|
||||
|
||||
// 1. Open Graph image
|
||||
@@ -121,18 +184,17 @@
|
||||
// Skip favicons, they're not useful as content images
|
||||
|
||||
// 4. Content area images (from article/main/content areas)
|
||||
const contentSelectors = ['article', 'main', '.content', '.post-content', '#content'];
|
||||
for (const selector of contentSelectors) {
|
||||
const container = document.querySelector(selector);
|
||||
if (container) {
|
||||
container.querySelectorAll('img').forEach(img => {
|
||||
const src = img.src || img.dataset.src || img.dataset.original;
|
||||
if (src && !isSmallImage(img) && !isIconOrAvatar(src)) {
|
||||
images.add(resolveUrl(src));
|
||||
}
|
||||
});
|
||||
if (images.size > 0) break;
|
||||
}
|
||||
if (mainElement) {
|
||||
mainElement.querySelectorAll('img').forEach(img => {
|
||||
const src = img.currentSrc
|
||||
|| img.src
|
||||
|| img.dataset.src
|
||||
|| img.dataset.original
|
||||
|| img.dataset.lazySrc;
|
||||
if (src && !isSmallImage(img) && !isIconOrAvatar(src)) {
|
||||
images.add(resolveUrl(src));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 5. If no content images found, scan all images
|
||||
@@ -148,6 +210,15 @@
|
||||
return Array.from(images).slice(0, 10);
|
||||
}
|
||||
|
||||
function extractLinks(mainElement) {
|
||||
const links = new Set();
|
||||
(mainElement || document.body)?.querySelectorAll('a[href]').forEach(anchor => {
|
||||
const href = resolveUrl(anchor.getAttribute('href'));
|
||||
if (/^https?:\/\//i.test(href)) links.add(href);
|
||||
});
|
||||
return Array.from(links).slice(0, 100);
|
||||
}
|
||||
|
||||
function isSmallImage(img) {
|
||||
return (img.naturalWidth > 0 && img.naturalWidth < 100) ||
|
||||
(img.naturalHeight > 0 && img.naturalHeight < 100);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
'getVersion',
|
||||
'listPlatforms',
|
||||
'checkPlatforms',
|
||||
'captureUrl',
|
||||
'startBatch',
|
||||
'syncToPlatform',
|
||||
]);
|
||||
@@ -33,6 +34,11 @@
|
||||
const response = await sendRuntimeMessage({ type: 'CHECK_PLATFORM_STATUS', platforms: selected });
|
||||
return response?.status || {};
|
||||
}
|
||||
case 'captureUrl': {
|
||||
if (typeof payload?.url !== 'string' || !payload.url.trim())
|
||||
throw new Error('缺少要采集的页面地址');
|
||||
return chrome.runtime.sendMessage({ type: 'CAPTURE_URL', url: payload.url });
|
||||
}
|
||||
case 'startBatch':
|
||||
return sendRuntimeMessage({ type: 'START_SYNC_BATCH' });
|
||||
case 'syncToPlatform': {
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
getVersion: () => request('getVersion'),
|
||||
listPlatforms: () => request('listPlatforms'),
|
||||
checkPlatforms: platformIds => request('checkPlatforms', { platformIds }),
|
||||
captureUrl: url => request('captureUrl', { url }),
|
||||
startBatch: () => request('startBatch'),
|
||||
syncToPlatform: (platformId, content) => request('syncToPlatform', { platformId, content }),
|
||||
},
|
||||
|
||||
@@ -868,7 +868,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.plainText || content.markdown || content.body || ''
|
||||
console.log('[COSE] 小红书 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -1583,7 +1583,7 @@ async function syncToPlatform(platformId, content) {
|
||||
// 微信公众号:直接注入 HTML 到编辑器
|
||||
if (platformId === 'wechat') {
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.wechatHtml || content.html || content.body || ''
|
||||
console.log('[COSE] 微信 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 等待额外时间确保编辑器完全加载
|
||||
@@ -1753,7 +1753,7 @@ async function syncToPlatform(platformId, content) {
|
||||
// 抖音:使用剪贴板 HTML 粘贴到编辑器(类似微信公众号)
|
||||
if (platformId === 'douyin') {
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.plainText || content.markdown || content.body || ''
|
||||
console.log('[COSE] 抖音 HTML 内容长度:', htmlContent?.length || 0)
|
||||
console.log('[COSE] 开始注入抖音内容...')
|
||||
|
||||
@@ -1883,7 +1883,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] 搜狐号 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -1942,7 +1942,7 @@ async function syncToPlatform(platformId, content) {
|
||||
// B站专栏:使用 UEditor execCommand 插入 HTML
|
||||
if (platformId === 'bilibili') {
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] B站专栏 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 等待 UEditor 就绪
|
||||
@@ -2052,7 +2052,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.plainText || content.markdown || content.body || ''
|
||||
console.log('[COSE] 微博头条 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -2717,7 +2717,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] 百家号 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -2826,7 +2826,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] 少数派 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -2896,7 +2896,7 @@ async function syncToPlatform(platformId, content) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] 支付宝开放平台 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 填充标题和内容
|
||||
@@ -3196,7 +3196,7 @@ async function syncToPlatform(platformId, content) {
|
||||
// 豆瓣:向首页分享框注入内容
|
||||
if (platformId === 'douban') {
|
||||
// 使用纯文本内容(豆瓣分享框不支持富文本)
|
||||
const textContent = content.markdown || content.body || ''
|
||||
const textContent = content.plainText || content.markdown || content.body || ''
|
||||
console.log('[COSE] 豆瓣文本内容长度:', textContent?.length || 0)
|
||||
|
||||
// 等待页面加载
|
||||
@@ -3389,7 +3389,7 @@ async function syncToPlatform(platformId, content) {
|
||||
|
||||
// 在目标页面执行的填充函数
|
||||
function fillContentOnPage(content, platformId) {
|
||||
const { title, body, markdown, wechatHtml } = content
|
||||
const { title, body, html, markdown, plainText } = content
|
||||
|
||||
// 等待元素出现的工具函数
|
||||
function waitFor(selector, timeout = 10000) {
|
||||
@@ -3422,7 +3422,7 @@ function fillContentOnPage(content, platformId) {
|
||||
// 根据平台填充内容
|
||||
async function fill() {
|
||||
const host = window.location.hostname
|
||||
const contentToFill = markdown || body || ''
|
||||
const contentToFill = markdown || plainText || body || ''
|
||||
|
||||
// 知乎专栏 - 由 syncToPlatform 单独处理(使用导入文档功能)
|
||||
if (host.includes('zhihu.com')) {
|
||||
@@ -3839,7 +3839,7 @@ function fillContentOnPage(content, platformId) {
|
||||
* Medium 使用 contenteditable 编辑器,通过 paste 事件注入 HTML 内容
|
||||
* 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
*/
|
||||
const htmlContent = wechatHtml || body || ''
|
||||
const htmlContent = html || body || ''
|
||||
const contentEl = document.querySelector('p.graf--p')
|
||||
|
||||
if (contentEl && htmlContent) {
|
||||
|
||||
@@ -19,8 +19,8 @@ const MediumPlatform = {
|
||||
* 3. 通过 paste 事件填充 HTML 内容到编辑器
|
||||
*/
|
||||
async function fillMediumContent(content, waitFor, setInputValue) {
|
||||
const { title, body, wechatHtml } = content
|
||||
const htmlContent = wechatHtml || body || ''
|
||||
const { title, body, html } = content
|
||||
const htmlContent = html || body || ''
|
||||
|
||||
console.log('[COSE] Medium 开始同步...')
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ async function syncWangyihaoContent(tab, content, helpers) {
|
||||
await injectUtils(chrome, tab.id)
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.html || content.body || ''
|
||||
console.log('[COSE] 网易号 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 在页面中执行:填充标题和粘贴 HTML 内容
|
||||
|
||||
@@ -331,7 +331,7 @@ async function syncWechatContent(tab, content, helpers) {
|
||||
await waitForTab(tab.id)
|
||||
|
||||
// 使用剪贴板 HTML(带完整样式)或降级到 body
|
||||
const htmlContent = content.wechatHtml || content.body
|
||||
const htmlContent = content.wechatHtml || content.html || content.body || ''
|
||||
console.log('[COSE] 微信 HTML 内容长度:', htmlContent?.length || 0)
|
||||
|
||||
// 步骤4:使用 MutationObserver 监听编辑器出现
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "AiToEarn - 内容营销助手",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"description": "AiToEarn 自维护内容扩展:网页采集、账号检测与多平台文章分发",
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
|
||||
Reference in New Issue
Block a user