@wenyan-md/core 3.0.10 → 3.0.11
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/dist/core.js +46 -9
- package/dist/publish.js +16 -1
- package/dist/types/core/parser/frontMatterParser.d.ts +2 -0
- package/dist/types/publish.d.ts +9 -1
- package/dist/types/wechat.d.ts +24 -0
- package/dist/wechat.js +37 -1
- package/dist/wrapper.js +48 -3
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -202,7 +202,19 @@ async function handleFrontMatter(markdown) {
|
|
|
202
202
|
const { attributes, body } = fm(markdown);
|
|
203
203
|
const result = { content: body || "" };
|
|
204
204
|
let head = "";
|
|
205
|
-
const {
|
|
205
|
+
const {
|
|
206
|
+
title,
|
|
207
|
+
description,
|
|
208
|
+
cover,
|
|
209
|
+
author,
|
|
210
|
+
source_url,
|
|
211
|
+
pic_crop_235_1,
|
|
212
|
+
pic_crop_1_1,
|
|
213
|
+
need_open_comment,
|
|
214
|
+
only_fans_can_comment,
|
|
215
|
+
image_list,
|
|
216
|
+
type
|
|
217
|
+
} = attributes;
|
|
206
218
|
if (title) {
|
|
207
219
|
result.title = title;
|
|
208
220
|
}
|
|
@@ -219,6 +231,12 @@ async function handleFrontMatter(markdown) {
|
|
|
219
231
|
if (source_url) {
|
|
220
232
|
result.source_url = source_url;
|
|
221
233
|
}
|
|
234
|
+
if (pic_crop_235_1) {
|
|
235
|
+
result.pic_crop_235_1 = String(pic_crop_235_1);
|
|
236
|
+
}
|
|
237
|
+
if (pic_crop_1_1) {
|
|
238
|
+
result.pic_crop_1_1 = String(pic_crop_1_1);
|
|
239
|
+
}
|
|
222
240
|
if (need_open_comment !== void 0) {
|
|
223
241
|
result.need_open_comment = need_open_comment;
|
|
224
242
|
}
|
|
@@ -996,15 +1014,34 @@ function wechatPostRender(element) {
|
|
|
996
1014
|
}
|
|
997
1015
|
li.appendChild(section);
|
|
998
1016
|
});
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1017
|
+
const flattenNestedLists = () => {
|
|
1018
|
+
let nestedLists = element.querySelectorAll(
|
|
1019
|
+
"li > section > ul, li > section > ol"
|
|
1020
|
+
);
|
|
1021
|
+
while (nestedLists.length > 0) {
|
|
1022
|
+
Array.from(nestedLists).reverse().forEach((nestedList) => {
|
|
1023
|
+
const isOrdered = nestedList.tagName === "OL";
|
|
1024
|
+
const doc = element.ownerDocument;
|
|
1025
|
+
const items = Array.from(nestedList.children).filter(
|
|
1026
|
+
(child) => child.tagName === "LI"
|
|
1027
|
+
);
|
|
1028
|
+
const wrapper = doc.createElement("section");
|
|
1029
|
+
wrapper.style.marginLeft = "1em";
|
|
1030
|
+
items.forEach((item, index) => {
|
|
1031
|
+
const content = item.querySelector("section");
|
|
1032
|
+
const sectionEl = doc.createElement("section");
|
|
1033
|
+
const marker = isOrdered ? `${index + 1}. ` : "• ";
|
|
1034
|
+
sectionEl.innerHTML = marker + (content?.innerHTML ?? item.innerHTML);
|
|
1035
|
+
wrapper.appendChild(sectionEl);
|
|
1036
|
+
});
|
|
1037
|
+
nestedList.replaceWith(wrapper);
|
|
1038
|
+
});
|
|
1039
|
+
nestedLists = element.querySelectorAll(
|
|
1040
|
+
"li > section > ul, li > section > ol"
|
|
1041
|
+
);
|
|
1006
1042
|
}
|
|
1007
|
-
}
|
|
1043
|
+
};
|
|
1044
|
+
flattenNestedLists();
|
|
1008
1045
|
element.style.color = "rgb(0, 0, 0)";
|
|
1009
1046
|
element.style.caretColor = "rgb(0, 0, 0)";
|
|
1010
1047
|
}
|
package/dist/publish.js
CHANGED
|
@@ -196,12 +196,18 @@ class WechatPublisher {
|
|
|
196
196
|
uploadCacheStore;
|
|
197
197
|
uploadMaterial;
|
|
198
198
|
publishArticle;
|
|
199
|
+
_listDraftsFn;
|
|
200
|
+
_getDraftFn;
|
|
201
|
+
_updateDraftFn;
|
|
199
202
|
fetchAccessToken;
|
|
200
203
|
constructor(httpAdapter, tokenStoreAdapter, uploadCacheStoreAdapter) {
|
|
201
|
-
const { uploadMaterial, publishArticle, fetchAccessToken } = createWechatClient(httpAdapter);
|
|
204
|
+
const { uploadMaterial, publishArticle, fetchAccessToken, listDrafts, getDraft, updateDraft } = createWechatClient(httpAdapter);
|
|
202
205
|
this.uploadMaterial = uploadMaterial;
|
|
203
206
|
this.publishArticle = publishArticle;
|
|
204
207
|
this.fetchAccessToken = fetchAccessToken;
|
|
208
|
+
this._listDraftsFn = listDrafts;
|
|
209
|
+
this._getDraftFn = getDraft;
|
|
210
|
+
this._updateDraftFn = updateDraft;
|
|
205
211
|
this.tokenStore = tokenStoreAdapter ? new TokenStore(tokenStoreAdapter) : void 0;
|
|
206
212
|
this.uploadCacheStore = uploadCacheStoreAdapter ? new UploadCacheStore(uploadCacheStoreAdapter) : void 0;
|
|
207
213
|
}
|
|
@@ -242,6 +248,15 @@ class WechatPublisher {
|
|
|
242
248
|
async publishToDraft(accessToken, options) {
|
|
243
249
|
return await this.publishArticle(accessToken, options);
|
|
244
250
|
}
|
|
251
|
+
async listDrafts(accessToken, offset = 0, count = 20, noContent = 0) {
|
|
252
|
+
return await this._listDraftsFn(accessToken, offset, count, noContent);
|
|
253
|
+
}
|
|
254
|
+
async getDraft(accessToken, mediaId) {
|
|
255
|
+
return await this._getDraftFn(accessToken, mediaId);
|
|
256
|
+
}
|
|
257
|
+
async updateDraft(accessToken, mediaId, articleIndex, options) {
|
|
258
|
+
await this._updateDraftFn(accessToken, mediaId, articleIndex, options);
|
|
259
|
+
}
|
|
245
260
|
async clearCache() {
|
|
246
261
|
if (this.tokenStore) {
|
|
247
262
|
await this.tokenStore.clear();
|
package/dist/types/publish.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { HttpAdapter } from "./http.js";
|
|
2
2
|
import { TokenStorageAdapter } from "./tokenStore.js";
|
|
3
3
|
import { UploadCacheStorageAdapter } from "./uploadCacheStore.js";
|
|
4
|
-
import { WechatPublishOptions, WechatPublishResponse, WechatUploadResponse } from "./wechat.js";
|
|
4
|
+
import { WechatPublishOptions, WechatPublishResponse, WechatUploadResponse, WechatDraftListResponse, WechatDraftGetResponse } from "./wechat.js";
|
|
5
5
|
export interface ArticleOptions {
|
|
6
6
|
title: string;
|
|
7
7
|
content: string;
|
|
8
8
|
cover?: string;
|
|
9
9
|
author?: string;
|
|
10
10
|
source_url?: string;
|
|
11
|
+
pic_crop_235_1?: string;
|
|
12
|
+
pic_crop_1_1?: string;
|
|
11
13
|
need_open_comment?: boolean;
|
|
12
14
|
only_fans_can_comment?: boolean;
|
|
13
15
|
}
|
|
@@ -19,11 +21,17 @@ export declare class WechatPublisher {
|
|
|
19
21
|
private uploadCacheStore;
|
|
20
22
|
private uploadMaterial;
|
|
21
23
|
private publishArticle;
|
|
24
|
+
private _listDraftsFn;
|
|
25
|
+
private _getDraftFn;
|
|
26
|
+
private _updateDraftFn;
|
|
22
27
|
private fetchAccessToken;
|
|
23
28
|
constructor(httpAdapter: HttpAdapter, tokenStoreAdapter?: TokenStorageAdapter, uploadCacheStoreAdapter?: UploadCacheStorageAdapter);
|
|
24
29
|
getAccessTokenWithCache(appId: string, appSecret: string): Promise<string>;
|
|
25
30
|
uploadImage(file: Blob, filename: string, accessToken: string, appId?: string): Promise<WechatUploadResponse>;
|
|
26
31
|
publishToDraft(accessToken: string, options: WechatPublishOptions): Promise<WechatPublishResponse>;
|
|
32
|
+
listDrafts(accessToken: string, offset?: number, count?: number, noContent?: number): Promise<WechatDraftListResponse>;
|
|
33
|
+
getDraft(accessToken: string, mediaId: string): Promise<WechatDraftGetResponse>;
|
|
34
|
+
updateDraft(accessToken: string, mediaId: string, articleIndex: number, options: Partial<WechatPublishOptions>): Promise<void>;
|
|
27
35
|
clearCache(): Promise<void>;
|
|
28
36
|
setExternalToken(appid: string, accessToken: string): Promise<void>;
|
|
29
37
|
}
|
package/dist/types/wechat.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface WechatPublishOptions {
|
|
|
19
19
|
content: string;
|
|
20
20
|
thumb_media_id: string;
|
|
21
21
|
content_source_url?: string;
|
|
22
|
+
pic_crop_235_1?: string;
|
|
23
|
+
pic_crop_1_1?: string;
|
|
22
24
|
article_type?: "news" | "newspic";
|
|
23
25
|
image_info?: ImageInfo;
|
|
24
26
|
need_open_comment?: 0 | 1;
|
|
@@ -39,9 +41,31 @@ export interface WechatTokenResponse {
|
|
|
39
41
|
export interface WechatPublishResponse {
|
|
40
42
|
media_id: string;
|
|
41
43
|
}
|
|
44
|
+
export interface WechatDraftListItem {
|
|
45
|
+
media_id: string;
|
|
46
|
+
content: {
|
|
47
|
+
news_item: WechatPublishOptions[];
|
|
48
|
+
};
|
|
49
|
+
update_time: number;
|
|
50
|
+
}
|
|
51
|
+
export interface WechatDraftListResponse {
|
|
52
|
+
total_count: number;
|
|
53
|
+
item_count: number;
|
|
54
|
+
item: WechatDraftListItem[];
|
|
55
|
+
}
|
|
56
|
+
export interface WechatDraftGetResponse {
|
|
57
|
+
news_item: WechatPublishOptions[];
|
|
58
|
+
}
|
|
59
|
+
export interface WechatDraftUpdateResponse {
|
|
60
|
+
errcode: number;
|
|
61
|
+
errmsg: string;
|
|
62
|
+
}
|
|
42
63
|
export declare function createWechatClient(httpAdapter: HttpAdapter): {
|
|
43
64
|
fetchAccessToken(appId: string, appSecret: string): Promise<WechatTokenResponse>;
|
|
44
65
|
uploadMaterial(type: string, file: Blob, filename: string, accessToken: string): Promise<WechatUploadResponse>;
|
|
45
66
|
publishArticle(accessToken: string, options: WechatPublishOptions): Promise<WechatPublishResponse>;
|
|
67
|
+
listDrafts(accessToken: string, offset?: number, count?: number, noContent?: number): Promise<WechatDraftListResponse>;
|
|
68
|
+
getDraft(accessToken: string, mediaId: string): Promise<WechatDraftGetResponse>;
|
|
69
|
+
updateDraft(accessToken: string, mediaId: string, articleIndex: number, options: Partial<WechatPublishOptions>): Promise<void>;
|
|
46
70
|
};
|
|
47
71
|
export type WechatClient = ReturnType<typeof createWechatClient>;
|
package/dist/wechat.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
|
|
2
2
|
const publishUrl = "https://api.weixin.qq.com/cgi-bin/draft/add";
|
|
3
3
|
const uploadUrl = "https://api.weixin.qq.com/cgi-bin/material/add_material";
|
|
4
|
+
const draftListUrl = "https://api.weixin.qq.com/cgi-bin/draft/batchget";
|
|
5
|
+
const draftGetUrl = "https://api.weixin.qq.com/cgi-bin/draft/get";
|
|
6
|
+
const draftUpdateUrl = "https://api.weixin.qq.com/cgi-bin/draft/update";
|
|
4
7
|
function createWechatClient(httpAdapter) {
|
|
5
8
|
return {
|
|
6
9
|
async fetchAccessToken(appId, appSecret) {
|
|
@@ -37,6 +40,39 @@ function createWechatClient(httpAdapter) {
|
|
|
37
40
|
const data = await res.json();
|
|
38
41
|
assertWechatSuccess(data);
|
|
39
42
|
return data;
|
|
43
|
+
},
|
|
44
|
+
async listDrafts(accessToken, offset = 0, count = 20, noContent = 0) {
|
|
45
|
+
const res = await httpAdapter.fetch(`${draftListUrl}?access_token=${accessToken}`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
body: JSON.stringify({ offset, count, no_content: noContent })
|
|
48
|
+
});
|
|
49
|
+
if (!res.ok) throw new Error(await res.text());
|
|
50
|
+
const data = await res.json();
|
|
51
|
+
assertWechatSuccess(data);
|
|
52
|
+
return data;
|
|
53
|
+
},
|
|
54
|
+
async getDraft(accessToken, mediaId) {
|
|
55
|
+
const res = await httpAdapter.fetch(`${draftGetUrl}?access_token=${accessToken}`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: JSON.stringify({ media_id: mediaId })
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) throw new Error(await res.text());
|
|
60
|
+
const data = await res.json();
|
|
61
|
+
assertWechatSuccess(data);
|
|
62
|
+
return data;
|
|
63
|
+
},
|
|
64
|
+
async updateDraft(accessToken, mediaId, articleIndex, options) {
|
|
65
|
+
const res = await httpAdapter.fetch(`${draftUpdateUrl}?access_token=${accessToken}`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
media_id: mediaId,
|
|
69
|
+
index: articleIndex,
|
|
70
|
+
articles: options
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) throw new Error(await res.text());
|
|
74
|
+
const data = await res.json();
|
|
75
|
+
assertWechatSuccess(data);
|
|
40
76
|
}
|
|
41
77
|
};
|
|
42
78
|
}
|
|
@@ -44,7 +80,7 @@ const WECHAT_ERROR_HINTS = {
|
|
|
44
80
|
45166: "内容超长。小绿书模式有内容长度限制,请精简正文后重试。"
|
|
45
81
|
};
|
|
46
82
|
function assertWechatSuccess(data) {
|
|
47
|
-
if ("errcode" in data) {
|
|
83
|
+
if ("errcode" in data && data.errcode !== 0) {
|
|
48
84
|
const hint = WECHAT_ERROR_HINTS[data.errcode];
|
|
49
85
|
throw new Error(hint ? `${data.errcode}: ${hint} (${data.errmsg})` : `${data.errcode}: ${data.errmsg}`);
|
|
50
86
|
}
|
package/dist/wrapper.js
CHANGED
|
@@ -478,7 +478,17 @@ async function uploadImages(content, accessToken, relativePath, appId) {
|
|
|
478
478
|
return { html: updatedHtml, firstImageId };
|
|
479
479
|
}
|
|
480
480
|
async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
481
|
-
const {
|
|
481
|
+
const {
|
|
482
|
+
title,
|
|
483
|
+
content,
|
|
484
|
+
cover,
|
|
485
|
+
author,
|
|
486
|
+
source_url,
|
|
487
|
+
pic_crop_235_1,
|
|
488
|
+
pic_crop_1_1,
|
|
489
|
+
need_open_comment,
|
|
490
|
+
only_fans_can_comment
|
|
491
|
+
} = articleOptions;
|
|
482
492
|
const { appId, appSecret, relativePath } = publishOptions;
|
|
483
493
|
const { appId: appIdFinal, appSecret: appSecretFinal } = await getAppIdAndSecret(appId, appSecret);
|
|
484
494
|
const accessToken = await wechatPublisher.getAccessTokenWithCache(appIdFinal, appSecretFinal);
|
|
@@ -514,6 +524,8 @@ async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
|
514
524
|
thumb_media_id: thumbMediaId,
|
|
515
525
|
author,
|
|
516
526
|
content_source_url: source_url,
|
|
527
|
+
pic_crop_235_1,
|
|
528
|
+
pic_crop_1_1,
|
|
517
529
|
need_open_comment: need_open_comment ? 1 : 0,
|
|
518
530
|
only_fans_can_comment: only_fans_can_comment ? 1 : 0
|
|
519
531
|
});
|
|
@@ -571,11 +583,30 @@ async function publishImageTextToWechatDraft(articleOptions, publishOptions = {}
|
|
|
571
583
|
if (!thumbMediaId) {
|
|
572
584
|
throw new Error("未能获取封面图的 media_id");
|
|
573
585
|
}
|
|
586
|
+
let plainContent = content || "";
|
|
587
|
+
if (plainContent) {
|
|
588
|
+
if (plainContent.includes("<br") || plainContent.includes("<p")) {
|
|
589
|
+
plainContent = plainContent.replace(/<br\s*\/?>\n/g, "\n");
|
|
590
|
+
const dom = new JSDOM(`<body>${plainContent}</body>`);
|
|
591
|
+
const document = dom.window.document;
|
|
592
|
+
const brs = document.querySelectorAll("br");
|
|
593
|
+
for (const br of brs) {
|
|
594
|
+
br.replaceWith(document.createTextNode("\n"));
|
|
595
|
+
}
|
|
596
|
+
const paragraphs = document.querySelectorAll("p");
|
|
597
|
+
for (const p of paragraphs) {
|
|
598
|
+
const text = document.createTextNode("\n" + p.textContent + "\n");
|
|
599
|
+
p.replaceWith(text);
|
|
600
|
+
}
|
|
601
|
+
plainContent = document.body.textContent?.trim() || "";
|
|
602
|
+
}
|
|
603
|
+
plainContent = plainContent.replace(/^#{1,6}\s+/gm, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/__(.*?)__/g, "$1").replace(/_(.*?)_/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "").replace(/^\s*[-*+]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").replace(/^\s*>\s+/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
604
|
+
}
|
|
574
605
|
const data = await wechatPublisher.publishToDraft(
|
|
575
606
|
accessToken,
|
|
576
607
|
{
|
|
577
608
|
title,
|
|
578
|
-
content,
|
|
609
|
+
content: plainContent,
|
|
579
610
|
thumb_media_id: thumbMediaId,
|
|
580
611
|
author,
|
|
581
612
|
article_type: "newspic",
|
|
@@ -864,7 +895,21 @@ async function extractAndCleanImages(body) {
|
|
|
864
895
|
parent.remove();
|
|
865
896
|
}
|
|
866
897
|
}
|
|
867
|
-
|
|
898
|
+
for (const child of Array.from(wenyan.children)) {
|
|
899
|
+
if (!child.textContent?.trim()) {
|
|
900
|
+
child.remove();
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
const paragraphs = Array.from(wenyan.querySelectorAll("p"));
|
|
904
|
+
for (const p of paragraphs) {
|
|
905
|
+
const frag = document.createDocumentFragment();
|
|
906
|
+
while (p.firstChild) {
|
|
907
|
+
frag.appendChild(p.firstChild);
|
|
908
|
+
}
|
|
909
|
+
frag.appendChild(document.createElement("br"));
|
|
910
|
+
p.parentNode?.replaceChild(frag, p);
|
|
911
|
+
}
|
|
912
|
+
return { imagePaths, cleanedHtml: wenyan.innerHTML.trim() };
|
|
868
913
|
}
|
|
869
914
|
const nodeMermaidRenderer = createNodeMermaidRenderer();
|
|
870
915
|
const wenyanCoreInstance = await createWenyanCore({
|
package/package.json
CHANGED