tail-fin-xhs 0.7.8

Xiaohongshu adapter for tail-fin: search, notes, comments, feed
Documentation
pub const JS: &str = r#"(() => {
    const loginWall = /登录后查看|请登录|登录后/.test(document.body.innerText);
    const notFound = /用户不存在|页面不见了/.test(document.body.innerText);
    if (loginWall) return { loginWall: true, notFound: false, notes: [] };
    if (notFound) return { loginWall: false, notFound: true, notes: [] };

    const state = window.__INITIAL_STATE__;
    if (!state) return { loginWall: false, notFound: false, notes: [] };

    const userState = state.user || {};
    let rawNotes = [];
    if (userState.notes) {
        const n = userState.notes;
        if (n._value && Array.isArray(n._value)) {
            rawNotes = n._value;
        } else if (Array.isArray(n)) {
            rawNotes = n;
        }
    }

    const notes = rawNotes.map(item => {
        const card = item.noteCard || item;
        const id = card.noteId || card.id || '';
        const title = card.displayTitle || card.title || '';
        const likes = (card.interactInfo && card.interactInfo.likedCount) ? Number(card.interactInfo.likedCount) : 0;
        const noteType = card.type || card.noteType || 'normal';
        const coverImage = (card.cover && (card.cover.urlDefault || card.cover.url)) || null;
        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 { id, title, likes, noteType, coverImage, publishedAt };
    }).filter(n => n.id);

    return { loginWall: false, notFound: false, notes };
})()"#;