multi-publisher 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -22
- package/dist/adapters/csdn.d.ts +15 -0
- package/dist/adapters/csdn.js +136 -1
- package/dist/adapters/interface.d.ts +10 -0
- package/dist/adapters/qq.d.ts +19 -0
- package/dist/adapters/qq.js +185 -0
- package/dist/adapters/registry.js +2 -0
- package/dist/adapters/toutiao.d.ts +4 -0
- package/dist/adapters/toutiao.js +205 -40
- package/dist/adapters/wechat-publisher.d.ts +6 -1
- package/dist/adapters/wechat-publisher.js +58 -17
- package/dist/adapters/weixin.d.ts +5 -0
- package/dist/adapters/weixin.js +41 -5
- package/dist/cli/capture.d.ts +6 -0
- package/dist/cli/capture.js +49 -0
- package/dist/cli/index.js +8 -0
- package/dist/cli/login.js +3 -0
- package/dist/cli/platforms.js +2 -1
- package/dist/cli/publish-all.js +1 -1
- package/dist/cli/publish.d.ts +1 -0
- package/dist/cli/publish.js +29 -5
- package/dist/config.d.ts +8 -0
- package/dist/config.js +11 -0
- package/dist/core/parser.js +9 -1
- package/dist/core/renderer.d.ts +9 -1
- package/dist/core/renderer.js +86 -11
- package/dist/core/theme.d.ts +1 -1
- package/dist/core/theme.js +91 -336
- package/dist/runtime/browser-runtime.js +31 -2
- package/dist/tools/browser-upload.d.ts +13 -0
- package/dist/tools/browser-upload.js +349 -0
- package/dist/tools/capture.d.ts +26 -0
- package/dist/tools/capture.js +348 -0
- package/dist/tools/cover-fetcher.d.ts +10 -0
- package/dist/tools/cover-fetcher.js +100 -0
- package/dist/tools/imgbb-uploader.d.ts +18 -0
- package/dist/tools/imgbb-uploader.js +89 -0
- package/dist/tools/toutiao-upload.d.ts +10 -0
- package/dist/tools/toutiao-upload.js +166 -0
- package/package.json +1 -1
- package/themes/previews/cyberpunk.png +0 -0
- package/themes/previews/nord.png +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 头条号封面图片浏览器上传
|
|
3
|
+
*/
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { ConfigStore } from '../config.js';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
/**
|
|
8
|
+
* 通过浏览器自动化上传头条号封面
|
|
9
|
+
* 流程:打开发布页 -> 填写内容 -> 点击预览并发布 -> 在预览弹窗中上传封面 -> 确认
|
|
10
|
+
*/
|
|
11
|
+
export async function uploadCoverViaBrowser(imagePath) {
|
|
12
|
+
const browser = await chromium.launch({
|
|
13
|
+
headless: false,
|
|
14
|
+
args: [
|
|
15
|
+
'--disable-blink-features=AutomationControlled',
|
|
16
|
+
'--disable-devtools-shm-usage',
|
|
17
|
+
'--no-sandbox',
|
|
18
|
+
]
|
|
19
|
+
});
|
|
20
|
+
try {
|
|
21
|
+
const context = await browser.newContext({
|
|
22
|
+
viewport: { width: 1280, height: 900 },
|
|
23
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
24
|
+
});
|
|
25
|
+
const page = await context.newPage();
|
|
26
|
+
// CDP 隐藏自动化特征
|
|
27
|
+
const cdp = await context.newCDPSession(page);
|
|
28
|
+
await cdp.send('Page.addScriptToEvaluateOnNewDocument', {
|
|
29
|
+
source: `
|
|
30
|
+
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
|
31
|
+
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });
|
|
32
|
+
Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN', 'zh', 'en'] });
|
|
33
|
+
window.chrome = { runtime: {}, loadTimes: () => {}, csi: () => {} };
|
|
34
|
+
`
|
|
35
|
+
});
|
|
36
|
+
// 加载 cookies
|
|
37
|
+
const cookies = await ConfigStore.getToutiaoCookies();
|
|
38
|
+
if (!cookies || Object.keys(cookies).length === 0) {
|
|
39
|
+
return { success: false, error: '未配置头条号 Cookie' };
|
|
40
|
+
}
|
|
41
|
+
const toutiaoCookies = Object.entries(cookies).map(([name, value]) => ({
|
|
42
|
+
name,
|
|
43
|
+
value,
|
|
44
|
+
domain: '.toutiao.com',
|
|
45
|
+
path: '/',
|
|
46
|
+
}));
|
|
47
|
+
await context.addCookies(toutiaoCookies);
|
|
48
|
+
console.log('[ToutiaoUpload] 打开发布页...');
|
|
49
|
+
await page.goto('https://mp.toutiao.com/profile_v4/graphic/publish', {
|
|
50
|
+
waitUntil: 'networkidle',
|
|
51
|
+
timeout: 60000
|
|
52
|
+
});
|
|
53
|
+
await page.waitForTimeout(2000);
|
|
54
|
+
// 关闭可能存在的遮罩层
|
|
55
|
+
try {
|
|
56
|
+
const mask = page.locator('.byte-drawer-mask').first();
|
|
57
|
+
if (await mask.isVisible({ timeout: 1000 })) {
|
|
58
|
+
await mask.click({ force: true });
|
|
59
|
+
await page.waitForTimeout(500);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
// 截图
|
|
64
|
+
await page.screenshot({ path: `temp/toutiao-upload-start-${Date.now()}.png` });
|
|
65
|
+
// 填写标题和内容(让用户之前已经填好了,这里只做演示)
|
|
66
|
+
const titleInput = page.locator('textarea').first();
|
|
67
|
+
if (await titleInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
68
|
+
const currentTitle = await titleInput.inputValue().catch(() => '');
|
|
69
|
+
if (!currentTitle) {
|
|
70
|
+
await titleInput.fill('临时标题-封面测试');
|
|
71
|
+
console.log('[ToutiaoUpload] 填写了临时标题');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// 填写内容(如果为空)
|
|
75
|
+
const contentEl = page.locator('div[contenteditable="true"]').first();
|
|
76
|
+
if (await contentEl.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
77
|
+
const currentContent = await contentEl.textContent().catch(() => '');
|
|
78
|
+
if (!currentContent || currentContent.trim() === '') {
|
|
79
|
+
await contentEl.click();
|
|
80
|
+
await page.keyboard.press('Control+a');
|
|
81
|
+
await page.keyboard.type('临时内容-封面测试');
|
|
82
|
+
console.log('[ToutiaoUpload] 填写了临时内容');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 点击"预览并发布"按钮
|
|
86
|
+
console.log('[ToutiaoUpload] 点击预览并发布按钮...');
|
|
87
|
+
const publishBtn = page.locator('button:has-text("预览并发布")');
|
|
88
|
+
if (await publishBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
89
|
+
await publishBtn.click({ force: true });
|
|
90
|
+
console.log('[ToutiaoUpload] 已点击预览并发布');
|
|
91
|
+
await page.waitForTimeout(3000);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return { success: false, error: '未找到预览并发布按钮' };
|
|
95
|
+
}
|
|
96
|
+
// 在预览弹窗中选择"单图"选项
|
|
97
|
+
console.log('[ToutiaoUpload] 选择单图选项...');
|
|
98
|
+
const singleImageOption = page.locator('text=单图').first();
|
|
99
|
+
if (await singleImageOption.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
100
|
+
await singleImageOption.click();
|
|
101
|
+
console.log('[ToutiaoUpload] 点击了单图');
|
|
102
|
+
await page.waitForTimeout(500);
|
|
103
|
+
}
|
|
104
|
+
// 截图
|
|
105
|
+
await page.screenshot({ path: `temp/toutiao-upload-select-cover-${Date.now()}.png` });
|
|
106
|
+
// 设置 filechooser 监听
|
|
107
|
+
const absolutePath = path.resolve(imagePath);
|
|
108
|
+
console.log(`[ToutiaoUpload] 准备上传: ${absolutePath}`);
|
|
109
|
+
page.on('filechooser', async (fileChooser) => {
|
|
110
|
+
console.log('[ToutiaoUpload] 收到 filechooser,设置文件');
|
|
111
|
+
await fileChooser.setFiles(absolutePath);
|
|
112
|
+
});
|
|
113
|
+
// 点击封面添加区域触发 filechooser
|
|
114
|
+
console.log('[ToutiaoUpload] 点击封面添加区域...');
|
|
115
|
+
const coverAdd = page.locator('.article-cover-add');
|
|
116
|
+
if (await coverAdd.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
117
|
+
await coverAdd.click({ force: true });
|
|
118
|
+
console.log('[ToutiaoUpload] 点击了 article-cover-add');
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return { success: false, error: '未找到封面添加区域' };
|
|
122
|
+
}
|
|
123
|
+
// 等待文件选择
|
|
124
|
+
await page.waitForTimeout(2000);
|
|
125
|
+
// 点击"本地上传"按钮
|
|
126
|
+
console.log('[ToutiaoUpload] 点击本地上传按钮...');
|
|
127
|
+
const localUploadBtn = page.locator('text=本地上传');
|
|
128
|
+
if (await localUploadBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
129
|
+
await localUploadBtn.click();
|
|
130
|
+
console.log('[ToutiaoUpload] 点击了本地上传');
|
|
131
|
+
await page.waitForTimeout(2000);
|
|
132
|
+
}
|
|
133
|
+
// 截图看预览
|
|
134
|
+
await page.screenshot({ path: `temp/toutiao-upload-preview-${Date.now()}.png` });
|
|
135
|
+
// 点击"确定"按钮
|
|
136
|
+
console.log('[ToutiaoUpload] 点击确定按钮...');
|
|
137
|
+
const confirmBtn = page.locator('button:has-text("确定")').filter({ visible: true });
|
|
138
|
+
try {
|
|
139
|
+
if (await confirmBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
140
|
+
const disabled = await confirmBtn.first().isDisabled().catch(() => true);
|
|
141
|
+
if (!disabled) {
|
|
142
|
+
await confirmBtn.first().click();
|
|
143
|
+
console.log('[ToutiaoUpload] 点击了确定按钮');
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log('[ToutiaoUpload] 确定按钮被禁用');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
console.log('[ToutiaoUpload] 未找到确定按钮');
|
|
152
|
+
}
|
|
153
|
+
// 等待保存
|
|
154
|
+
await page.waitForTimeout(3000);
|
|
155
|
+
await page.screenshot({ path: `temp/toutiao-upload-finish-${Date.now()}.png` });
|
|
156
|
+
console.log('[ToutiaoUpload] 封面上传流程完成');
|
|
157
|
+
return { success: true, coverUrl: 'uploaded' };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error('[ToutiaoUpload] 上传失败:', err);
|
|
161
|
+
return { success: false, error: err.message };
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
await browser.close();
|
|
165
|
+
}
|
|
166
|
+
}
|
package/package.json
CHANGED
|
Binary file
|
package/themes/previews/nord.png
DELETED
|
Binary file
|