pub const JS: &str = r#"(() => {
const loginWallPattern = /登录后查看|请登录|登录后/;
const notFoundPattern = /页面不见了|笔记不存在|无法浏览|内容已删除/;
const bodyText = document.body ? document.body.innerText : '';
const loginWall = loginWallPattern.test(bodyText);
const notFound = notFoundPattern.test(bodyText);
if (loginWall || notFound) {
return { loginWall, notFound };
}
try {
const state = window.__INITIAL_STATE__;
if (!state || !state.note || !state.note.noteDetailMap) {
return { loginWall, notFound, error: "noteDetailMap not found in __INITIAL_STATE__" };
}
const noteDetailMap = state.note.noteDetailMap;
const keys = Object.keys(noteDetailMap);
if (keys.length === 0) {
return { loginWall, notFound, error: "noteDetailMap is empty" };
}
const entry = noteDetailMap[keys[0]];
const note = entry && (entry.note || entry);
if (!note) {
return { loginWall, notFound, error: "note entry is null or undefined" };
}
// Basic fields
const id = note.noteId || note.id || '';
const title = note.title || '';
const content = note.desc || note.content || '';
// Author
const user = note.user || {};
const author = user.nickname || user.name || '';
const authorId = user.userId || user.id || '';
// Interact info
const interactInfo = note.interactInfo || {};
function parseCount(val) {
if (!val) return 0;
if (typeof val === 'number') return val;
const s = String(val).replace(/[^\d]/g, '');
return s ? parseInt(s, 10) : 0;
}
const likes = parseCount(interactInfo.likedCount);
const collects = parseCount(interactInfo.collectedCount);
const comments = parseCount(interactInfo.commentCount);
const shares = parseCount(interactInfo.shareCount);
// Tags
const tagList = note.tagList || [];
const tags = tagList.map(t => t.name || t.text || t).filter(t => typeof t === 'string' && t.length > 0);
// Images — prefer highest resolution from infoList
const imageList = note.imageList || [];
const images = imageList.map(img => {
const infoList = img.infoList || [];
if (infoList.length > 0) {
// Sort by width descending, take the best
const sorted = infoList.slice().sort((a, b) => (b.width || 0) - (a.width || 0));
return sorted[0].url || '';
}
return img.url || img.urlDefault || '';
}).filter(u => u.length > 0);
// Video URL — check note.video with stream/h264 priority
let video = null;
const CDN_PREFIX = 'https://sns-video-bd.xhscdn.com/';
const videoData = note.video || {};
if (videoData) {
// Try stream.h264 first
const stream = videoData.stream || {};
const h264List = stream.h264 || [];
if (h264List.length > 0) {
video = h264List[0].masterUrl || h264List[0].backupUrls && h264List[0].backupUrls[0] || null;
}
// Fallback: try video.url
if (!video && videoData.url) {
video = videoData.url;
}
// Fallback: originVideoKey with CDN prefix
if (!video && videoData.originVideoKey) {
video = CDN_PREFIX + videoData.originVideoKey;
}
}
// Note type
const noteType = note.type || note.noteType || 'normal';
// Published at — decode from MongoDB ObjectID (first 8 hex chars = unix timestamp)
let publishedAt = '';
if (id && id.length >= 8) {
try {
const ts = parseInt(id.substring(0, 8), 16) * 1000;
if (!isNaN(ts)) publishedAt = new Date(ts).toISOString().split('T')[0];
} catch (e) {}
}
return {
loginWall,
notFound,
note: {
id,
title,
content,
author,
authorId,
likes,
collects,
comments,
shares,
tags,
images,
video,
publishedAt,
noteType,
}
};
} catch (e) {
return { loginWall, notFound, error: String(e) };
}
})()
"#;