// ==UserScript== // @name 阿豆影视界面适配 // @namespace https://scriptcat.org/zh-CN/ // @run-at document-start // @match *://movie.douban.com/tv* // @match *://movie.douban.com/explore* // @match *://movie.douban.com/subject/* // @match *://movie.douban.com/ // @match *://m.douban.com/tv* // @match *://m.douban.com/movie* // @match *://search.douban.com/movie/subject_search* // @match *://www.douban.com/doubanapp/dispatch* // @grant none // @author 失辛向南 // @version 5.8.9 // @description 优化豆瓣影视页面(TV/探索/搜索)的显示与交互,支持移动端/PC端自适应重定向、自动加载更多内容及页面布局适配。 // @license MIT // ==/UserScript== (function() { 'use strict'; const DEBUG = false; function log(...args) { if (DEBUG) console.log('[豆瓣适配]', ...args); } window._noButtonRetryCount = 0; // ========== 最高优先级:doubanapp 跳转 ========== (function() { const url = window.location.href; const hostname = window.location.hostname; const pathname = window.location.pathname; if (hostname === 'www.douban.com' && pathname === '/doubanapp/dispatch') { try { const params = new URLSearchParams(window.location.search); const uri = params.get('uri'); if (uri && (uri.startsWith('/tv/') || uri.startsWith('/movie/'))) { const idMatch = uri.match(/\/(\d+)/); if (idMatch) { if (window.stop) window.stop(); document.documentElement.innerHTML = ''; const targetUrl = `https://m.douban.com/movie/subject/${idMatch[1]}/`; window.location.replace(targetUrl); return; } } } catch(e) { console.error(e); } } })(); // ========== 配置 ========== const CONFIG = { DESKTOP_UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", SUBJECT_REDIRECT: { enable: true, minWidthForDesktop: 769, originHost: "movie.douban.com", targetHost: "m.douban.com", pathPrefix: "/movie" }, M_SUBJECT_REDIRECT: { enable: true, minWidthForMobile: 769, originHost: "m.douban.com", targetHost: "movie.douban.com", pathPrefixRemove: "/movie" }, SEARCH_REDIRECT: { enable: true, originHost: "search.douban.com", originPath: "/movie/subject_search", targetHost: "m.douban.com", targetPath: "/search/", searchParam: "search_text", targetParam: "query" }, AUTO_LOAD: { enable: true, triggerDistance: 250, lockResetTime: 2000, loadCooldown: 1000, noDataCheckDelay: 1200 }, ADAPT_ENABLE: true, M_TO_MOVIE_REDIRECT: { enable: true, originHost: "m.douban.com", targetHost: "movie.douban.com", targetPath: "/tv", excludePaths: ["/subject/", "/celebrity/"], matchListPaths: ["/tv", "/movie"] } }; const currentLocation = window.location; const currentHostname = currentLocation.hostname; const currentPathname = currentLocation.pathname; const currentHref = currentLocation.href; const isMovieDoubanDomain = currentHostname === CONFIG.SUBJECT_REDIRECT.originHost; const isMDoubanDomain = currentHostname === CONFIG.M_SUBJECT_REDIRECT.originHost; const isTvPage = isMovieDoubanDomain && (currentPathname.startsWith('/tv') || currentPathname === '/tv'); const isExplorePage = isMovieDoubanDomain && (currentPathname.startsWith('/explore') || currentPathname === '/explore'); const isHomePage = isMovieDoubanDomain && (currentPathname === '/' || currentPathname === ''); const needAdaptPage = isTvPage || isExplorePage; if (isHomePage) return; const getViewportWidth = () => window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; // 手机版详情页 -> 电脑版 const isMSubjectPage = isMDoubanDomain && currentPathname.startsWith('/movie/subject/'); if (CONFIG.M_SUBJECT_REDIRECT.enable && isMSubjectPage) { const screenWidth = getViewportWidth(); if (screenWidth >= CONFIG.M_SUBJECT_REDIRECT.minWidthForMobile) { try { const newPathname = currentPathname.replace(CONFIG.M_SUBJECT_REDIRECT.pathPrefixRemove, ''); const targetUrl = new URL(currentHref); targetUrl.hostname = CONFIG.M_SUBJECT_REDIRECT.targetHost; targetUrl.pathname = newPathname; if (targetUrl.href !== currentHref) { log(`跳转电脑版详情页`); window.location.replace(targetUrl.href); return; } } catch(e) { console.error(e); } } } if (isTvPage && currentLocation.hash !== '#douban-desktop-adapt') { window.location.hash = 'douban-desktop-adapt'; } // UA 伪装 if (needAdaptPage) { const rewriteNavigatorProp = (prop, value) => { Object.defineProperty(navigator, prop, { get: () => value, configurable: true, enumerable: true }); }; rewriteNavigatorProp('userAgent', CONFIG.DESKTOP_UA); rewriteNavigatorProp('appVersion', CONFIG.DESKTOP_UA.replace('Mozilla/', '')); rewriteNavigatorProp('platform', 'Win64'); rewriteNavigatorProp('oscpu', 'Windows NT 10.0; Win64; Win64; x64'); Object.defineProperty(window.screen, 'width', { get: () => 1920, configurable: true }); Object.defineProperty(window.screen, 'height', { get: () => 1080, configurable: true }); Object.defineProperty(window.screen, 'availWidth', { get: () => 1920, configurable: true }); Object.defineProperty(window.screen, 'availHeight', { get: () => 1040, configurable: true }); } // viewport (function() { if (isTvPage || isExplorePage) { const meta = document.createElement('meta'); meta.name = 'viewport'; meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes'; if (document.head) document.head.appendChild(meta); else document.write(''); } })(); // 搜索页跳转 const isSearchPage = currentHostname === CONFIG.SEARCH_REDIRECT.originHost && currentPathname.startsWith(CONFIG.SEARCH_REDIRECT.originPath); if (CONFIG.SEARCH_REDIRECT.enable && isSearchPage) { try { const urlParams = new URLSearchParams(currentLocation.search); const searchKeyword = urlParams.get(CONFIG.SEARCH_REDIRECT.searchParam); if (searchKeyword) { const targetUrl = new URL(currentLocation.origin + CONFIG.SEARCH_REDIRECT.targetPath); targetUrl.hostname = CONFIG.SEARCH_REDIRECT.targetHost; targetUrl.searchParams.set(CONFIG.SEARCH_REDIRECT.targetParam, searchKeyword); if (targetUrl.href !== currentHref) window.location.replace(targetUrl.href); return; } } catch(e) { console.error(e); } } // 详情页跳转手机版 const isSubjectPage = isMovieDoubanDomain && currentPathname.startsWith('/subject/'); if (CONFIG.SUBJECT_REDIRECT.enable && isSubjectPage) { const screenWidth = getViewportWidth(); if (screenWidth < CONFIG.SUBJECT_REDIRECT.minWidthForDesktop) { try { const targetUrl = new URL(currentHref); targetUrl.hostname = CONFIG.SUBJECT_REDIRECT.targetHost; targetUrl.pathname = CONFIG.SUBJECT_REDIRECT.pathPrefix + targetUrl.pathname; if (targetUrl.href !== currentHref) window.location.replace(targetUrl.href); return; } catch(e) { console.error(e); } } } // m站列表页跳回电脑版 const isMDoubanListPage = isMDoubanDomain && !currentPathname.includes('/subject/') && !currentPathname.includes('/celebrity/') && (currentPathname.startsWith('/tv') || currentPathname.startsWith('/movie')); if (CONFIG.M_TO_MOVIE_REDIRECT.enable && isMDoubanListPage) { try { const targetUrl = new URL(currentHref); targetUrl.hostname = CONFIG.M_TO_MOVIE_REDIRECT.targetHost; targetUrl.pathname = CONFIG.M_TO_MOVIE_REDIRECT.targetPath; targetUrl.hash = 'douban-desktop-adapt'; if (targetUrl.href !== currentHref) { const link = document.createElement('a'); link.href = targetUrl.href; link.referrerPolicy = 'no-referrer'; link.style.display = 'none'; document.body.appendChild(link); link.click(); setTimeout(() => link.remove(), 100); return; } } catch(e) { console.error(e); } } // ========== 样式注入(圆角6px + 重构筛选区专用样式) ========== function injectAdaptStyle() { const style = document.createElement('style'); style.textContent = ` html, body, #wrapper, .grid-16-8, .article { overflow-x: hidden !important; max-width: 100% !important; width: 100% !important; box-sizing: border-box !important; } * { box-sizing: border-box; } #db-global-nav, #db-nav-movie .nav-primary, #db-nav-movie .nav-secondary, .global-nav, .top-nav-info, .site-nav, .nav-search, .movieannual, .nav-logo, .nav-items, #footer, .aside, .extra, #recommend-groups, .dale_movie_tv_bottom_banner, .grid-16-8 .aside, .grid-16-8 .extra { display: none !important; } .rating-range, .score-range, .filter-checkbox, .drc-checkbox, .explore-all-filter, .rating-range-container, [class*="rating-range"], [class*="score-range"] { display: none !important; } /* 原有筛选组基础样式将被新重构容器覆盖,但保留选项基础风格 */ .selector-item, .tag-group, .base-selector { margin: 0 !important; padding: 6px 14px !important; background: #f5f5f7 !important; border-radius: 30px !important; font-size: 14px !important; font-weight: 500 !important; color: #2c3e50 !important; white-space: nowrap !important; transition: all 0.2s ease !important; } .selector-item.active, .tag-group.active, .base-selector.active { background: #1e2a3e !important; color: white !important; } .grid-16-8 .article, #content .article { float: none !important; width: 100% !important; margin: 0 !important; padding: 0 12px !important; box-sizing: border-box; overflow-x: hidden !important; } #content > h1 { margin: 16px 0 8px 0 !important; font-size: 22px !important; font-weight: 600 !important; padding-left: 8px !important; } .subject-list-list, .grid-view .items, .list-view .items { display: grid !important; gap: 16px 12px !important; margin: 16px 0 24px 0 !important; padding: 0 4px !important; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)) !important; } @media (max-width: 480px) { .subject-list-list, .grid-view .items, .list-view .items { grid-template-columns: repeat(3, 1fr) !important; gap: 14px 8px !important; } } @media (min-width: 481px) and (max-width: 768px) { .subject-list-list, .grid-view .items, .list-view .items { grid-template-columns: repeat(4, 1fr) !important; gap: 16px 12px !important; } } @media (min-width: 769px) and (max-width: 1024px) { .subject-list-list, .grid-view .items, .list-view .items { grid-template-columns: repeat(5, 1fr) !important; gap: 20px 16px !important; } } .subject-list-list li, .grid-view .item, .list-view .item { width: auto !important; margin: 0 !important; padding: 0 !important; list-style: none; transition: transform 0.2s ease, box-shadow 0.2s ease; } .subject-list-list li:hover, .grid-view .item:hover, .list-view .item:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,0.12); } .drc-subject-card, .grid-view .item .pic, .list-view .item .pic { display: flex !important; flex-direction: column !important; background: #ffffff !important; border-radius: 6px !important; overflow: hidden !important; box-shadow: 0 4px 12px rgba(0,0,0,0.08) !important; height: 100% !important; transition: all 0.25s ease; } .drc-subject-card-cover, .grid-view .item .pic a, .list-view .item .pic a { width: 100% !important; margin-bottom: 0 !important; overflow: hidden !important; background: #f0f2f5 !important; display: block; } .drc-subject-card-cover img, .grid-view .item .pic img, .list-view .item .pic img { width: 100% !important; height: auto !important; aspect-ratio: 9 / 16 !important; object-fit: cover !important; display: block; transition: transform 0.3s ease; } .drc-subject-card-main, .grid-view .item .info, .list-view .item .info { padding: 8px 6px 10px 6px !important; text-align: left !important; background: white; } .drc-subject-info-title, .grid-view .item .title a, .list-view .item .title a { font-size: 13px !important; font-weight: 600 !important; line-height: 1.35 !important; margin: 0 0 4px 0 !important; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; color: #1a1a2e !important; text-decoration: none !important; } .drc-rating, .grid-view .item .rating, .list-view .item .rating { display: flex !important; align-items: center !important; gap: 4px !important; margin-top: 2px !important; } .drc-rating-stars { display: inline-flex !important; align-items: center; } .drc-rating-num, .grid-view .item .rating .rating_num, .list-view .item .rating .rating_num { font-size: 13px !important; font-weight: 700 !important; color: #f5a623 !important; letter-spacing: 0.5px; } .drc-rating.no-rating, .grid-view .item .rating:empty, .list-view .item .rating:empty { display: none !important; } .drc-subject-info-subtitle, .drc-subject-info-year, .drc-subject-info-info, .grid-view .item .year, .list-view .item .year, .grid-view .item .abstract, .list-view .item .abstract { display: none !important; } .subject-list-more { margin: 30px 0 40px !important; text-align: center !important; } .subject-list-more button, .subject-list-more .drc-button, .subject-list-more a { border-radius: 60px !important; padding: 10px 28px !important; background-color: #f0f2f5 !important; border: none !important; color: #1e2a3e !important; font-weight: 600 !important; font-size: 14px !important; cursor: pointer !important; transition: background 0.2s, transform 0.1s !important; box-shadow: 0 1px 2px rgba(0,0,0,0.05); } .subject-list-more button:active, .subject-list-more .drc-button:active { transform: scale(0.97); background-color: #e4e6e9; } #content { padding-bottom: 20px !important; } .article .item, .grid-view .item { break-inside: avoid; } a, button, .selector-item, .tag-group { cursor: pointer; touch-action: manipulation; } /* ========== 筛选区重构专用样式(水平滚动 + 垂直滚动 + 去多重背景) ========== */ .dh-filter-horizontal { display: flex !important; flex-direction: row !important; overflow-x: auto !important; overflow-y: visible !important; gap: 12px !important; padding: 12px 8px !important; margin: 0 0 8px 0 !important; scrollbar-width: thin; -webkit-overflow-scrolling: touch; background: transparent !important; box-shadow: none !important; border-radius: 0 !important; } .dh-filter-horizontal .tag-group { flex: 0 0 auto !important; display: inline-flex !important; flex-direction: column !important; background: #ffffff !important; border-radius: 12px !important; padding: 8px 12px !important; margin: 0 !important; box-shadow: 0 1px 2px rgba(0,0,0,0.05) !important; min-width: 110px !important; } .dh-filter-horizontal .tag-group .tag-group-title { font-size: 14px !important; font-weight: 600 !important; margin-bottom: 8px !important; color: #1e2a3e !important; } .dh-filter-horizontal .tag-group .selector-item, .dh-filter-horizontal .tag-group .tag-group { display: inline-block !important; margin: 4px 6px 4px 0 !important; white-space: nowrap !important; } /* 垂直滚动区域(国家列表) */ .dh-filter-vertical { max-height: 280px !important; overflow-y: auto !important; overflow-x: hidden !important; padding: 8px 12px !important; margin: 0 0 12px 0 !important; background: transparent !important; border-radius: 16px !important; box-shadow: none !important; scrollbar-width: thin; -webkit-overflow-scrolling: touch; } .dh-filter-vertical .tag-group { background: transparent !important; padding: 0 !important; margin: 0 !important; box-shadow: none !important; display: flex !important; flex-wrap: wrap !important; gap: 8px !important; } .dh-filter-vertical .selector-item, .dh-filter-vertical .tag-group .selector-item { display: inline-block !important; margin: 0 !important; background: #f5f5f7 !important; border-radius: 30px !important; padding: 6px 14px !important; font-size: 13px !important; } /* 移除原有父容器背景和多重背景 */ .explore-all-selectors, .explore-menu, .tag-group-list, .base-selector { background: transparent !important; box-shadow: none !important; border: none !important; padding: 0 !important; margin: 0 !important; } /* 确保国家组垂直滚动时不出现额外背景 */ .dh-filter-vertical .tag-group .tag-group-title { display: none !important; } /* 水平滚动区域自定义滚动条样式 */ .dh-filter-horizontal::-webkit-scrollbar { height: 4px; } .dh-filter-horizontal::-webkit-scrollbar-track { background: #e9ecef; border-radius: 4px; } .dh-filter-horizontal::-webkit-scrollbar-thumb { background: #adb5bd; border-radius: 4px; } .dh-filter-vertical::-webkit-scrollbar { width: 4px; } .dh-filter-vertical::-webkit-scrollbar-track { background: #e9ecef; border-radius: 4px; } .dh-filter-vertical::-webkit-scrollbar-thumb { background: #adb5bd; border-radius: 4px; } `; document.head.appendChild(style); } function cleanPage() { const hideSelectors = ['.rating-range', '.score-range', '.filter-checkbox', '.drc-checkbox', '.explore-all-filter', '.rating-range-container', '[class*="rating-range"]', '[class*="score-range"]']; hideSelectors.forEach(sel => document.querySelectorAll(sel).forEach(el => el && (el.style.display = 'none'))); const candidates = document.querySelectorAll('.explore-all-selectors, .explore-menu, .tag-group-list, .base-selector, .subject-list-list, .grid-view, .list-view'); candidates.forEach(container => { if (!container) return; const elements = container.querySelectorAll('div, span, li'); elements.forEach(el => { const txt = el.innerText || ''; if ((txt.includes('评分区间') || txt.includes('未看过') || txt.includes('可播放')) && !el.querySelector('a, .selector-item, .tag-group, button')) { el.style.display = 'none'; } }); }); } // ========== 筛选区重构:水平滚动(类型/地区/年代/平台/排序) + 垂直滚动(国家列表) ========== let isFilterRestructured = false; function restructureFilterPanel() { if (!needAdaptPage) return; // 避免重复重构 if (isFilterRestructured) return; // 查找筛选父容器 const filterContainer = document.querySelector('.explore-all-selectors, .explore-menu, .tag-group-list'); if (!filterContainer) return; // 获取所有筛选组(.tag-group 或 .base-selector) let groups = Array.from(filterContainer.querySelectorAll(':scope > .tag-group, :scope > .base-selector')); if (groups.length === 0) return; // 识别哪个组是“国家/地区”组(垂直滚动区域) // 策略:包含选项数量大于8,或者内部文本包含常见国家关键词 let countryGroup = null; let otherGroups = []; const countryKeywords = ['华语', '欧美', '韩国', '日本', '美国', '英国', '泰国', '法国', '德国', '西班牙', '俄罗斯', '瑞典', '巴西', '丹麦', '印度', '加拿大', '爱尔兰', '澳大利亚', '中国台湾', '中国香港', '意大利']; for (let group of groups) { const items = group.querySelectorAll('.selector-item, .tag-group'); const itemCount = items.length; const innerText = group.innerText || ''; // 如果选项数量大于8 或 包含多个国家关键词,则认定为国家组 let isCountry = itemCount > 8; if (!isCountry) { let matchCount = 0; for (let kw of countryKeywords) { if (innerText.includes(kw)) matchCount++; if (matchCount >= 2) break; } isCountry = matchCount >= 2; } if (isCountry && !countryGroup) { countryGroup = group; } else { otherGroups.push(group); } } // 如果没有明确国家组,但存在一个特别大的组,也作为国家组 if (!countryGroup && groups.length > 0) { let maxSize = 0; for (let g of groups) { let cnt = g.querySelectorAll('.selector-item, .tag-group').length; if (cnt > maxSize && cnt > 6) { maxSize = cnt; countryGroup = g; } } if (countryGroup) { otherGroups = groups.filter(g => g !== countryGroup); } else { // 若仍然没有,不重构 return; } } if (!countryGroup || otherGroups.length === 0) return; // 创建水平滚动容器和垂直滚动容器 const horizontalWrap = document.createElement('div'); horizontalWrap.className = 'dh-filter-horizontal'; const verticalWrap = document.createElement('div'); verticalWrap.className = 'dh-filter-vertical'; // 移动其他组到水平容器 otherGroups.forEach(group => { horizontalWrap.appendChild(group.cloneNode(true)); group.remove(); }); // 移动国家组到垂直容器(保留原组,但克隆后原组移除) const clonedCountry = countryGroup.cloneNode(true); verticalWrap.appendChild(clonedCountry); countryGroup.remove(); // 将两个新容器插入原筛选父容器中 filterContainer.appendChild(horizontalWrap); filterContainer.appendChild(verticalWrap); // 为每个筛选组添加标题(如果原本没有标题,从内部文本提取或预设) horizontalWrap.querySelectorAll('.tag-group').forEach(group => { if (!group.querySelector('.tag-group-title')) { // 尝试获取标题:可能是 group 内的第一个文本节点或第一个非选项元素 let title = ''; const firstText = group.childNodes[0]?.nodeType === Node.TEXT_NODE ? group.childNodes[0].textContent.trim() : ''; if (firstText && firstText.length < 10) title = firstText; else if (group.innerText) title = group.innerText.split(/\s/)[0]; if (title) { const titleSpan = document.createElement('div'); titleSpan.className = 'tag-group-title'; titleSpan.innerText = title; group.insertBefore(titleSpan, group.firstChild); } } }); isFilterRestructured = true; log('筛选面板重构完成:水平滚动区 + 垂直滚动区'); } // ========== 自动加载逻辑(严格防闪烁) ========== let isLoading = false; let noMoreData = false; let lastLoadTime = 0; let lastItemCount = 0; let pendingCheck = false; let contentObserver = null; function getCurrentItemCount() { return document.querySelectorAll('.subject-list-list li, .grid-view .item, .list-view .item').length; } function getLoadMoreBtn() { if (noMoreData) return null; const isValidBtn = (el) => { if (!el) return false; if (el.disabled) return false; const rect = el.getBoundingClientRect(); if (rect.width === 0 && rect.height === 0) return false; const style = window.getComputedStyle(el); if (style.display === 'none' || style.visibility === 'hidden') return false; const text = (el.textContent || '').trim(); return text.includes('加载更多') || text.includes('Load more') || text.includes('更多'); }; const selectors = [ '.subject-list-more button', '.subject-list-more .drc-button', '.subject-list-more a', '.more a', '.load-more a', '.list-more a', '.next a', '.load-more-btn', '.btn-more', '.more-btn', 'a.more', 'button.more', '[class*="load-more"]', '[class*="loadmore"]', '#load-more', '.load-more-button', '.more-link', '.next-page', '.paginator .next a' ]; for (const selector of selectors) { try { const elements = document.querySelectorAll(selector); for (const el of elements) { if (isValidBtn(el)) return el; } } catch(e) {} } try { const xpath = "//*[contains(text(),'加载更多') or contains(text(),'Load more')]"; const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); let node = result.singleNodeValue; while (node) { if (isValidBtn(node)) return node; let parent = node.parentElement; while (parent && parent !== document.body) { if (isValidBtn(parent) || parent.tagName === 'A' || parent.tagName === 'BUTTON') { if (isValidBtn(parent)) return parent; } parent = parent.parentElement; } node = node.parentElement; } } catch(e) {} const all = document.querySelectorAll('a, button, .more, .load-more, [role="button"]'); for (const el of all) { if (isValidBtn(el)) return el; } return null; } function checkNoMoreDataByText() { const bodyText = document.body.innerText; if (bodyText.includes('没有更多') || bodyText.includes('已经到底') || bodyText.includes('No more') || bodyText.includes('End of list')) { if (!noMoreData) log('文本检测到无更多数据'); return true; } const btn = getLoadMoreBtn(); if (btn && btn.disabled) { if (!noMoreData) log('按钮已禁用,无更多数据'); return true; } return false; } function performLoad() { if (isLoading) { log('跳过:正在加载'); return false; } if (noMoreData) { log('跳过:已无更多数据'); return false; } const now = Date.now(); if (now - lastLoadTime < CONFIG.AUTO_LOAD.loadCooldown) { log('跳过:冷却中'); return false; } if (checkNoMoreDataByText()) { noMoreData = true; return false; } const loadBtn = getLoadMoreBtn(); if (!loadBtn) { window._noButtonRetryCount = (window._noButtonRetryCount || 0) + 1; if (window._noButtonRetryCount > 3) { log('多次未找到按钮,标记无更多数据'); noMoreData = true; } return false; } window._noButtonRetryCount = 0; const beforeCount = getCurrentItemCount(); isLoading = true; lastLoadTime = now; loadBtn.click(); log(`触发加载,当前条目: ${beforeCount}`); const lockTimer = setTimeout(() => { if (isLoading) { log('加载超时,强制重置锁'); isLoading = false; } }, CONFIG.AUTO_LOAD.lockResetTime); setTimeout(() => { clearTimeout(lockTimer); if (!isLoading) return; const afterCount = getCurrentItemCount(); if (afterCount > beforeCount) { log(`加载成功: ${beforeCount} -> ${afterCount}`); noMoreData = false; lastItemCount = afterCount; } else { log(`加载无新条目,停止自动加载`); noMoreData = true; } isLoading = false; }, CONFIG.AUTO_LOAD.noDataCheckDelay); return true; } function checkAndLoad() { if (isLoading || noMoreData) return; if (pendingCheck) return; pendingCheck = true; setTimeout(() => { pendingCheck = false; }, 150); if (checkNoMoreDataByText()) { noMoreData = true; return; } const docEl = document.documentElement; const scrollTop = window.pageYOffset || docEl.scrollTop || 0; const windowHeight = window.innerHeight || docEl.clientHeight || 0; const documentHeight = Math.max(docEl.scrollHeight, docEl.offsetHeight, document.body.scrollHeight); const distanceToBottom = documentHeight - (scrollTop + windowHeight); if (distanceToBottom <= CONFIG.AUTO_LOAD.triggerDistance) { performLoad(); } } let changeTimer = null; function onContentChanged() { if (changeTimer) clearTimeout(changeTimer); changeTimer = setTimeout(() => { const newCount = getCurrentItemCount(); if (newCount !== lastItemCount) { log(`条目变化: ${lastItemCount} -> ${newCount}`); lastItemCount = newCount; if (noMoreData && newCount > lastItemCount) { log('检测到新条目,重置无数据标志'); noMoreData = false; } } if (!noMoreData) checkAndLoad(); }, 300); } function setupContentMonitor() { if (contentObserver) contentObserver.disconnect(); contentObserver = new MutationObserver(() => onContentChanged()); contentObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] }); lastItemCount = getCurrentItemCount(); } function initAfterDOMLoad() { if (needAdaptPage) { injectAdaptStyle(); cleanPage(); const observer = new MutationObserver(() => cleanPage()); observer.observe(document.body, { childList: true, subtree: true }); // 重构筛选面板(水平+垂直滚动) restructureFilterPanel(); // 监听DOM变化,如果筛选区域被动态重载,再次尝试重构(但避免重复) const filterObserver = new MutationObserver(() => { if (!isFilterRestructured) restructureFilterPanel(); }); filterObserver.observe(document.body, { childList: true, subtree: true }); } if (CONFIG.AUTO_LOAD.enable && needAdaptPage) { setupContentMonitor(); window.addEventListener('scroll', checkAndLoad, { passive: true }); window.addEventListener('resize', checkAndLoad, { passive: true }); window.addEventListener('load', () => setTimeout(checkAndLoad, 300)); setTimeout(checkAndLoad, 500); setInterval(() => { if (!isLoading && !noMoreData && needAdaptPage) { checkAndLoad(); } }, 3000); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAfterDOMLoad); } else { initAfterDOMLoad(); } })();