multi-publisher 1.0.0

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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +370 -0
  3. package/dist/adapters/baijiahao.d.ts +14 -0
  4. package/dist/adapters/baijiahao.js +77 -0
  5. package/dist/adapters/base-adapter.d.ts +41 -0
  6. package/dist/adapters/base-adapter.js +84 -0
  7. package/dist/adapters/bilibili.d.ts +14 -0
  8. package/dist/adapters/bilibili.js +86 -0
  9. package/dist/adapters/cnblogs.d.ts +14 -0
  10. package/dist/adapters/cnblogs.js +90 -0
  11. package/dist/adapters/csdn.d.ts +29 -0
  12. package/dist/adapters/csdn.js +174 -0
  13. package/dist/adapters/cto51.d.ts +14 -0
  14. package/dist/adapters/cto51.js +72 -0
  15. package/dist/adapters/douban.d.ts +14 -0
  16. package/dist/adapters/douban.js +49 -0
  17. package/dist/adapters/eastmoney.d.ts +14 -0
  18. package/dist/adapters/eastmoney.js +47 -0
  19. package/dist/adapters/imooc.d.ts +14 -0
  20. package/dist/adapters/imooc.js +78 -0
  21. package/dist/adapters/index.d.ts +26 -0
  22. package/dist/adapters/index.js +22 -0
  23. package/dist/adapters/interface.d.ts +44 -0
  24. package/dist/adapters/interface.js +1 -0
  25. package/dist/adapters/juejin.d.ts +23 -0
  26. package/dist/adapters/juejin.js +166 -0
  27. package/dist/adapters/oschina.d.ts +14 -0
  28. package/dist/adapters/oschina.js +77 -0
  29. package/dist/adapters/registry.d.ts +61 -0
  30. package/dist/adapters/registry.js +146 -0
  31. package/dist/adapters/segmentfault.d.ts +14 -0
  32. package/dist/adapters/segmentfault.js +73 -0
  33. package/dist/adapters/sohu.d.ts +14 -0
  34. package/dist/adapters/sohu.js +72 -0
  35. package/dist/adapters/toutiao.d.ts +9 -0
  36. package/dist/adapters/toutiao.js +199 -0
  37. package/dist/adapters/wechat-publisher.d.ts +55 -0
  38. package/dist/adapters/wechat-publisher.js +210 -0
  39. package/dist/adapters/weibo.d.ts +14 -0
  40. package/dist/adapters/weibo.js +99 -0
  41. package/dist/adapters/weixin.d.ts +14 -0
  42. package/dist/adapters/weixin.js +63 -0
  43. package/dist/adapters/woshipm.d.ts +14 -0
  44. package/dist/adapters/woshipm.js +72 -0
  45. package/dist/adapters/xiaohongshu.d.ts +9 -0
  46. package/dist/adapters/xiaohongshu.js +199 -0
  47. package/dist/adapters/xueqiu.d.ts +14 -0
  48. package/dist/adapters/xueqiu.js +74 -0
  49. package/dist/adapters/yuque.d.ts +13 -0
  50. package/dist/adapters/yuque.js +25 -0
  51. package/dist/adapters/zhihu.d.ts +23 -0
  52. package/dist/adapters/zhihu.js +142 -0
  53. package/dist/cli/cookie.d.ts +5 -0
  54. package/dist/cli/cookie.js +80 -0
  55. package/dist/cli/credential.d.ts +6 -0
  56. package/dist/cli/credential.js +32 -0
  57. package/dist/cli/index.d.ts +5 -0
  58. package/dist/cli/index.js +72 -0
  59. package/dist/cli/login.d.ts +3 -0
  60. package/dist/cli/login.js +101 -0
  61. package/dist/cli/platforms.d.ts +1 -0
  62. package/dist/cli/platforms.js +35 -0
  63. package/dist/cli/publish-all.d.ts +6 -0
  64. package/dist/cli/publish-all.js +101 -0
  65. package/dist/cli/publish.d.ts +7 -0
  66. package/dist/cli/publish.js +78 -0
  67. package/dist/cli/render.d.ts +9 -0
  68. package/dist/cli/render.js +40 -0
  69. package/dist/commands/login.d.ts +43 -0
  70. package/dist/commands/login.js +248 -0
  71. package/dist/commands/publish.d.ts +19 -0
  72. package/dist/commands/publish.js +275 -0
  73. package/dist/config.d.ts +177 -0
  74. package/dist/config.js +333 -0
  75. package/dist/core/mathjax.d.ts +4 -0
  76. package/dist/core/mathjax.js +33 -0
  77. package/dist/core/parser.d.ts +17 -0
  78. package/dist/core/parser.js +42 -0
  79. package/dist/core/renderer.d.ts +18 -0
  80. package/dist/core/renderer.js +30 -0
  81. package/dist/core/styler.d.ts +8 -0
  82. package/dist/core/styler.js +11 -0
  83. package/dist/core/theme.d.ts +9 -0
  84. package/dist/core/theme.js +420 -0
  85. package/dist/index.d.ts +8 -0
  86. package/dist/index.js +7 -0
  87. package/dist/runtime/browser-runtime.d.ts +79 -0
  88. package/dist/runtime/browser-runtime.js +501 -0
  89. package/dist/runtime/index.d.ts +12 -0
  90. package/dist/runtime/index.js +1 -0
  91. package/dist/runtime/node-runtime.d.ts +5 -0
  92. package/dist/runtime/node-runtime.js +25 -0
  93. package/dist/tools/xiaohongshu-sniffer.d.ts +1 -0
  94. package/dist/tools/xiaohongshu-sniffer.js +54 -0
  95. package/package.json +62 -0
  96. package/themes/all-themes-preview.html +522 -0
  97. package/themes/previews/cyberpunk.png +0 -0
  98. package/themes/previews/minimal.png +0 -0
  99. package/themes/previews/nord.png +0 -0
  100. package/themes/previews/wechat.png +0 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * B站 (Bilibili) 适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class BilibiliAdapter extends BaseAdapter {
7
+ meta = {
8
+ id: 'bilibili',
9
+ name: 'B站',
10
+ icon: 'https://www.bilibili.com/favicon.ico',
11
+ homepage: 'https://member.bilibili.com/articles/edit',
12
+ capabilities: ['article', 'draft', 'image_upload'],
13
+ };
14
+ cookieData = null;
15
+ async init() {
16
+ this.cookieData = await this.loadCookies();
17
+ }
18
+ getCookieConfigKey() {
19
+ return 'bilibili';
20
+ }
21
+ async checkAuth() {
22
+ if (!this.cookieData) {
23
+ return { isAuthenticated: false, error: '未配置 B站 Cookie' };
24
+ }
25
+ try {
26
+ const cookieStr = this.buildCookieString(this.cookieData);
27
+ const res = await fetch('https://api.bilibili.com/x/web-interface/nav', {
28
+ headers: {
29
+ 'Cookie': cookieStr,
30
+ 'User-Agent': this.getCommonHeaders()['User-Agent'],
31
+ },
32
+ });
33
+ const data = await res.json();
34
+ if (data.code === 0 && data.data?.mid) {
35
+ return {
36
+ isAuthenticated: true,
37
+ userId: String(data.data.mid),
38
+ username: data.data.uname,
39
+ };
40
+ }
41
+ return { isAuthenticated: false, error: '未登录或登录已过期' };
42
+ }
43
+ catch (err) {
44
+ return { isAuthenticated: false, error: err.message };
45
+ }
46
+ }
47
+ async publish(article) {
48
+ const start = Date.now();
49
+ if (!this.cookieData) {
50
+ return this.createErrorResult('未配置 B站 Cookie', start);
51
+ }
52
+ try {
53
+ const cookieStr = this.buildCookieString(this.cookieData);
54
+ // B站创作中心 API - 获取 csrf token
55
+ const csrfToken = this.cookieData.bili_jct || '';
56
+ // 发布文章草稿
57
+ const res = await fetch('https://member.bilibili.com/articles/submit', {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ 'Cookie': cookieStr,
62
+ ...this.getCommonHeaders(),
63
+ },
64
+ body: JSON.stringify({
65
+ title: article.title,
66
+ content: article.markdown || article.html || '',
67
+ category_id: 0,
68
+ tag_ids: [],
69
+ list_id: 0,
70
+ draft: 1, // 存草稿
71
+ image_urls: [],
72
+ }),
73
+ });
74
+ const data = await res.json();
75
+ if (data.code !== 0) {
76
+ throw new Error(data.message || '发布失败');
77
+ }
78
+ const postId = String(data.data?.id || 0);
79
+ const draftUrl = `https://member.bilibili.com/articles/edit?id=${postId}`;
80
+ return this.createSuccessResult(postId, draftUrl, true, start);
81
+ }
82
+ catch (err) {
83
+ return this.createErrorResult(err.message, start);
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 博客园 (Cnblogs) 适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ import type { Article, AuthResult, PlatformMeta } from './interface.js';
7
+ export declare class CnblogsAdapter extends BaseAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private cookieData;
10
+ init(): Promise<void>;
11
+ protected getCookieConfigKey(): string;
12
+ checkAuth(): Promise<AuthResult>;
13
+ publish(article: Article): Promise<import('./interface.js').SyncResult>;
14
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * 博客园 (Cnblogs) 适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class CnblogsAdapter extends BaseAdapter {
7
+ meta = {
8
+ id: 'cnblogs',
9
+ name: '博客园',
10
+ icon: 'https://www.cnblogs.com/favicon.ico',
11
+ homepage: 'https://i.cnblogs.com/',
12
+ capabilities: ['article', 'draft', 'image_upload'],
13
+ };
14
+ cookieData = null;
15
+ async init() {
16
+ this.cookieData = await this.loadCookies();
17
+ }
18
+ getCookieConfigKey() {
19
+ return 'cnblogs';
20
+ }
21
+ async checkAuth() {
22
+ if (!this.cookieData) {
23
+ return { isAuthenticated: false, error: '未配置博客园 Cookie' };
24
+ }
25
+ try {
26
+ const cookieStr = this.buildCookieString(this.cookieData);
27
+ const res = await fetch('https://home.cnblogs.com/user/CurrentUserInfo', {
28
+ headers: {
29
+ 'Cookie': cookieStr,
30
+ ...this.getCommonHeaders(),
31
+ },
32
+ });
33
+ const text = await res.text();
34
+ const avatarMatch = text.match(/<img[^>]+class="pfs"[^>]+src="([^"]+)"/);
35
+ const linkMatch = text.match(/href="\/u\/([^/]+)\/"/);
36
+ if (linkMatch) {
37
+ return {
38
+ isAuthenticated: true,
39
+ userId: linkMatch[1],
40
+ username: linkMatch[1],
41
+ avatar: avatarMatch?.[1],
42
+ };
43
+ }
44
+ return { isAuthenticated: false, error: '未获取到用户信息' };
45
+ }
46
+ catch (err) {
47
+ return { isAuthenticated: false, error: err.message };
48
+ }
49
+ }
50
+ async publish(article) {
51
+ const start = Date.now();
52
+ if (!this.cookieData) {
53
+ return this.createErrorResult('未配置博客园 Cookie', start);
54
+ }
55
+ try {
56
+ const cookieStr = this.buildCookieString(this.cookieData);
57
+ // 先获取 XSRF token
58
+ await fetch('https://i.cnblogs.com/posts/edit', { credentials: 'include' });
59
+ const xsrfToken = this.cookieData['.CNBlogsCookie']?.split(';')?.find(c => c.includes('XSRF-TOKEN')) || '';
60
+ const res = await fetch('https://i.cnblogs.com/api/posts', {
61
+ method: 'POST',
62
+ credentials: 'include',
63
+ headers: {
64
+ 'Content-Type': 'application/json',
65
+ 'x-xsrf-token': xsrfToken,
66
+ 'Cookie': cookieStr,
67
+ },
68
+ body: JSON.stringify({
69
+ id: null,
70
+ postType: 2,
71
+ title: article.title,
72
+ postBody: article.markdown || '',
73
+ isMarkdown: true,
74
+ isDraft: true,
75
+ isPublished: false,
76
+ }),
77
+ });
78
+ const data = await res.json();
79
+ if (!data.id) {
80
+ throw new Error(data.error || '创建草稿失败');
81
+ }
82
+ const postId = String(data.id);
83
+ const draftUrl = `https://i.cnblogs.com/articles/edit;postId=${postId}`;
84
+ return this.createSuccessResult(postId, draftUrl, true, start);
85
+ }
86
+ catch (err) {
87
+ return this.createErrorResult(err.message, start);
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * CSDN 适配器
3
+ * 认证方式: Cookie + API 签名 (HMAC-SHA256)
4
+ */
5
+ import type { IPlatformAdapter, Article, SyncResult, AuthResult, PlatformMeta } from './interface.js';
6
+ import type { RuntimeInterface } from '../runtime/index.js';
7
+ export declare class CSDNAdapter implements IPlatformAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private runtime;
10
+ private cookieData;
11
+ init(runtime: RuntimeInterface): Promise<void>;
12
+ private loadCookie;
13
+ private buildCookieString;
14
+ private getCommonHeaders;
15
+ /**
16
+ * 生成 UUID
17
+ */
18
+ private createUuid;
19
+ /**
20
+ * HMAC-SHA256 签名
21
+ */
22
+ private hmacSha256;
23
+ /**
24
+ * 生成 CSDN API 签名
25
+ */
26
+ private signRequest;
27
+ checkAuth(): Promise<AuthResult>;
28
+ publish(article: Article): Promise<SyncResult>;
29
+ }
@@ -0,0 +1,174 @@
1
+ import { ConfigStore } from '../config.js';
2
+ import crypto from 'node:crypto';
3
+ // CSDN API 签名密钥
4
+ const API_KEY = '203803574';
5
+ const API_SECRET = '9znpamsyl2c7cdrr9sas0le9vbc3r6ba';
6
+ export class CSDNAdapter {
7
+ meta = {
8
+ id: 'csdn',
9
+ name: 'CSDN',
10
+ icon: 'https://g.csdnimg.cn/static/logo/favicon32.ico',
11
+ homepage: 'https://editor.csdn.net/md/',
12
+ capabilities: ['article', 'draft', 'image_upload'],
13
+ };
14
+ runtime;
15
+ cookieData = null;
16
+ async init(runtime) {
17
+ this.runtime = runtime;
18
+ this.cookieData = await this.loadCookie();
19
+ }
20
+ async loadCookie() {
21
+ const cookies = await ConfigStore.getCSDNCookies();
22
+ if (!cookies)
23
+ return null;
24
+ return { cookies };
25
+ }
26
+ buildCookieString(cookieData) {
27
+ if (!cookieData.cookies)
28
+ return '';
29
+ return Object.entries(cookieData.cookies)
30
+ .map(([k, v]) => `${k}=${v}`)
31
+ .join('; ');
32
+ }
33
+ getCommonHeaders() {
34
+ return {
35
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
36
+ 'Origin': 'https://editor.csdn.net',
37
+ 'Referer': 'https://editor.csdn.net/',
38
+ };
39
+ }
40
+ /**
41
+ * 生成 UUID
42
+ */
43
+ createUuid() {
44
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
45
+ const r = Math.random() * 16 | 0;
46
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
47
+ return v.toString(16);
48
+ });
49
+ }
50
+ /**
51
+ * HMAC-SHA256 签名
52
+ */
53
+ async hmacSha256(message, secret) {
54
+ return crypto.createHmac('sha256', secret).update(message).digest('base64');
55
+ }
56
+ /**
57
+ * 生成 CSDN API 签名
58
+ */
59
+ async signRequest(apiPath, method = 'POST') {
60
+ const nonce = this.createUuid();
61
+ const signStr = method === 'GET'
62
+ ? `GET\n*/*\n\n\n\nx-ca-key:${API_KEY}\nx-ca-nonce:${nonce}\n${apiPath}`
63
+ : `POST\n*/*\n\napplication/json\n\nx-ca-key:${API_KEY}\nx-ca-nonce:${nonce}\n${apiPath}`;
64
+ const signature = await this.hmacSha256(signStr, API_SECRET);
65
+ const headers = {
66
+ 'accept': '*/*',
67
+ 'x-ca-key': API_KEY,
68
+ 'x-ca-nonce': nonce,
69
+ 'x-ca-signature': signature,
70
+ 'x-ca-signature-headers': 'x-ca-key,x-ca-nonce',
71
+ ...this.getCommonHeaders(),
72
+ };
73
+ if (method === 'POST') {
74
+ headers['content-type'] = 'application/json';
75
+ }
76
+ return headers;
77
+ }
78
+ async checkAuth() {
79
+ if (!this.cookieData?.cookies) {
80
+ return { isAuthenticated: false, error: '未配置 CSDN Cookie,请运行: mpub cookie --platform csdn --set' };
81
+ }
82
+ try {
83
+ const cookieStr = this.buildCookieString(this.cookieData);
84
+ const apiPath = '/blog-console-api/v3/editor/getBaseInfo';
85
+ const headers = await this.signRequest(apiPath, 'GET');
86
+ const response = await this.runtime.fetch(`https://bizapi.csdn.net${apiPath}`, {
87
+ method: 'GET',
88
+ headers: {
89
+ ...headers,
90
+ 'Cookie': cookieStr,
91
+ },
92
+ });
93
+ const res = await response.json();
94
+ if (res.code === 200 && res.data?.name) {
95
+ return {
96
+ isAuthenticated: true,
97
+ userId: res.data.name,
98
+ username: res.data.nickname || res.data.name,
99
+ avatar: res.data.avatar,
100
+ };
101
+ }
102
+ return { isAuthenticated: false, error: 'CSDN 未授权' };
103
+ }
104
+ catch (err) {
105
+ return { isAuthenticated: false, error: err.message };
106
+ }
107
+ }
108
+ async publish(article) {
109
+ const start = Date.now();
110
+ try {
111
+ if (!this.cookieData?.cookies) {
112
+ throw new Error('未配置 CSDN Cookie,请运行: mpub cookie --platform csdn --set');
113
+ }
114
+ const cookieStr = this.buildCookieString(this.cookieData);
115
+ // 使用 Markdown 格式
116
+ let markdown = article.markdown || '';
117
+ const htmlContent = article.html || '';
118
+ // 生成签名
119
+ const apiPath = '/blog-console-api/v3/mdeditor/saveArticle';
120
+ const headers = await this.signRequest(apiPath);
121
+ const response = await this.runtime.fetch(`https://bizapi.csdn.net${apiPath}`, {
122
+ method: 'POST',
123
+ headers: {
124
+ ...headers,
125
+ 'Cookie': cookieStr,
126
+ },
127
+ body: JSON.stringify({
128
+ title: article.title,
129
+ markdowncontent: markdown,
130
+ content: htmlContent,
131
+ readType: 'public',
132
+ level: 0,
133
+ tags: '',
134
+ status: 2, // 草稿
135
+ categories: '',
136
+ type: 'original',
137
+ original_link: '',
138
+ authorized_status: false,
139
+ not_auto_saved: '1',
140
+ source: 'pc_mdeditor',
141
+ cover_images: [],
142
+ cover_type: 1,
143
+ is_new: 1,
144
+ vote_id: 0,
145
+ resource_id: '',
146
+ pubStatus: 'draft',
147
+ creator_activity_id: '',
148
+ }),
149
+ });
150
+ const res = await response.json();
151
+ if (res.code !== 200 || !res.data?.id) {
152
+ throw new Error(res.msg || res.message || '保存草稿失败');
153
+ }
154
+ const postId = res.data.id;
155
+ const draftUrl = `https://editor.csdn.net/md?articleId=${postId}`;
156
+ return {
157
+ platform: this.meta.id,
158
+ success: true,
159
+ postId: postId,
160
+ postUrl: draftUrl,
161
+ draftOnly: true,
162
+ timestamp: Date.now() - start,
163
+ };
164
+ }
165
+ catch (err) {
166
+ return {
167
+ platform: this.meta.id,
168
+ success: false,
169
+ error: err.message,
170
+ timestamp: Date.now() - start,
171
+ };
172
+ }
173
+ }
174
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 51CTO 适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ import type { Article, AuthResult, PlatformMeta } from './interface.js';
7
+ export declare class Cto51Adapter extends BaseAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private cookieData;
10
+ init(): Promise<void>;
11
+ protected getCookieConfigKey(): string;
12
+ checkAuth(): Promise<AuthResult>;
13
+ publish(article: Article): Promise<import('./interface.js').SyncResult>;
14
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 51CTO 适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class Cto51Adapter extends BaseAdapter {
7
+ meta = {
8
+ id: 'cto51',
9
+ name: '51CTO',
10
+ icon: 'https://blog.51cto.com/favicon.ico',
11
+ homepage: 'https://blog.51cto.com/',
12
+ capabilities: ['article', 'draft'],
13
+ };
14
+ cookieData = null;
15
+ async init() {
16
+ this.cookieData = await this.loadCookies();
17
+ }
18
+ getCookieConfigKey() {
19
+ return 'cto51';
20
+ }
21
+ async checkAuth() {
22
+ if (!this.cookieData) {
23
+ return { isAuthenticated: false, error: '未配置 51CTO Cookie' };
24
+ }
25
+ try {
26
+ const cookieStr = this.buildCookieString(this.cookieData);
27
+ const res = await fetch('https://blog.51cto.com/editor/draft', {
28
+ headers: {
29
+ 'Cookie': cookieStr,
30
+ ...this.getCommonHeaders(),
31
+ },
32
+ });
33
+ if (res.ok && !res.url.includes('login')) {
34
+ return { isAuthenticated: true };
35
+ }
36
+ return { isAuthenticated: false, error: '未登录或登录已过期' };
37
+ }
38
+ catch (err) {
39
+ return { isAuthenticated: false, error: err.message };
40
+ }
41
+ }
42
+ async publish(article) {
43
+ const start = Date.now();
44
+ if (!this.cookieData) {
45
+ return this.createErrorResult('未配置 51CTO Cookie', start);
46
+ }
47
+ try {
48
+ const cookieStr = this.buildCookieString(this.cookieData);
49
+ const res = await fetch('https://blog.51cto.com/blogger/save_draft', {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ 'Cookie': cookieStr,
54
+ ...this.getCommonHeaders(),
55
+ },
56
+ body: JSON.stringify({
57
+ title: article.title,
58
+ content: article.markdown || '',
59
+ draft: 1,
60
+ }),
61
+ });
62
+ const data = await res.json();
63
+ if (data.code === 0 && data.id) {
64
+ return this.createSuccessResult(data.id, `https://blog.51cto.com/editor/edit?id=${data.id}`, true, start);
65
+ }
66
+ return this.createErrorResult('发布失败', start);
67
+ }
68
+ catch (err) {
69
+ return this.createErrorResult(err.message, start);
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 豆瓣适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ import type { Article, AuthResult, PlatformMeta } from './interface.js';
7
+ export declare class DoubanAdapter extends BaseAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private cookieData;
10
+ init(): Promise<void>;
11
+ protected getCookieConfigKey(): string;
12
+ checkAuth(): Promise<AuthResult>;
13
+ publish(article: Article): Promise<import('./interface.js').SyncResult>;
14
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 豆瓣适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class DoubanAdapter extends BaseAdapter {
7
+ meta = {
8
+ id: 'douban',
9
+ name: '豆瓣',
10
+ icon: 'https://www.douban.com/favicon.ico',
11
+ homepage: 'https://www.douban.com/',
12
+ capabilities: ['article', 'draft'],
13
+ };
14
+ cookieData = null;
15
+ async init() {
16
+ this.cookieData = await this.loadCookies();
17
+ }
18
+ getCookieConfigKey() {
19
+ return 'douban';
20
+ }
21
+ async checkAuth() {
22
+ if (!this.cookieData) {
23
+ return { isAuthenticated: false, error: '未配置豆瓣 Cookie' };
24
+ }
25
+ try {
26
+ const cookieStr = this.buildCookieString(this.cookieData);
27
+ const res = await fetch('https://www.douban.com/', {
28
+ headers: {
29
+ 'Cookie': cookieStr,
30
+ ...this.getCommonHeaders(),
31
+ },
32
+ });
33
+ const text = await res.text();
34
+ // 豆瓣登录后会有用户信息
35
+ if (text.includes('id="db_current_user"') || text.includes('授权者')) {
36
+ return { isAuthenticated: true };
37
+ }
38
+ return { isAuthenticated: false, error: '未登录或登录已过期' };
39
+ }
40
+ catch (err) {
41
+ return { isAuthenticated: false, error: err.message };
42
+ }
43
+ }
44
+ async publish(article) {
45
+ const start = Date.now();
46
+ // 豆瓣日记 API
47
+ return this.createErrorResult('豆瓣发布功能开发中', start);
48
+ }
49
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 东方财富适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ import type { Article, AuthResult, PlatformMeta } from './interface.js';
7
+ export declare class EastmoneyAdapter extends BaseAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private cookieData;
10
+ init(): Promise<void>;
11
+ protected getCookieConfigKey(): string;
12
+ checkAuth(): Promise<AuthResult>;
13
+ publish(article: Article): Promise<import('./interface.js').SyncResult>;
14
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 东方财富适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class EastmoneyAdapter extends BaseAdapter {
7
+ meta = {
8
+ id: 'eastmoney',
9
+ name: '东方财富',
10
+ icon: 'https://www.eastmoney.com/favicon.ico',
11
+ homepage: 'https://www.eastmoney.com/',
12
+ capabilities: ['article', 'draft'],
13
+ };
14
+ cookieData = null;
15
+ async init() {
16
+ this.cookieData = await this.loadCookies();
17
+ }
18
+ getCookieConfigKey() {
19
+ return 'eastmoney';
20
+ }
21
+ async checkAuth() {
22
+ if (!this.cookieData) {
23
+ return { isAuthenticated: false, error: '未配置东方财富 Cookie' };
24
+ }
25
+ try {
26
+ const cookieStr = this.buildCookieString(this.cookieData);
27
+ // 东方财富号
28
+ const res = await fetch('https://nsfc.eastmoney.com/', {
29
+ headers: {
30
+ 'Cookie': cookieStr,
31
+ ...this.getCommonHeaders(),
32
+ },
33
+ });
34
+ if (res.ok && !res.url.includes('login')) {
35
+ return { isAuthenticated: true };
36
+ }
37
+ return { isAuthenticated: false, error: '未登录或登录已过期' };
38
+ }
39
+ catch (err) {
40
+ return { isAuthenticated: false, error: err.message };
41
+ }
42
+ }
43
+ async publish(article) {
44
+ const start = Date.now();
45
+ return this.createErrorResult('东方财富发布功能开发中', start);
46
+ }
47
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 慕课网适配器
3
+ * 认证方式: Cookie
4
+ */
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ import type { Article, AuthResult, PlatformMeta } from './interface.js';
7
+ export declare class ImoocAdapter extends BaseAdapter {
8
+ readonly meta: PlatformMeta;
9
+ private cookieData;
10
+ init(): Promise<void>;
11
+ protected getCookieConfigKey(): string;
12
+ checkAuth(): Promise<AuthResult>;
13
+ publish(article: Article): Promise<import('./interface.js').SyncResult>;
14
+ }