Skip to content

Commit dbe497d

Browse files
authored
131 refactor article (#133)
* feat(message-handler): enhance message handling for publish and account info - Add new actions for handling publish requests, account info retrieval, and opening options page - Implement popup creation for publishing and refreshing accounts - Maintain current sync data for publish requests * feat(publish): add publish component for handling content publishing - Implement the Publish component to manage article, dynamic, podcast, and video processing - Add functionality for image and file handling with blob URLs - Integrate platform status updates and retry mechanism for publishing - Enhance user notifications during the publishing process * feat(sync): update SyncData interfaces and improve article processing - Make injectUrl and extraConfig optional in SyncDataPlatform interface - Update FileData interface to make type and size optional - Refactor ArticleData to include htmlContent and make images optional - Modify ArticleBaijiahao to process htmlContent instead of content for image handling * refactor(sync): update article processing to use htmlContent - Remove unused content state in ArticleTab component - Update SyncData interface to include origin field for temporary storage - Refactor article processing functions to handle htmlContent instead of content - Adjust image handling in various article sync functions to use images array * refactor(publish): improve tab management and error handling - Replace platform status tracking with error handling for image and file processing - Introduce functions for reloading and closing tabs, enhancing user interaction - Update state management for published tabs and integrate error display in the UI - Refactor publish component to streamline data handling and improve user notifications * refactor(message-handler): improve tab creation and response handling - Add focused option to popup creation based on request - Refactor tab creation and script injection to use async/await for better error handling - Enhance response structure for tab information after processing * feat(refresh-accounts): update auto-close feature and improve state handling - Change default state of autoClose to true for better user experience - Refactor handleAutoCloseChange to use event parameter for clarity - Update useEffect to handle undefined value for autoClose state - Replace Button with Switch component for a more intuitive UI * feat(localization): add new publishing messages and improve error handling - Add localization messages for publishing content and related processes in English and Chinese - Update error handling messages for content processing, image handling, and tab management - Enhance user notifications during the publishing workflow * feat(weixin): enhance article processing and image handling - Add new fields to CropConfig and ShareImageInfo interfaces for better image management - Update readInfo function to extract additional data (ticket and userName) - Refactor getImageInfo to simplify image fetching and size retrieval - Improve uploadImage function to handle image uploads more efficiently - Introduce processContent function to manage image uploads within article content - Update createArticle to support share image information and error handling
1 parent 7c4688a commit dbe497d

File tree

17 files changed

+885
-233
lines changed

17 files changed

+885
-233
lines changed

locales/en/messages.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,5 +953,50 @@
953953
"refreshAccountsAutoClose": {
954954
"message": "Auto Close",
955955
"description": "Auto close switch text"
956+
},
957+
"publishing": {
958+
"message": "Publishing Content"
959+
},
960+
"publishingInProgress": {
961+
"message": "Publishing in progress..."
962+
},
963+
"processingContent": {
964+
"message": "Processing content and images..."
965+
},
966+
"processingComplete": {
967+
"message": "Processing complete, ready to publish..."
968+
},
969+
"publishComplete": {
970+
"message": "Publishing complete"
971+
},
972+
"errorMessages": {
973+
"message": "Error Messages"
974+
},
975+
"finishPublishing": {
976+
"message": "Finish Publishing"
977+
},
978+
"finishAndCloseTabs": {
979+
"message": "Finish and Close All Tabs"
980+
},
981+
"errorGetSyncData": {
982+
"message": "Failed to get sync data"
983+
},
984+
"errorProcessContent": {
985+
"message": "Error processing content, please try again"
986+
},
987+
"errorProcessImage": {
988+
"message": "Failed to process image: $1"
989+
},
990+
"errorProcessFile": {
991+
"message": "Failed to process file: $1"
992+
},
993+
"errorReloadTab": {
994+
"message": "Failed to reload tab: $1"
995+
},
996+
"errorCloseTab": {
997+
"message": "Failed to close tab: $1"
998+
},
999+
"errorCloseAllTabs": {
1000+
"message": "Failed to close all tabs: $1"
9561001
}
9571002
}

locales/zh_CN/messages.json

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
"description": "动态标题输入框占位符"
8585
},
8686
"optionsEnterDynamicContent": {
87-
"message": "正文",
87+
"message": "请输入内容",
8888
"description": "动态内容输入框占位符"
8989
},
9090
"optionsSyncDynamic": {
@@ -300,11 +300,11 @@
300300
"description": "标签管理器中未命名分组的标题"
301301
},
302302
"sidepanelReloadTab": {
303-
"message": "重新加载标签",
303+
"message": "重新加载标签页",
304304
"description": "重新加载标签按钮的 aria 标签"
305305
},
306306
"sidepanelCloseTab": {
307-
"message": "关闭标签",
307+
"message": "关闭标签页",
308308
"description": "关闭标签按钮的 aria 标签"
309309
},
310310
"optionsAtLeastOneImage": {
@@ -733,7 +733,7 @@
733733
"message": "控制台"
734734
},
735735
"optionsSelectPublishPlatforms": {
736-
"message": "请至少选择一个平台"
736+
"message": "请选择发布平台"
737737
},
738738
"extraConfigOkjikeConfigureTopic": {
739739
"message": "配置即刻圈子"
@@ -927,5 +927,50 @@
927927
"refreshAccountsAutoClose": {
928928
"message": "下次自动关闭",
929929
"description": "自动关闭设置的开关文本"
930+
},
931+
"publishing": {
932+
"message": "正在发布内容"
933+
},
934+
"publishingInProgress": {
935+
"message": "正在发布..."
936+
},
937+
"processingContent": {
938+
"message": "正在处理文章内容和图片..."
939+
},
940+
"processingComplete": {
941+
"message": "处理完成,准备发布..."
942+
},
943+
"publishComplete": {
944+
"message": "发布完成"
945+
},
946+
"errorMessages": {
947+
"message": "错误信息"
948+
},
949+
"finishPublishing": {
950+
"message": "完成发布"
951+
},
952+
"finishAndCloseTabs": {
953+
"message": "完成并关闭所有标签页"
954+
},
955+
"errorGetSyncData": {
956+
"message": "获取同步数据失败"
957+
},
958+
"errorProcessContent": {
959+
"message": "处理内容时出错,请重试"
960+
},
961+
"errorProcessImage": {
962+
"message": "处理图片失败: $1"
963+
},
964+
"errorProcessFile": {
965+
"message": "处理文件失败: $1"
966+
},
967+
"errorReloadTab": {
968+
"message": "重新加载标签页失败: $1"
969+
},
970+
"errorCloseTab": {
971+
"message": "关闭标签页失败: $1"
972+
},
973+
"errorCloseAllTabs": {
974+
"message": "关闭所有标签页失败: $1"
930975
}
931976
}

src/background/index.ts

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -61,38 +61,23 @@ chrome.tabs.onRemoved.addListener((tabId) => {
6161
// Listen Message || 监听消息 || END
6262

6363
// Message Handler || 消息处理器 || START
64+
let currentSyncData: SyncData | null = null;
65+
let currentPublishPopup: chrome.windows.Window | null = null;
6466
const defaultMessageHandler = (request, sender, sendResponse) => {
6567
if (request.action === 'MUTLIPOST_EXTENSION_CHECK_SERVICE_STATUS') {
6668
sendResponse({ extensionId: chrome.runtime.id });
6769
}
6870
if (request.action === 'MUTLIPOST_EXTENSION_PUBLISH') {
6971
const data = request.data as SyncData;
70-
if (Array.isArray(data.platforms) && data.platforms.length > 0) {
71-
createTabsForPlatforms(data)
72-
.then(async (tabs) => {
73-
injectScriptsToTabs(tabs, data);
74-
75-
addTabsManagerMessages({
76-
syncData: data,
77-
tabs: tabs.map((t: { tab: chrome.tabs.Tab; platformInfo: SyncDataPlatform }) => ({
78-
tab: t.tab,
79-
platformInfo: t.platformInfo,
80-
})),
81-
});
82-
83-
for (const t of tabs) {
84-
if (t.tab.id) {
85-
await chrome.tabs.update(t.tab.id, { active: true });
86-
await new Promise((resolve) => setTimeout(resolve, 2000));
87-
}
88-
}
89-
})
90-
.catch((error) => {
91-
console.error('创建标签页或分组时出错:', error);
92-
});
93-
} else {
94-
console.error('没有指定有效的平台');
95-
}
72+
currentSyncData = data;
73+
(async () => {
74+
currentPublishPopup = await chrome.windows.create({
75+
url: chrome.runtime.getURL(`tabs/publish.html`),
76+
type: 'popup',
77+
width: 800,
78+
height: 600,
79+
});
80+
})();
9681
}
9782
if (request.action === 'MUTLIPOST_EXTENSION_PLATFORMS') {
9883
getPlatformInfos().then((platforms) => {
@@ -114,8 +99,50 @@ const defaultMessageHandler = (request, sender, sendResponse) => {
11499
type: 'popup',
115100
width: 800,
116101
height: 600,
102+
focused: request.isFocused || true,
117103
});
118104
}
105+
if (request.action === 'MUTLIPOST_EXTENSION_PUBLISH_REQUEST_SYNC_DATA') {
106+
sendResponse({ syncData: currentSyncData });
107+
}
108+
if (request.action === 'MUTLIPOST_EXTENSION_PUBLISH_NOW') {
109+
const data = request.data as SyncData;
110+
if (Array.isArray(data.platforms) && data.platforms.length > 0) {
111+
(async () => {
112+
try {
113+
const tabs = await createTabsForPlatforms(data);
114+
await injectScriptsToTabs(tabs, data);
115+
116+
addTabsManagerMessages({
117+
syncData: data,
118+
tabs: tabs.map((t: { tab: chrome.tabs.Tab; platformInfo: SyncDataPlatform }) => ({
119+
tab: t.tab,
120+
platformInfo: t.platformInfo,
121+
})),
122+
});
123+
124+
for (const t of tabs) {
125+
if (t.tab.id) {
126+
await chrome.tabs.update(t.tab.id, { active: true });
127+
await new Promise((resolve) => setTimeout(resolve, 2000));
128+
}
129+
}
130+
if (currentPublishPopup) {
131+
await chrome.windows.update(currentPublishPopup.id, { focused: true });
132+
}
133+
134+
sendResponse({
135+
tabs: tabs.map((t: { tab: chrome.tabs.Tab; platformInfo: SyncDataPlatform }) => ({
136+
tab: t.tab,
137+
platformInfo: t.platformInfo,
138+
})),
139+
});
140+
} catch (error) {
141+
console.error('创建标签页或分组时出错:', error);
142+
}
143+
})();
144+
}
145+
}
119146
};
120147
starter(1000 * 30);
121148
// Message Handler || 消息处理器 || END

src/components/Sync/ArticleTab.tsx

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ interface ArticleTabProps {
3636
const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) => {
3737
const [title, setTitle] = useState<string>('');
3838
const [digest, setDigest] = useState<string>('');
39-
const [content, setContent] = useState<string>('');
4039
const [selectedPlatforms, setSelectedPlatforms] = useState<string[]>([]);
4140
const [url, setUrl] = useState<string>('');
4241
const [importedContent, setImportedContent] = useState<{
@@ -49,8 +48,6 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
4948
} | null>(null);
5049
const [coverImage, setCoverImage] = useState<FileData | null>(null);
5150
const [images, setImages] = useState<FileData[]>([]);
52-
const [videos, setVideos] = useState<FileData[]>([]);
53-
const [fileDatas, setFileDatas] = useState<FileData[]>([]);
5451
const coverInputRef = useRef<HTMLInputElement>(null);
5552
const [isProcessing, setIsProcessing] = useState(false);
5653
const [processStatus, setProcessStatus] = useState('');
@@ -140,7 +137,7 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
140137
return;
141138
}
142139
// 将 HTML 转换为 Markdown
143-
const markdownContent = turndownService.turndown(content || digest || '');
140+
// const markdownContent = turndownService.turndown(content || digest || '');
144141
const markdownOriginContent = importedContent?.originContent
145142
? turndownService.turndown(importedContent.originContent)
146143
: '';
@@ -153,15 +150,11 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
153150
})),
154151
data: {
155152
title,
156-
content: content || digest || '',
157153
digest: digest || '',
158154
cover: coverImage || null,
159155
images: images || [],
160-
videos: videos || [],
161-
fileDatas: [...fileDatas, ...images, ...videos],
162-
originContent: importedContent?.originContent || '',
163-
markdownContent,
164-
markdownOriginContent,
156+
markdownContent: markdownOriginContent,
157+
htmlContent: importedContent?.originContent || digest || '',
165158
},
166159
isAutoPublish: false,
167160
};
@@ -205,7 +198,6 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
205198
type: blob.type,
206199
size: blob.size,
207200
url: URL.createObjectURL(blob),
208-
originUrl: src,
209201
};
210202
imageFileDatas.push(fileData);
211203

@@ -236,7 +228,6 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
236228
type: blob.type,
237229
size: blob.size,
238230
url: URL.createObjectURL(blob),
239-
originUrl: src,
240231
};
241232
videoFileDatas.push(fileData);
242233

@@ -261,7 +252,6 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
261252
type: blob.type,
262253
size: blob.size,
263254
url: URL.createObjectURL(blob),
264-
originUrl: href,
265255
};
266256
fileDatas.push(fileData);
267257

@@ -294,9 +284,7 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
294284
const res = await funcScraper(url);
295285
console.log('res', res);
296286
if (res && res.title && res.content) {
297-
const { imageFileDatas, videoFileDatas, fileDatas, processedContent } = await processImportedContent(
298-
res.content,
299-
);
287+
const { imageFileDatas, processedContent } = await processImportedContent(res.content);
300288

301289
// 如果导入的内容有封面图,且当前没有设置封面,则设置为封面
302290
if (res.cover && !coverImage) {
@@ -308,7 +296,6 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
308296
type: blob.type,
309297
size: blob.size,
310298
url: URL.createObjectURL(blob),
311-
originUrl: res.cover,
312299
};
313300
setCoverImage(coverFileData);
314301
} catch (error) {
@@ -326,11 +313,8 @@ const ArticleTab: React.FC<ArticleTabProps> = ({ funcPublish, funcScraper }) =>
326313
});
327314

328315
setTitle(res.title);
329-
setContent(processedContent);
330316
setDigest(res.digest || '');
331317
setImages(imageFileDatas);
332-
setVideos(videoFileDatas);
333-
setFileDatas(fileDatas);
334318
}
335319
} catch (error) {
336320
console.error(chrome.i18n.getMessage('errorImportingContent') || '导入内容时出错:', error);

src/sync/article/baijiahao.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ interface CoverResult {
88
}
99

1010
export async function ArticleBaijiahao(data: SyncData) {
11-
console.log('ArticleBaijiahao', data);
12-
1311
const articleData = data.data as ArticleData;
14-
1512
// 上传单个图片
1613
async function uploadSingleImage(fileInfo: FileData): Promise<string | null> {
1714
try {
@@ -96,9 +93,9 @@ export async function ArticleBaijiahao(data: SyncData) {
9693
}
9794

9895
// 处理文章内容中的图片
99-
async function processContent(content: string, fileDatas: FileData[]): Promise<string> {
96+
async function processContent(htmlContent: string, imageDatas: FileData[]): Promise<string> {
10097
const parser = new DOMParser();
101-
const doc = parser.parseFromString(content, 'text/html');
98+
const doc = parser.parseFromString(htmlContent, 'text/html');
10299
const images = Array.from(doc.getElementsByTagName('img'));
103100

104101
console.log(`处理文章图片,共 ${images.length} 张`);
@@ -107,7 +104,7 @@ export async function ArticleBaijiahao(data: SyncData) {
107104
const src = img.getAttribute('src');
108105
if (!src) return;
109106

110-
const fileInfo = fileDatas.find((f) => f.url === src);
107+
const fileInfo = imageDatas.find((f) => f.url === src);
111108
if (!fileInfo) return;
112109

113110
const newUrl = await uploadSingleImage(fileInfo);
@@ -167,8 +164,8 @@ export async function ArticleBaijiahao(data: SyncData) {
167164
async function publishArticle(articleData: ArticleData): Promise<string | null> {
168165
console.log('开始发布文章:', articleData.title);
169166

170-
if (articleData.fileDatas) {
171-
articleData.content = await processContent(articleData.content, articleData.fileDatas);
167+
if (articleData.images) {
168+
articleData.htmlContent = await processContent(articleData.htmlContent, articleData.images);
172169
}
173170

174171
let coverResults: CoverResult[] | null = null;
@@ -183,12 +180,13 @@ export async function ArticleBaijiahao(data: SyncData) {
183180
const formData = new FormData();
184181
formData.append('type', 'news');
185182
formData.append('title', articleData.title?.slice(0, 30) || '');
186-
formData.append('content', articleData.content || '');
183+
formData.append('content', articleData.htmlContent || '');
187184
formData.append('vertical_cover', coverResults?.[1].src || '');
188185
formData.append('abstract', articleData.digest || '');
189186

190187
const contentLength =
191-
new DOMParser().parseFromString(articleData.content || '', 'text/html').documentElement.textContent?.length || 0;
188+
new DOMParser().parseFromString(articleData.htmlContent || '', 'text/html').documentElement.textContent?.length ||
189+
0;
192190

193191
formData.append('len', contentLength.toString());
194192
formData.append('activity_list[0][id]', 'ttv');

0 commit comments

Comments
 (0)