Skip to content

Commit 7f497a3

Browse files
committed
feat(route/youmemark): add user bookmarks
1 parent 71e4e6c commit 7f497a3

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

lib/routes/youmemark/index.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { Route, Data } from '@/types';
2+
import ofetch from '@/utils/ofetch';
3+
import { parseDate } from '@/utils/parse-date';
4+
import { load } from 'cheerio';
5+
6+
export const route: Route = {
7+
path: '/:userid',
8+
categories: ['blog'],
9+
example: '/youmemark/Cds2gZ2HIDdS41IfC6kzE1DL9Su1MqUp',
10+
parameters: { userid: '`userid` is the user id of youmemark' },
11+
features: {
12+
requireConfig: false,
13+
requirePuppeteer: false,
14+
antiCrawler: false,
15+
supportBT: false,
16+
supportPodcast: false,
17+
supportScihub: false,
18+
},
19+
name: 'Bookmarks',
20+
maintainers: ['pseudoyu'],
21+
handler,
22+
radar: [
23+
{
24+
source: ['youmemark.com/user/:userid'],
25+
},
26+
],
27+
description: `Get user's public bookmarks from YouMeMark
28+
::: tip
29+
Add \`?limit=<number>\` to the end of the route to limit the number of items. Default is 10.
30+
:::`,
31+
};
32+
33+
async function handler(ctx): Promise<Data> {
34+
const userid = ctx.req.param('userid');
35+
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
36+
37+
const response = await ofetch(`https://youmemark.com/user/${userid}`, {
38+
headers: {
39+
'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',
40+
},
41+
});
42+
43+
const $ = load(response);
44+
45+
// Extract user info from the profile section
46+
const name = $('h2.font-bold').text().trim();
47+
const avatar = $('span.relative.flex img').attr('src');
48+
const intro = $('.text-sm p').text().trim();
49+
50+
// Extract bookmarks from the bookmarks section
51+
const items: Data['item'] = [];
52+
$('div.flex.flex-col.gap-2').each((_, element) => {
53+
const $item = $(element);
54+
const $divs = $item.children('div');
55+
if ($divs.length < 2) {
56+
return;
57+
}
58+
59+
const $firstDiv = $divs.eq(0);
60+
const $link = $firstDiv.find('a').first();
61+
const $domain = $firstDiv.find('span').first();
62+
63+
// Check for blockquote content
64+
let content = '';
65+
if ($divs.length >= 3) {
66+
const $contentDiv = $divs.eq(1);
67+
const $blockquote = $contentDiv.find('blockquote');
68+
if ($blockquote.length) {
69+
content = $blockquote.text().trim();
70+
}
71+
}
72+
73+
const $dateDiv = $divs.eq(-1);
74+
75+
if (!$link.length || !$dateDiv.length) {
76+
return;
77+
}
78+
79+
const link = $link.attr('href');
80+
const title = $link.text().trim();
81+
const domain = $domain.text().trim().replaceAll(/[()]/g, '');
82+
const dateStr = $dateDiv.text().trim();
83+
84+
if (link && title && dateStr) {
85+
const description = content || `${title} (${domain})`;
86+
87+
items.push({
88+
title,
89+
link,
90+
description,
91+
pubDate: parseDate(dateStr, 'YYYY-MM-DD HH:mm'),
92+
author: domain,
93+
guid: link,
94+
});
95+
}
96+
});
97+
98+
return {
99+
title: `${name}'s Bookmarks - YouMeMark`,
100+
link: `https://youmemark.com/user/${userid}`,
101+
description: intro,
102+
image: avatar,
103+
item: items.slice(0, limit),
104+
language: 'en',
105+
} as Data;
106+
}

lib/routes/youmemark/namespace.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { Namespace } from '@/types';
2+
3+
export const namespace: Namespace = {
4+
name: 'YouMeMark',
5+
url: 'youmemark.com',
6+
lang: 'zh-CN',
7+
};

0 commit comments

Comments
 (0)