openclaw-github-trending 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.
- package/LICENSE +21 -0
- package/README.md +480 -0
- package/dist/channels/email.d.ts +61 -0
- package/dist/channels/email.d.ts.map +1 -0
- package/dist/channels/email.js +599 -0
- package/dist/channels/email.js.map +1 -0
- package/dist/channels/feishu.d.ts +50 -0
- package/dist/channels/feishu.d.ts.map +1 -0
- package/dist/channels/feishu.js +322 -0
- package/dist/channels/feishu.js.map +1 -0
- package/dist/channels/types.d.ts +66 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +12 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config.d.ts +83 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +145 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/fetcher.d.ts +43 -0
- package/dist/core/fetcher.d.ts.map +1 -0
- package/dist/core/fetcher.js +306 -0
- package/dist/core/fetcher.js.map +1 -0
- package/dist/core/file-storage.d.ts +62 -0
- package/dist/core/file-storage.d.ts.map +1 -0
- package/dist/core/file-storage.js +253 -0
- package/dist/core/file-storage.js.map +1 -0
- package/dist/core/history.d.ts +71 -0
- package/dist/core/history.d.ts.map +1 -0
- package/dist/core/history.js +133 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/summarizer.d.ts +64 -0
- package/dist/core/summarizer.d.ts.map +1 -0
- package/dist/core/summarizer.js +324 -0
- package/dist/core/summarizer.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +668 -0
- package/dist/index.js.map +1 -0
- package/dist/models/config.d.ts +93 -0
- package/dist/models/config.d.ts.map +1 -0
- package/dist/models/config.js +3 -0
- package/dist/models/config.js.map +1 -0
- package/dist/models/history.d.ts +6 -0
- package/dist/models/history.d.ts.map +1 -0
- package/dist/models/history.js +7 -0
- package/dist/models/history.js.map +1 -0
- package/dist/models/repository.d.ts +28 -0
- package/dist/models/repository.d.ts.map +1 -0
- package/dist/models/repository.js +3 -0
- package/dist/models/repository.js.map +1 -0
- package/dist/models/service.types.d.ts +87 -0
- package/dist/models/service.types.d.ts.map +1 -0
- package/dist/models/service.types.js +3 -0
- package/dist/models/service.types.js.map +1 -0
- package/dist/services/trending.service.d.ts +29 -0
- package/dist/services/trending.service.d.ts.map +1 -0
- package/dist/services/trending.service.js +306 -0
- package/dist/services/trending.service.js.map +1 -0
- package/dist/tool.d.ts +47 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +314 -0
- package/dist/tool.js.map +1 -0
- package/dist/utils/logger.d.ts +77 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +214 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/markdown.d.ts +9 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/utils/markdown.js +40 -0
- package/dist/utils/markdown.js.map +1 -0
- package/openclaw.plugin.json +152 -0
- package/package.json +78 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.EmailChannel = void 0;
|
|
40
|
+
const markdown = __importStar(require("../utils/markdown"));
|
|
41
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
42
|
+
const logger_1 = require("../utils/logger");
|
|
43
|
+
const logger = logger_1.Logger.get('EmailChannel');
|
|
44
|
+
/**
|
|
45
|
+
* Email Channel for pushing GitHub trending repositories via email
|
|
46
|
+
*/
|
|
47
|
+
class EmailChannel {
|
|
48
|
+
/**
|
|
49
|
+
* Create an email channel instance
|
|
50
|
+
* @param config Email configuration
|
|
51
|
+
*/
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate HTML email content from repositories
|
|
57
|
+
* @param newRepositories Array of new repositories to display
|
|
58
|
+
* @param seenRepositories Array of seen repositories to display
|
|
59
|
+
* @param since Time period for trending (daily, weekly, monthly)
|
|
60
|
+
* @returns HTML string for the email
|
|
61
|
+
*/
|
|
62
|
+
static generateHTML(newRepositories, seenRepositories, since = 'monthly') {
|
|
63
|
+
const currentDate = new Date();
|
|
64
|
+
const dateStr = currentDate.toLocaleDateString('zh-CN', {
|
|
65
|
+
year: 'numeric',
|
|
66
|
+
month: 'long',
|
|
67
|
+
day: 'numeric',
|
|
68
|
+
weekday: 'long'
|
|
69
|
+
});
|
|
70
|
+
// 根据 since 参数确定时间范围描述
|
|
71
|
+
const sinceTextMap = {
|
|
72
|
+
daily: '今日',
|
|
73
|
+
weekly: '本周',
|
|
74
|
+
monthly: '本月'
|
|
75
|
+
};
|
|
76
|
+
const sinceText = sinceTextMap[since];
|
|
77
|
+
const NEW_REPOS_TITLE = '新上榜项目';
|
|
78
|
+
const SEEN_REPOS_TITLE = '持续霸榜项目';
|
|
79
|
+
// Email styles using 靛蓝色系 (indigo/blue color scheme)
|
|
80
|
+
// 使用 CSS 变量提高可维护性
|
|
81
|
+
const styles = `
|
|
82
|
+
:root {
|
|
83
|
+
--primary-color: #4A6FA5;
|
|
84
|
+
--primary-light: #5B8CB3;
|
|
85
|
+
--text-dark: #333;
|
|
86
|
+
--text-medium: #666;
|
|
87
|
+
--text-light: #888;
|
|
88
|
+
--bg-light: #f5f7fa;
|
|
89
|
+
--bg-card: #f9fafb;
|
|
90
|
+
--border-color: #e1e4e8;
|
|
91
|
+
--ai-bg: #f0f4ff;
|
|
92
|
+
--ai-border: #4A6FA5;
|
|
93
|
+
--ai-title-color: #2c5282;
|
|
94
|
+
--new-section-bg: #fff5f5;
|
|
95
|
+
--seen-section-bg: #f0f9ff;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
body {
|
|
99
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
100
|
+
background-color: var(--bg-light);
|
|
101
|
+
margin: 0;
|
|
102
|
+
padding: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.container {
|
|
106
|
+
max-width: 800px;
|
|
107
|
+
margin: 20px auto;
|
|
108
|
+
padding: 0 20px;
|
|
109
|
+
background-color: #ffffff;
|
|
110
|
+
border-radius: 8px;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.header {
|
|
116
|
+
background: linear-gradient(135deg, #4A6FA5 0%, #5B8CB3 100%);
|
|
117
|
+
color: white;
|
|
118
|
+
padding: 40px 40px;
|
|
119
|
+
text-align: center;
|
|
120
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.header h1 {
|
|
124
|
+
margin: 0;
|
|
125
|
+
font-size: 32px;
|
|
126
|
+
font-weight: 700;
|
|
127
|
+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
128
|
+
letter-spacing: 1px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.header .date {
|
|
132
|
+
margin-top: 12px;
|
|
133
|
+
font-size: 15px;
|
|
134
|
+
opacity: 0.95;
|
|
135
|
+
font-weight: 500;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.content {
|
|
139
|
+
padding: 30px 40px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.section {
|
|
143
|
+
margin-bottom: 30px;
|
|
144
|
+
padding: 0;
|
|
145
|
+
border-radius: 12px;
|
|
146
|
+
background-color: #ffffff;
|
|
147
|
+
border: 1px solid var(--border-color);
|
|
148
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
149
|
+
overflow: hidden;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.section-new {
|
|
153
|
+
border-top: 3px solid #e53e3e;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.section-seen {
|
|
157
|
+
border-top: 3px solid #3182ce;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.section-title {
|
|
161
|
+
font-size: 20px;
|
|
162
|
+
font-weight: 700;
|
|
163
|
+
padding: 20px 25px 15px;
|
|
164
|
+
margin: 0;
|
|
165
|
+
background-color: #fafafa;
|
|
166
|
+
border-bottom: 1px solid var(--border-color);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.section-new .section-title {
|
|
170
|
+
color: #e53e3e;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.section-seen .section-title {
|
|
174
|
+
color: #3182ce;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.section-title::before {
|
|
178
|
+
margin-right: 8px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.section-new .section-title::before {
|
|
182
|
+
content: "🔥";
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.section-seen .section-title::before {
|
|
186
|
+
content: "⭐";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.section-content {
|
|
190
|
+
padding: 20px 25px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.section-new .section-title {
|
|
194
|
+
color: #e53e3e;
|
|
195
|
+
border-bottom: 2px solid #e53e3e;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.section-seen .section-title {
|
|
199
|
+
color: #3182ce;
|
|
200
|
+
border-bottom: 2px solid #3182ce;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.repo-card {
|
|
204
|
+
background-color: #ffffff;
|
|
205
|
+
border: 1px solid var(--border-color);
|
|
206
|
+
border-radius: 8px;
|
|
207
|
+
padding: 20px;
|
|
208
|
+
margin-bottom: 20px;
|
|
209
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
|
210
|
+
transition: box-shadow 0.2s;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.repo-card:hover {
|
|
214
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.repo-card:last-child {
|
|
218
|
+
margin-bottom: 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.repo-header {
|
|
222
|
+
margin-bottom: 12px;
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: baseline;
|
|
225
|
+
gap: 12px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.repo-number {
|
|
229
|
+
font-size: 18px;
|
|
230
|
+
font-weight: 700;
|
|
231
|
+
color: var(--primary-color);
|
|
232
|
+
min-width: 32px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.repo-name {
|
|
236
|
+
font-size: 17px;
|
|
237
|
+
font-weight: 600;
|
|
238
|
+
color: var(--primary-color);
|
|
239
|
+
text-decoration: none;
|
|
240
|
+
transition: color 0.2s;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.repo-name:hover {
|
|
244
|
+
text-decoration: underline;
|
|
245
|
+
color: #3d5a80;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.repo-meta {
|
|
249
|
+
font-size: 12px;
|
|
250
|
+
color: var(--text-medium);
|
|
251
|
+
margin-top: 5px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.repo-lang {
|
|
255
|
+
display: inline-block;
|
|
256
|
+
padding: 2px 8px;
|
|
257
|
+
border-radius: 3px;
|
|
258
|
+
font-size: 11px;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
margin-left: 10px;
|
|
261
|
+
color: white;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.repo-desc {
|
|
265
|
+
font-size: 14px;
|
|
266
|
+
color: var(--text-dark);
|
|
267
|
+
line-height: 1.6;
|
|
268
|
+
margin: 10px 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.repo-ai-summary {
|
|
272
|
+
background-color: var(--ai-bg);
|
|
273
|
+
border-left: 4px solid var(--ai-border);
|
|
274
|
+
padding: 12px;
|
|
275
|
+
margin: 10px 0;
|
|
276
|
+
border-radius: 4px;
|
|
277
|
+
font-size: 13px;
|
|
278
|
+
line-height: 1.6;
|
|
279
|
+
color: var(--text-dark);
|
|
280
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.repo-ai-summary-title {
|
|
284
|
+
font-weight: 600;
|
|
285
|
+
color: var(--ai-title-color);
|
|
286
|
+
margin-bottom: 6px;
|
|
287
|
+
font-size: 13px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.repo-simple-summary {
|
|
291
|
+
color: var(--text-medium);
|
|
292
|
+
font-size: 13px;
|
|
293
|
+
margin: 8px 0;
|
|
294
|
+
padding-left: 12px;
|
|
295
|
+
border-left: 3px solid var(--text-light);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.repo-footer {
|
|
299
|
+
font-size: 12px;
|
|
300
|
+
color: var(--text-light);
|
|
301
|
+
margin-top: 10px;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.star-icon {
|
|
305
|
+
color: #f1c40f;
|
|
306
|
+
margin-right: 4px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.fork-icon {
|
|
310
|
+
color: #e74c3c;
|
|
311
|
+
margin-left: 15px;
|
|
312
|
+
margin-right: 4px;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.no-repos {
|
|
316
|
+
text-align: center;
|
|
317
|
+
padding: 40px;
|
|
318
|
+
color: var(--text-light);
|
|
319
|
+
font-size: 14px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.footer {
|
|
323
|
+
background-color: var(--bg-light);
|
|
324
|
+
padding: 20px 40px;
|
|
325
|
+
text-align: center;
|
|
326
|
+
font-size: 12px;
|
|
327
|
+
color: var(--text-light);
|
|
328
|
+
border-top: 1px solid var(--border-color);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.link {
|
|
332
|
+
color: var(--primary-color);
|
|
333
|
+
text-decoration: none;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* 响应式设计 */
|
|
337
|
+
@media (max-width: 600px) {
|
|
338
|
+
.container {
|
|
339
|
+
margin: 0;
|
|
340
|
+
padding: 0;
|
|
341
|
+
border-radius: 0;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.header {
|
|
345
|
+
padding: 20px;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.header h1 {
|
|
349
|
+
font-size: 24px;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.content {
|
|
353
|
+
padding: 20px;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.section {
|
|
357
|
+
padding: 15px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.repo-card {
|
|
361
|
+
padding: 12px;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.repo-name {
|
|
365
|
+
font-size: 15px;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.repo-desc {
|
|
369
|
+
font-size: 13px;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.repo-ai-summary {
|
|
373
|
+
padding: 10px;
|
|
374
|
+
font-size: 12px;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
`;
|
|
378
|
+
// Build new repositories section HTML
|
|
379
|
+
const buildReposHTML = (repos, titleText, isNew) => {
|
|
380
|
+
// 问题3:当项目数为0时不显示该模块
|
|
381
|
+
if (repos.length === 0) {
|
|
382
|
+
return '';
|
|
383
|
+
}
|
|
384
|
+
const reposHTML = repos
|
|
385
|
+
.map((repo, index) => {
|
|
386
|
+
const formattedStars = EmailChannel.formatNumberWithK(repo.stars);
|
|
387
|
+
const formattedForks = repo.forks
|
|
388
|
+
? `<span class="fork-icon" aria-hidden="true">⚡</span>${EmailChannel.formatNumberWithK(repo.forks)}`
|
|
389
|
+
: '';
|
|
390
|
+
const languageBadge = repo.language
|
|
391
|
+
? `<span class="repo-lang" style="background-color: ${EmailChannel.getLanguageColor(repo.language)}">${repo.language}</span>`
|
|
392
|
+
: '';
|
|
393
|
+
// 新上榜项目:显示详细项目介绍
|
|
394
|
+
// 持续霸榜项目:显示简化介绍(一句话)
|
|
395
|
+
const aiSummaryHTML = isNew
|
|
396
|
+
? (repo.ai_summary
|
|
397
|
+
? `<div class="repo-ai-summary" role="complementary" aria-label="项目介绍">
|
|
398
|
+
<div class="repo-ai-summary-title"><span aria-hidden="true">🤖</span> 项目介绍</div>
|
|
399
|
+
${markdown.markdownToHTML(repo.ai_summary)}
|
|
400
|
+
</div>`
|
|
401
|
+
: '')
|
|
402
|
+
: (repo.ai_summary
|
|
403
|
+
? `<div class="repo-simple-summary">${markdown.markdownToHTML(repo.ai_summary.split('。')[0] + '。')}</div>`
|
|
404
|
+
: '');
|
|
405
|
+
const repoNumber = index + 1;
|
|
406
|
+
return `
|
|
407
|
+
<article class="repo-card" aria-label="${repo.full_name} 项目详情">
|
|
408
|
+
<div class="repo-header">
|
|
409
|
+
<span class="repo-number">${repoNumber}.</span>
|
|
410
|
+
<a href="${repo.url}" class="repo-name" target="_blank" rel="noopener noreferrer" aria-label="访问 ${repo.full_name} 仓库">
|
|
411
|
+
${repo.full_name}
|
|
412
|
+
</a>
|
|
413
|
+
</div>
|
|
414
|
+
<div class="repo-meta">
|
|
415
|
+
<span class="star-icon" aria-hidden="true">★</span><span aria-label="${repo.stars} stars">${formattedStars}</span>${formattedForks}${languageBadge}
|
|
416
|
+
</div>
|
|
417
|
+
${aiSummaryHTML}
|
|
418
|
+
</article>
|
|
419
|
+
`;
|
|
420
|
+
})
|
|
421
|
+
.join('');
|
|
422
|
+
return `
|
|
423
|
+
<section class="section ${isNew ? 'section-new' : 'section-seen'}" aria-label="${titleText}">
|
|
424
|
+
<h2 class="section-title">${titleText}</h2>
|
|
425
|
+
<div class="section-content">
|
|
426
|
+
${reposHTML}
|
|
427
|
+
</div>
|
|
428
|
+
</section>
|
|
429
|
+
`;
|
|
430
|
+
};
|
|
431
|
+
const newReposHTML = buildReposHTML(newRepositories, '新上榜项目', true);
|
|
432
|
+
const seenReposHTML = buildReposHTML(seenRepositories, '持续霸榜项目', false);
|
|
433
|
+
// If no repositories, show message
|
|
434
|
+
const contentHTML = newRepositories.length === 0 && seenRepositories.length === 0
|
|
435
|
+
? `
|
|
436
|
+
<main class="content">
|
|
437
|
+
<div class="no-repos" role="status">📌 暂无 trending 项目</div>
|
|
438
|
+
</main>
|
|
439
|
+
`
|
|
440
|
+
: `
|
|
441
|
+
<main class="content">
|
|
442
|
+
${newReposHTML}
|
|
443
|
+
${seenReposHTML}
|
|
444
|
+
</main>
|
|
445
|
+
`;
|
|
446
|
+
return `
|
|
447
|
+
<!DOCTYPE html>
|
|
448
|
+
<html lang="zh-CN">
|
|
449
|
+
<head>
|
|
450
|
+
<meta charset="UTF-8">
|
|
451
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
452
|
+
<title>GitHub 热榜推送</title>
|
|
453
|
+
<style>${styles}</style>
|
|
454
|
+
</head>
|
|
455
|
+
<body>
|
|
456
|
+
<div class="container" role="main">
|
|
457
|
+
<header class="header">
|
|
458
|
+
<h1>GitHub ${sinceText}热榜推送</h1>
|
|
459
|
+
<time class="date" datetime="${currentDate.toISOString()}">${dateStr}</time>
|
|
460
|
+
</header>
|
|
461
|
+
${contentHTML}
|
|
462
|
+
<footer class="footer">
|
|
463
|
+
<p>本邮件由 GitHub 热榜机器人自动生成</p>
|
|
464
|
+
<p><a href="https://github.com/indigos" class="link" aria-label="访问 GitHub Trending 主页">GitHub Trending</a></p>
|
|
465
|
+
</footer>
|
|
466
|
+
</div>
|
|
467
|
+
</body>
|
|
468
|
+
</html>
|
|
469
|
+
`;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Format number with 'k' suffix for thousands
|
|
473
|
+
* @param num Number to format
|
|
474
|
+
* @returns Formatted string
|
|
475
|
+
*/
|
|
476
|
+
static formatNumberWithK(num) {
|
|
477
|
+
if (num >= 1000) {
|
|
478
|
+
return (num / 1000).toFixed(1) + 'k';
|
|
479
|
+
}
|
|
480
|
+
return num.toString();
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Get background color based on programming language
|
|
484
|
+
* @param language Programming language
|
|
485
|
+
* @returns Color code
|
|
486
|
+
*/
|
|
487
|
+
static getLanguageColor(language) {
|
|
488
|
+
const colors = {
|
|
489
|
+
JavaScript: '#f1e05a',
|
|
490
|
+
TypeScript: '#3178c6',
|
|
491
|
+
Python: '#3572A5',
|
|
492
|
+
Ruby: '#701516',
|
|
493
|
+
Java: '#b07219',
|
|
494
|
+
Go: '#00ADD8',
|
|
495
|
+
Rust: '#dea584',
|
|
496
|
+
Swift: '#ffac45',
|
|
497
|
+
C: '#555555',
|
|
498
|
+
'C++': '#f34b7d',
|
|
499
|
+
'C#': '#178600',
|
|
500
|
+
PHP: '#8993bd',
|
|
501
|
+
HTML: '#e34c26',
|
|
502
|
+
CSS: '#563d7c',
|
|
503
|
+
Shell: '#89e051',
|
|
504
|
+
SQL: '#e38c00',
|
|
505
|
+
Kotlin: '#A97BFF',
|
|
506
|
+
Dart: '#00B4AB'
|
|
507
|
+
};
|
|
508
|
+
return colors[language] || '#666666';
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Send email with repositories
|
|
512
|
+
* @param config Email configuration
|
|
513
|
+
* @param newRepositories Array of new repositories
|
|
514
|
+
* @param seenRepositories Array of seen repositories
|
|
515
|
+
* @param since Time period for trending (daily, weekly, monthly)
|
|
516
|
+
* @returns Push result
|
|
517
|
+
*/
|
|
518
|
+
static async send(config, newRepositories, seenRepositories, since = 'monthly') {
|
|
519
|
+
logger.info('Starting email send', {
|
|
520
|
+
since,
|
|
521
|
+
newCount: newRepositories.length,
|
|
522
|
+
seenCount: seenRepositories.length,
|
|
523
|
+
from: config.from,
|
|
524
|
+
to: config.to,
|
|
525
|
+
subject: config.subject,
|
|
526
|
+
smtpHost: config.smtp.host,
|
|
527
|
+
smtpPort: config.smtp.port
|
|
528
|
+
});
|
|
529
|
+
try {
|
|
530
|
+
logger.debug('Creating SMTP transport...');
|
|
531
|
+
const startTime = Date.now();
|
|
532
|
+
// Create transport with SMTP configuration
|
|
533
|
+
const transport = nodemailer_1.default.createTransport({
|
|
534
|
+
host: config.smtp.host,
|
|
535
|
+
port: config.smtp.port,
|
|
536
|
+
secure: config.smtp.secure,
|
|
537
|
+
auth: {
|
|
538
|
+
user: config.smtp.auth.user,
|
|
539
|
+
pass: config.smtp.auth.pass
|
|
540
|
+
},
|
|
541
|
+
logger: false,
|
|
542
|
+
debug: false
|
|
543
|
+
});
|
|
544
|
+
const transportCreateTime = Date.now();
|
|
545
|
+
logger.info('SMTP transport created', {
|
|
546
|
+
durationMs: transportCreateTime - startTime
|
|
547
|
+
});
|
|
548
|
+
// Verify SMTP connection
|
|
549
|
+
logger.debug('Verifying SMTP connection...');
|
|
550
|
+
const verified = await transport.verify();
|
|
551
|
+
const verifyDuration = Date.now() - transportCreateTime;
|
|
552
|
+
logger.info('SMTP connection verified', {
|
|
553
|
+
verified,
|
|
554
|
+
durationMs: verifyDuration
|
|
555
|
+
});
|
|
556
|
+
// Generate HTML content
|
|
557
|
+
logger.debug('Generating HTML content...');
|
|
558
|
+
const html = EmailChannel.generateHTML(newRepositories, seenRepositories, since);
|
|
559
|
+
logger.info('HTML content generated', {
|
|
560
|
+
htmlSize: html.length
|
|
561
|
+
});
|
|
562
|
+
// Send email
|
|
563
|
+
logger.info('Sending email...');
|
|
564
|
+
const sendStartTime = Date.now();
|
|
565
|
+
const info = await transport.sendMail({
|
|
566
|
+
from: config.from,
|
|
567
|
+
to: config.to,
|
|
568
|
+
subject: config.subject,
|
|
569
|
+
html: html
|
|
570
|
+
});
|
|
571
|
+
const sendDuration = Date.now() - sendStartTime;
|
|
572
|
+
logger.success('Email sent successfully', {
|
|
573
|
+
messageId: info.messageId,
|
|
574
|
+
accepted: info.accepted,
|
|
575
|
+
rejected: info.rejected,
|
|
576
|
+
pending: info.pending,
|
|
577
|
+
durationMs: sendDuration
|
|
578
|
+
});
|
|
579
|
+
return {
|
|
580
|
+
success: true,
|
|
581
|
+
messageId: info.messageId,
|
|
582
|
+
error: undefined
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
logger.error('Email send failed', {
|
|
587
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
588
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
589
|
+
});
|
|
590
|
+
return {
|
|
591
|
+
success: false,
|
|
592
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
exports.EmailChannel = EmailChannel;
|
|
598
|
+
exports.default = EmailChannel;
|
|
599
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/channels/email.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { RepositoryInfo } from '../models/repository';
|
|
2
|
+
import { PushResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Feishu Channel for pushing GitHub trending repositories
|
|
5
|
+
*/
|
|
6
|
+
export declare class FeishuChannel {
|
|
7
|
+
/**
|
|
8
|
+
* Build Feishu card message
|
|
9
|
+
* @param newRepositories Array of new repositories to display
|
|
10
|
+
* @param seenRepositories Array of seen repositories to display
|
|
11
|
+
* @param since Time period for trending
|
|
12
|
+
* @returns Feishu card object
|
|
13
|
+
*/
|
|
14
|
+
static buildCard(newRepositories: RepositoryInfo[], seenRepositories: RepositoryInfo[], since?: 'daily' | 'weekly' | 'monthly'): any;
|
|
15
|
+
/**
|
|
16
|
+
* Build a single repository card element
|
|
17
|
+
* @param repo Repository information
|
|
18
|
+
* @param index Index of repository
|
|
19
|
+
* @param isNew Whether this is a new repository
|
|
20
|
+
* @returns Feishu card element array
|
|
21
|
+
*/
|
|
22
|
+
static buildRepoElement(repo: RepositoryInfo, index: number, isNew: boolean): any[];
|
|
23
|
+
/**
|
|
24
|
+
* Get emoji icon for programming language
|
|
25
|
+
* @param language Programming language
|
|
26
|
+
* @returns Emoji icon
|
|
27
|
+
*/
|
|
28
|
+
static getLanguageEmoji(language: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Get background color based on programming language
|
|
31
|
+
* @param language Programming language
|
|
32
|
+
* @returns Color code
|
|
33
|
+
*/
|
|
34
|
+
static getLanguageColor(language: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Format number with 'k' suffix for thousands
|
|
37
|
+
* @param num Number to format
|
|
38
|
+
* @returns Formatted string
|
|
39
|
+
*/
|
|
40
|
+
static formatNumberWithK(num: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* Push repositories to Feishu webhook
|
|
43
|
+
* @param newRepositories Array of new repositories
|
|
44
|
+
* @param seenRepositories Array of seen repositories
|
|
45
|
+
* @returns Push result
|
|
46
|
+
*/
|
|
47
|
+
static push(webhookUrl: string, newRepositories: RepositoryInfo[], seenRepositories: RepositoryInfo[], since?: 'daily' | 'weekly' | 'monthly'): Promise<PushResult>;
|
|
48
|
+
}
|
|
49
|
+
export default FeishuChannel;
|
|
50
|
+
//# sourceMappingURL=feishu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKrC;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACd,eAAe,EAAE,cAAc,EAAE,EACjC,gBAAgB,EAAE,cAAc,EAAE,EAClC,KAAK,GAAE,OAAO,GAAG,QAAQ,GAAG,SAAqB,GAChD,GAAG;IAsGN;;;;;;OAMG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,GAAG,EAAE;IA2CnF;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoCjD;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoCjD;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAO7C;;;;;OAKG;WACU,IAAI,CACf,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,cAAc,EAAE,EACjC,gBAAgB,EAAE,cAAc,EAAE,EAClC,KAAK,GAAE,OAAO,GAAG,QAAQ,GAAG,SAAqB,GAChD,OAAO,CAAC,UAAU,CAAC;CA4EvB;AAED,eAAe,aAAa,CAAC"}
|