Add desk lock mode, web bookmark card type, sound default, and buried visual effects
This commit is contained in:
1 parent
15fbe1db88
commit
19eb968f86
7 files changed
+493
-187
No files matched your search
@@ -187,6 +187,80 @@ app.post('/api/upload', upload.single('file'), (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// Bookmark web page metadata preview extractor
|
||||
app.get('/api/bookmark-meta', async (req, res) => {
|
||||
const targetUrl = req.query.url;
|
||||
if (!targetUrl || typeof targetUrl !== 'string') {
|
||||
return res.status(400).json({ success: false, error: 'url parameter required' });
|
||||
}
|
||||
|
||||
let validUrl;
|
||||
try {
|
||||
validUrl = new URL(targetUrl.startsWith('http') ? targetUrl : `https://${targetUrl}`);
|
||||
} catch {
|
||||
return res.status(400).json({ success: false, error: 'Invalid URL format' });
|
||||
}
|
||||
|
||||
const hostname = validUrl.hostname;
|
||||
const favicon = `https://www.google.com/s2/favicons?domain=${encodeURIComponent(hostname)}&sz=128`;
|
||||
const mshotsScreenshot = `https://s0.wp.com/mshots/v1/${encodeURIComponent(validUrl.href)}?w=600`;
|
||||
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 4000);
|
||||
|
||||
const response = await fetch(validUrl.href, {
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
'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',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||
}
|
||||
});
|
||||
clearTimeout(timeout);
|
||||
|
||||
const html = await response.text();
|
||||
|
||||
// Extract title
|
||||
const ogTitleMatch = html.match(/<meta\s+property=["']og:title["']\s+content=["'](.*?)["']/i) ||
|
||||
html.match(/<meta\s+content=["'](.*?)["']\s+property=["']og:title["']/i);
|
||||
const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
|
||||
const title = ogTitleMatch?.[1] || titleMatch?.[1] || hostname;
|
||||
|
||||
// Extract description
|
||||
const ogDescMatch = html.match(/<meta\s+property=["']og:description["']\s+content=["'](.*?)["']/i) ||
|
||||
html.match(/<meta\s+name=["']description["']\s+content=["'](.*?)["']/i);
|
||||
const description = ogDescMatch?.[1] || '';
|
||||
|
||||
// Extract image
|
||||
const ogImageMatch = html.match(/<meta\s+property=["']og:image["']\s+content=["'](.*?)["']/i) ||
|
||||
html.match(/<meta\s+content=["'](.*?)["']\s+property=["']og:image["']/i);
|
||||
let image = ogImageMatch?.[1] || mshotsScreenshot;
|
||||
if (image && image.startsWith('/')) {
|
||||
image = `${validUrl.origin}${image}`;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
url: validUrl.href,
|
||||
hostname,
|
||||
title: title.trim(),
|
||||
description: description.trim(),
|
||||
image,
|
||||
favicon
|
||||
});
|
||||
} catch {
|
||||
res.json({
|
||||
success: true,
|
||||
url: validUrl.href,
|
||||
hostname,
|
||||
title: hostname,
|
||||
description: '',
|
||||
image: mshotsScreenshot,
|
||||
favicon
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Serve uploaded photos/media
|
||||
app.use('/uploads', express.static(UPLOADS_DIR, {
|
||||
maxAge: '7d',
|
||||
|
||||
Reference in new issue
Block a user