红袖添香

https://www.hongxiu.com

zpccool (13551) 16小时前 下载:320

小说
红袖添香小说网 - 免费无弹窗小说阅读(已过滤作品相关)
二维码导入(APP尚未完成该功能)
// @name        红袖添香
// @uuid        hongxiutianxiang
// @version     1.0.0
// @author      AI
// @url         https://www.hongxiu.com
// @type        novel
// @enabled     true
// @description 红袖添香小说网 - 免费无弹窗小说阅读(已过滤作品相关)

var BASE = 'https://www.hongxiu.com';
var SEARCH_BASE = 'https://www.hongxiu.com';
var EXPLORE_BASE = 'https://www.hongxiu.com';
var BOOK_BASE = 'https://www.hongxiu.com';

var GENRE_MAP = {
    '现代言情': '30020',
    '古代言情': '30013',
    '浪漫青春': '30031',
    '玄幻言情': '30001',
    '仙侠奇缘': '30008',
    '悬疑': '30036',
    '科幻空间': '30042',
    '游戏竞技': '30050',
    '短篇小说': '30083',
    '轻小说': '30055'
};

var GENRE_LIST = Object.keys(GENRE_MAP);

function _trim(s) {
    if (!s) return '';
    return String(s).replace(/^[\s\u3000\u00A0]+|[\s\u3000\u00A0]+$/g, '').trim();
}

async function search(keyword, page) {
    legado.log('[search] keyword=' + keyword + ' page=' + page);
    var result = [];

    var url = SEARCH_BASE + '/so/' + encodeURIComponent(keyword);
    var html = await legado.http.get(url);

    legado.log('[search] html length=' + (html ? html.length : 'null'));
    if (!html || html.length < 500) {
        return result;
    }

    var doc = legado.dom.parse(html);
    var listItems = legado.dom.selectAll(doc, '#result-list li');

    legado.log('[search] listItems count=' + (listItems ? listItems.length : 0));

    for (var i = 0; i < listItems.length; i++) {
        var item = listItems[i];

        var bookBox = legado.dom.select(item, '.book-img-box');
        var bookLink = bookBox ? legado.dom.select(bookBox, 'a') : null;
        var bookUrl = bookLink ? legado.dom.attr(bookLink, 'href') || '' : '';
        var coverEl = bookBox ? legado.dom.select(bookBox, 'img') : null;
        var coverUrl = coverEl ? legado.dom.attr(coverEl, 'src') || '' : '';

        var midInfo = legado.dom.select(item, '.book-mid-info');
        var titleEl = midInfo ? legado.dom.select(midInfo, 'h4 a') : null;
        var name = titleEl ? legado.dom.text(titleEl) : '';
        name = name.replace(/<[^>]+>/g, '').trim();

        var authorEl = midInfo ? legado.dom.select(midInfo, 'a.name') : null;
        var author = authorEl ? legado.dom.text(authorEl) : '';

        var kindEl = midInfo ? legado.dom.select(midInfo, 'a[href*="/category/"]') : null;
        var kind = kindEl ? legado.dom.text(kindEl) : '';

        var introEl = midInfo ? legado.dom.select(midInfo, 'p.intro') : null;
        var intro = introEl ? legado.dom.text(introEl) : '';

        legado.log('[search] item ' + i + ': name=' + name + ' author=' + author + ' url=' + bookUrl);

        if (bookUrl && name) {
            if (bookUrl.indexOf('http') !== 0) {
                bookUrl = SEARCH_BASE + bookUrl;
            }
            if (coverUrl && coverUrl.indexOf('//') === 0) {
                coverUrl = 'https:' + coverUrl;
            }

            result.push({
                name: _trim(name),
                author: _trim(author),
                bookUrl: bookUrl,
                coverUrl: coverUrl,
                intro: _trim(intro),
                kind: _trim(kind),
                lastChapter: ''
            });
        }
    }

    legado.log('[search] found=' + result.length);
    legado.dom.free(doc);
    return result;
}

async function bookInfo(bookUrl) {
    legado.log('[bookInfo] url=' + bookUrl);

    if (bookUrl.indexOf('m.xxsy.net') >= 0) {
        bookUrl = bookUrl.replace('m.xxsy.net', 'www.hongxiu.com');
        legado.log('[bookInfo] converted to pc: ' + bookUrl);
    }

    var result = {
        name: '',
        author: '',
        bookUrl: bookUrl,
        coverUrl: '',
        intro: '',
        kind: '',
        lastChapter: '',
        wordCount: '',
        tocUrl: bookUrl
    };

    var html = await legado.http.get(bookUrl);

    if (!html || html.length < 500) {
        return result;
    }

    var doc = legado.dom.parse(html);

    var nameEl = legado.dom.select(doc, 'h1.book-title');
    if (nameEl) {
        result.name = _trim(legado.dom.text(nameEl));
    }
    if (!result.name) {
        var nameEl2 = legado.dom.select(doc, '.book-info h1');
        if (nameEl2) {
            result.name = _trim(legado.dom.text(nameEl2));
        }
    }

    var authorEl = legado.dom.select(doc, 'span.book-author');
    if (authorEl) {
        result.author = _trim(legado.dom.text(authorEl));
    }

    var coverEl = legado.dom.select(doc, '.book-img img');
    if (coverEl) {
        result.coverUrl = legado.dom.attr(coverEl, 'src') || legado.dom.attr(coverEl, 'data-src') || '';
        if (result.coverUrl && result.coverUrl.indexOf('//') === 0) {
            result.coverUrl = 'https:' + result.coverUrl;
        }
    }

    var introEl = legado.dom.select(doc, 'p.book-intro');
    if (introEl) {
        result.intro = _trim(legado.dom.text(introEl));
    }
    if (!result.intro) {
        var introEl2 = legado.dom.select(doc, '.book-desc');
        if (introEl2) {
            result.intro = _trim(legado.dom.text(introEl2));
        }
    }

    var kindEl = legado.dom.select(doc, 'a.tag');
    if (kindEl) {
        result.kind = _trim(legado.dom.text(kindEl));
    }

    var lastChEl = legado.dom.select(doc, '.book-chapter a.chapterName');
    if (lastChEl) {
        result.lastChapter = _trim(legado.dom.text(lastChEl));
    }

    var tocLink = legado.dom.select(doc, '#j_catalogPage');
    if (tocLink) {
        var tocHref = legado.dom.attr(tocLink, 'href');
        if (tocHref) {
            result.tocUrl = tocHref.indexOf('http') === 0 ? tocHref : BOOK_BASE + tocHref;
        }
    } else {
        var tocLink2 = legado.dom.select(doc, '.j_catalog_block a');
        if (tocLink2) {
            var tocHref = legado.dom.attr(tocLink2, 'href');
            if (tocHref) {
                result.tocUrl = tocHref.indexOf('http') === 0 ? tocHref : BOOK_BASE + tocHref;
            }
        }
    }

    legado.log('[bookInfo] name=' + result.name + ' author=' + result.author);
    legado.dom.free(doc);
    return result;
}

async function chapterList(tocUrl) {
    legado.log('[chapterList] url=' + tocUrl);
    var result = [];

    if (tocUrl.indexOf('m.xxsy.net') >= 0) {
        tocUrl = tocUrl.replace('m.xxsy.net', 'www.hongxiu.com');
        legado.log('[chapterList] converted to pc: ' + tocUrl);
    }

    if (tocUrl.indexOf('chapterlist') >= 0) {
        var bookUrl = tocUrl.replace('/chapterlist/', '/book/');
        legado.log('[chapterList] try book page: ' + bookUrl);
        var pcResult = await chapterList(bookUrl);
        if (pcResult && pcResult.length > 0) {
            return pcResult;
        }
    }

    var html = await legado.http.get(tocUrl);

    if (!html || html.length < 500) {
        return result;
    }

    // ---------- 新增:移除“作品相关”分卷的全部内容 ----------
    var h3Pattern = /<h3[^>]*>[\s\S]*?<\/h3>/g;
    var h3Positions = [];
    var match;
    while ((match = h3Pattern.exec(html)) !== null) {
        h3Positions.push({ index: match.index, text: match[0].replace(/<[^>]+>/g, '').trim() });
    }

    var cleanedHtml = html;
    var removeRanges = [];
    for (var i = 0; i < h3Positions.length; i++) {
        if (h3Positions[i].text.indexOf('作品相关') !== -1) {
            var start = h3Positions[i].index;
            var end = (i + 1 < h3Positions.length) ? h3Positions[i + 1].index : html.length;
            removeRanges.push({ start: start, end: end });
        }
    }

    // 从后往前删除,避免索引错乱
    for (var j = removeRanges.length - 1; j >= 0; j--) {
        cleanedHtml = cleanedHtml.substring(0, removeRanges[j].start) + cleanedHtml.substring(removeRanges[j].end);
    }
    // ---------- 结束 ----------

    var doc = legado.dom.parse(cleanedHtml);

    // 原有逻辑:寻找“正文”分卷,进一步缩小范围(如果存在)
    var zhengwenStart = -1;
    var h3Matches = cleanedHtml.match(/<h3[^>]*>[\s\S]*?<\/h3>/g);
    if (h3Matches) {
        for (var i = 0; i < h3Matches.length; i++) {
            var h3Text = h3Matches[i].replace(/<[^>]+>/g, '').replace(/&[^;]+;/g, '');
            if (h3Text.indexOf('正文') >= 0) {
                zhengwenStart = cleanedHtml.indexOf(h3Matches[i]);
                break;
            }
        }
    }

    if (zhengwenStart > 0) {
        var afterZhengwen = cleanedHtml.substring(zhengwenStart);
        var nextH3 = afterZhengwen.indexOf('<h3');
        var zhengwenSection;
        if (nextH3 > 0) {
            zhengwenSection = afterZhengwen.substring(0, nextH3);
        } else {
            zhengwenSection = afterZhengwen;
        }

        var liMatches = zhengwenSection.match(/<li[^>]*><a[^>]*href="([^"]+)"[^>]*>([^<]+)<\/a>/g);
        if (liMatches) {
            for (var i = 0; i < liMatches.length; i++) {
                var m = liMatches[i].match(/href="([^"]+)"[^>]*>([^<]+)/);
                if (m && m[1] && m[2]) {
                    var url = m[1];
                    var name = _trim(m[2]);
                    if (_isValidChapter(url, name)) {
                        if (url.indexOf('http') !== 0) {
                            url = BOOK_BASE + url;
                        }
                        result.push({ name: name, url: url });
                    }
                }
            }
        }
    }

    // 如果上一步没提取到章节,则提取全部列表(此时已无“作品相关”)
    if (result.length === 0) {
        var chapterItems = legado.dom.selectAll(doc, 'ul.j_catalogList li');
        if (!chapterItems || chapterItems.length === 0) {
            chapterItems = legado.dom.selectAll(doc, 'ul li');
        }
        for (var k = 0; k < chapterItems.length; k++) {
            var item = chapterItems[k];
            var linkEl = legado.dom.select(item, 'a');
            if (!linkEl) continue;

            var chapterUrl = legado.dom.attr(linkEl, 'href');
            var chapterName = legado.dom.text(linkEl);

            if (_isValidChapter(chapterUrl, chapterName)) {
                if (chapterUrl.indexOf('http') !== 0) {
                    chapterUrl = BOOK_BASE + chapterUrl;
                }
                result.push({ name: _trim(chapterName), url: chapterUrl });
            }
        }
    }

    legado.log('[chapterList] found=' + result.length);
    legado.dom.free(doc);
    return result;
}

function _isValidChapter(url, name) {
    if (!url || !name || name.length < 2) return false;
    if (url.indexOf('javascript') >= 0) return false;
    if (url.indexOf('/category') >= 0) return false;
    if (url.indexOf('/rank') >= 0) return false;
    if (url.indexOf('/free') >= 0) return false;
    if (url.indexOf('/chapter/') < 0) return false;
    var chapterNumMatch = url.match(/\/(\d+)$/);
    if (!chapterNumMatch) return false;
    var lowerName = name.toLowerCase();
    if (lowerName.indexOf('新书') >= 0) return false;
    if (lowerName.indexOf('试阅') >= 0) return false;
    if (lowerName.indexOf('手游') >= 0) return false;
    if (lowerName.indexOf('公测') >= 0) return false;
    if (lowerName.indexOf('服务器') >= 0) return false;
    if (lowerName.indexOf('玄界之门') >= 0) return false;
    if (lowerName.indexOf('魔天记') >= 0) return false;
    if (lowerName.indexOf('最新章节') >= 0) return false;
    if (lowerName.indexOf('推荐总榜') >= 0) return false;
    if (lowerName.indexOf('不到') >= 0 && lowerName.indexOf('票') >= 0) return false;
    return true;
}

async function chapterContent(chapterUrl) {
    legado.log('[chapterContent] url=' + chapterUrl);
    var content = '';

    var html = await legado.http.get(chapterUrl);

    if (!html || html.length < 200) {
        return content;
    }

    var doc = legado.dom.parse(html);
    var contentEl = legado.dom.select(doc, '.j_readContent');

    if (contentEl) {
        var lines = [];
        var ps = legado.dom.selectAll(contentEl, 'p');
        if (ps && ps.length > 0) {
            for (var i = 0; i < ps.length; i++) {
                var line = _trim(legado.dom.text(ps[i]));
                if (line) {
                    lines.push(line);
                }
            }
        }
        if (lines.length > 0) {
            content = lines.join('\n\n');
        } else {
            content = _trim(legado.dom.text(contentEl));
        }
    }

    if (!content) {
        var contentEl2 = legado.dom.select(doc, '.ywskythunderfont');
        if (contentEl2) {
            content = _trim(legado.dom.text(contentEl2));
        }
    }

    content = content.replace(/window\.[a-zA-Z0-9=]+/, '').trim();
    content = content.replace(/=\s*"[^"]*"\s*;?\s*$/, '').trim();
    content = content.replace(/\s*=\s*$/, '').trim();
    content = content.replace(/\s+$/, '');

    legado.log('[chapterContent] length=' + content.length);
    legado.dom.free(doc);
    return content;
}

async function explore(category, page) {
    legado.log('[explore] page=' + page + ' category=' + category);

    if (typeof category === 'number') {
        var temp = category;
        category = page;
        page = temp;
    }

    if (category === 'GETALL' || category === undefined || category === null) {
        return GENRE_LIST.slice();
    }

    var result = [];
    var slug = GENRE_MAP[category];
    if (!slug) {
        legado.log('[explore] unknown category: ' + category);
        return result;
    }

    var p = page && page > 1 ? page : 1;
    var url = EXPLORE_BASE + '/category/' + slug + '_f1_f1_f1_f1_f1_0_' + p;
    legado.log('[explore] url=' + url);

    var html = await legado.http.get(url);

    if (!html || html.length < 500) {
        return result;
    }

    var doc = legado.dom.parse(html);
    var bookItems = legado.dom.selectAll(doc, '.all-pro-wrap li');

    for (var i = 0; i < bookItems.length; i++) {
        var item = bookItems[i];
        var linkEl = legado.dom.select(item, '.book-info h3 a');
        if (!linkEl) continue;

        var bookUrl = legado.dom.attr(linkEl, 'href');
        var name = legado.dom.attr(linkEl, 'title') || legado.dom.text(linkEl);

        var authorEl = legado.dom.select(item, '.book-info h4 a');
        var author = authorEl ? legado.dom.text(authorEl) : '';

        var coverEl = legado.dom.select(item, '.book-img img');
        var coverUrl = coverEl ? legado.dom.attr(coverEl, 'src') || '' : '';

        var introEl = legado.dom.select(item, '.book-info p.intro');
        var intro = introEl ? legado.dom.text(introEl) : '';

        var tagEls = legado.dom.selectAll(item, '.book-info p.tag span');
        var kind = '';
        var wordCount = '';
        if (tagEls && tagEls.length > 0) {
            kind = legado.dom.text(tagEls[0]);
        }
        if (tagEls && tagEls.length > 2) {
            wordCount = legado.dom.text(tagEls[2]);
        }

        if (bookUrl && name) {
            if (bookUrl.indexOf('http') !== 0) {
                bookUrl = BASE + bookUrl;
            }
            if (coverUrl && coverUrl.indexOf('//') === 0) {
                coverUrl = 'https:' + coverUrl;
            }

            result.push({
                name: _trim(name),
                author: _trim(author),
                bookUrl: bookUrl,
                coverUrl: coverUrl,
                intro: _trim(intro),
                kind: _trim(kind),
                wordCount: _trim(wordCount),
                lastChapter: ''
            });
        }
    }

    legado.log('[explore] found=' + result.length);
    legado.dom.free(doc);
    return result;
}

function init() {
    legado.log('[init] 红袖添香 book source loaded');
}
广告