项目文件夹

文件
wehub-resource-sync 9b395f5cc3
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
Build Chrome Extension / build (push) Has been cancelled
Trigger Website Rebuild (Docs Updated) / dispatch (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:48 +08:00

187 行
8.1 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
import { clamp } from '../_shared/common.js';
const clampLimit = (limit) => clamp(limit || 20, 1, 50);
export function buildSinaBlogSearchUrl(keyword) {
return `https://search.sina.com.cn/search?q=${encodeURIComponent(keyword)}&tp=mix`;
}
export function buildSinaBlogUserUrl(uid) {
return `https://blog.sina.com.cn/s/articlelist_${encodeURIComponent(uid)}_0_1.html`;
}
export async function loadSinaBlogArticle(page, url) {
await page.goto(url);
await page.wait({ selector: 'h1', timeout: 3 });
return page.evaluate(`
(async () => {
await new Promise((resolve) => setTimeout(resolve, 1500));
const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
const title = normalize(document.querySelector('.articalTitle h2, .title h2, h1, h2.titName')?.textContent);
const titleParts = normalize(document.title).split('_').map((part) => normalize(part)).filter(Boolean);
const author = titleParts[1] || title.split(/[:]/)[0] || '';
const timeText = normalize(document.querySelector('.time, .articalInfo .time')?.textContent).replace(/[()]/g, '');
const date = timeText || normalize(document.body.innerText.match(/\\b\\d{4}-\\d{2}-\\d{2}(?:\\s+\\d{2}:\\d{2}:\\d{2})?\\b/)?.[0]);
const category = normalize(document.querySelector('.articalTag .blog_class a, .blog_class a')?.textContent);
const tags = Array.from(document.querySelectorAll('.blog_tag h3, .blog_tag a, .tag a, .artical_tag a'))
.map((node) => normalize(node.textContent))
.filter(Boolean);
const content = normalize(document.querySelector('.articalContent, .blog_content, .content, #sina_keyword_ad_area2')?.textContent).slice(0, 500);
const images = Array.from(document.querySelectorAll('.articalContent img, .blog_content img, .content img'))
.map((img) => img.getAttribute('src') || img.getAttribute('real_src') || '')
.filter((src) => src && !src.includes('icon'))
.slice(0, 5);
return {
title,
author,
date,
category,
tags: tags.join(', '),
readCount: '',
commentCount: '',
content: content + (content.length >= 500 ? '...' : ''),
images: images.join(', '),
url: ${JSON.stringify(url)},
};
})()
`);
}
export async function loadSinaBlogHot(page, limit) {
const safeLimit = clampLimit(limit);
await page.goto('https://blog.sina.com.cn/');
await page.wait({ selector: 'h1', timeout: 3 });
const data = await page.evaluate(`
(async () => {
await new Promise((resolve) => setTimeout(resolve, 1500));
const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
const limit = ${safeLimit};
const abs = (href) => {
if (!href) return '';
if (href.startsWith('//')) return 'https:' + href;
if (href.startsWith('http')) return href;
return 'https://blog.sina.com.cn' + (href.startsWith('/') ? '' : '/') + href;
};
const parseArticle = (doc, fallback) => {
const title = normalize(doc.querySelector('.articalTitle h2, .title h2, h1, h2.titName')?.textContent) || fallback.title;
const titleParts = normalize(doc.title).split('_').map((part) => normalize(part)).filter(Boolean);
const timeText = normalize(doc.querySelector('.time, .articalInfo .time')?.textContent).replace(/[()]/g, '');
const articleId = fallback.url.match(/blog_([a-zA-Z0-9]+)\\.html/)?.[1] || '';
return {
articleId,
title,
author: titleParts[1] || title.split(/[:]/)[0] || '',
date: timeText || '',
readCount: '',
description: normalize(doc.querySelector('.articalContent, .blog_content, .content, #sina_keyword_ad_area2')?.textContent).slice(0, 150),
};
};
const seeds = [];
const seen = new Set();
for (const link of Array.from(document.querySelectorAll('.day-hot-rank .art-list a[href*="/s/blog_"], .hot-rank .art-list a[href*="/s/blog_"]'))) {
const title = normalize(link.textContent);
const url = abs(link.getAttribute('href') || '');
if (!title || !url || seen.has(url)) continue;
seen.add(url);
seeds.push({ rank: seeds.length + 1, title, url });
if (seeds.length >= limit) break;
}
const results = [];
for (const item of seeds) {
let merged = {
rank: item.rank,
articleId: item.url.match(/blog_([a-zA-Z0-9]+)\\.html/)?.[1] || '',
title: item.title,
author: '',
date: '',
readCount: '',
description: '',
url: item.url,
};
try {
const resp = await fetch(item.url, { credentials: 'include' });
if (resp.ok) {
const html = await resp.text();
const doc = new DOMParser().parseFromString(html, 'text/html');
merged = Object.assign(merged, parseArticle(doc, item));
}
} catch {}
results.push(merged);
}
return results;
})()
`);
return Array.isArray(data) ? data : [];
}
export async function loadSinaBlogSearch(page, keyword, limit) {
const safeLimit = clampLimit(limit);
await page.goto(buildSinaBlogSearchUrl(keyword));
await page.wait({ selector: '.result-item', timeout: 5 });
const data = await page.evaluate(`
(async () => {
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
for (let i = 0; i < 20; i += 1) {
if (document.querySelector('.result-item')) break;
await sleep(500);
}
const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
const limit = ${safeLimit};
const items = Array.from(document.querySelectorAll('.result-item'));
const results = [];
for (const item of items) {
const link = item.querySelector('.result-title a[href*="blog.sina.com.cn/s/blog_"]');
const title = normalize(link?.textContent);
const url = link?.getAttribute('href') || '';
if (!title || !url) continue;
results.push({
rank: results.length + 1,
title,
author: normalize(item.querySelector('.result-meta .source')?.textContent),
date: normalize(item.querySelector('.result-meta .time')?.textContent),
description: normalize(item.querySelector('.result-intro')?.textContent).slice(0, 150),
url,
});
if (results.length >= limit) break;
}
return results;
})()
`);
return Array.isArray(data) ? data : [];
}
export async function loadSinaBlogUser(page, uid, limit) {
const safeLimit = clampLimit(limit);
await page.goto(buildSinaBlogUserUrl(uid));
await page.wait({ selector: 'h1', timeout: 3 });
const data = await page.evaluate(`
(async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
const limit = ${safeLimit};
const author = normalize(document.title).split('_').map((part) => normalize(part)).filter(Boolean)[1] || '';
const abs = (href) => {
if (!href) return '';
if (href.startsWith('//')) return 'https:' + href;
if (href.startsWith('http')) return href;
return 'https://blog.sina.com.cn' + (href.startsWith('/') ? '' : '/') + href;
};
const results = [];
for (const item of Array.from(document.querySelectorAll('.articleList .articleCell'))) {
const link = item.querySelector('.atc_title a[href*="/s/blog_"]');
const title = normalize(link?.textContent);
const url = abs(link?.getAttribute('href') || '');
if (!title || !url) continue;
results.push({
rank: results.length + 1,
articleId: url.match(/blog_([a-zA-Z0-9]+)\\.html/)?.[1] || '',
title,
author,
date: normalize(item.querySelector('.atc_tm')?.textContent),
readCount: '',
description: '',
url,
});
if (results.length >= limit) break;
}
return results;
})()
`);
return Array.isArray(data) ? data : [];
}