您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Ultimate F95 - Removed const reassignment error, prefix display.
当前为
// ==UserScript== // @name Ultimate F95Zone // @namespace https://github.com/balu100/Ultimate-F95Zone // @version 1.7 // @license MIT // @description Ultimate F95 - Removed const reassignment error, prefix display. // @author balu100 // @match https://f95zone.to/sam/latest_alpha/* // @icon https://www.google.com/s2/favicons?sz=64&domain=f95zone.to // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; // --- Constants and State Variables --- let currentPage = 1; let isLoading = false; let noMorePages = false; let currentFilters = ''; let infiniteScrollInitialized = false; let itemsPerRow = 90; let siteOptions = { newTab: "true", version: "small", searchHighlight: "true" }; let sitePrefixData = null; // To store latestUpdates.prefixes let prefixCache = {}; // Cache for getPrefixDetails const itemContainerSelector = 'div#latest-page_items-wrap_inner'; const itemSelector = '.resource-tile'; const originalPaginationSelector = '.sub-nav_paging'; const AJAX_ENDPOINT_URL = 'https://f95zone.to/sam/latest_alpha/latest_data.php'; // --- Helper Function Definitions --- const htmlEscape = (str) => { if (str === null || str === undefined) return ''; return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); }; const highlightUnreadLinks = () => { try { document.querySelectorAll('a:not(.resource-item_row-hover_outer > a)').forEach(link => { const text = link.textContent.trim().toLowerCase(); const buttonTextEl = link.querySelector('.button-text'); const buttonText = buttonTextEl ? buttonTextEl.textContent.trim().toLowerCase() : ''; if (link.href.includes('/unread?new=1') || text === 'jump to new' || buttonText === 'jump to new') { link.classList.add('highlight-unread'); if (buttonTextEl) buttonTextEl.classList.add('highlight-unread'); } }); } catch (e) { console.error("Error in highlightUnreadLinks:", e); } }; const getCurrentPageFromUrl = () => { const match = (window.location.hash || '').match(/page=(\d+)/); return match && match[1] ? parseInt(match[1], 10) : 1; }; const getCurrentFiltersFromUrl = () => { const defaultFilters = { cat: 'games', sort: 'date', tagtype: 'and', date: 0 }; const parsedHashFilters = {}; const hash = window.location.hash; if (hash && hash.length > 1 && hash !== '#/') { let rhP = hash.substring(1); if (rhP.startsWith('/')) rhP = rhP.substring(1); rhP.split('/').forEach(part => { if (part.includes('=')) { let [key, value] = part.split('='); value = decodeURIComponent(value); if (key && value !== undefined && key !== 'page') parsedHashFilters[key] = value; }}); } const finalFilterState = { ...defaultFilters, ...parsedHashFilters }; const params = new URLSearchParams(); const arrayKeys = ['tags', 'notags', 'prefixes', 'noprefixes']; for (const key in finalFilterState) { if (finalFilterState.hasOwnProperty(key)) { const value = finalFilterState[key]; if (arrayKeys.includes(key)) { if (String(value).length > 0) String(value).split(',').filter(Boolean).forEach(sV => params.append(`${key}[]`, sV)); } else if (key==='cat'||key==='sort'||(key==='tagtype'&&value!=='and')||(key==='date'&&Number(value)!==0)||(['search','creator'].includes(key)&&String(value).length>0)) { params.set(key, String(value)); }}} return params.toString(); }; function getPrefixDetails(prefixId, category) { const cacheKey = `${category}-${prefixId}`; if (prefixCache[cacheKey]) return prefixCache[cacheKey]; if (!sitePrefixData || !sitePrefixData[category]) return false; for (const group of sitePrefixData[category]) { for (const prefix of group.prefixes) { if (String(prefix.id) === String(prefixId)) { // Compare as strings after ensuring they are numbers const details = { id: prefix.id, name: prefix.name, class: prefix.class, parentId: group.id }; prefixCache[cacheKey] = details; return details; } } } return false; } function createItemElement(itemData_g) { const tile = document.createElement('div'); let tileCls = ['resource-tile', 'userscript-generated-tile']; if(itemData_g.ignored)tileCls.push('resource-tile_ignored'); itemData_g.new ? tileCls.push('resource-tile_new') : tileCls.push('resource-tile_update'); const cat = (new URLSearchParams(currentFilters)).get('cat') || 'games'; if(cat) { tileCls.push(`${cat}-item`, `resource-tile_${cat}`); } tile.className = tileCls.join(' '); tile.dataset.threadId=String(itemData_g.thread_id||'0'); tile.dataset.tags=(itemData_g.tags||[]).join(','); tile.dataset.images=(itemData_g.screens&&itemData_g.screens.length?itemData_g.screens:[itemData_g.cover||'']).join(','); let tLink=`https://f95zone.to/threads/${htmlEscape(String(itemData_g.thread_id||'0'))}/`; let title=htmlEscape(itemData_g.title||'No Title'); let titleAttr=htmlEscape(itemData_g.title||'No Title'); let creator=htmlEscape(itemData_g.creator||'Unknown'); let version=(itemData_g.version&&itemData_g.version!=="Unknown")?htmlEscape(itemData_g.version):""; let cover=htmlEscape(itemData_g.cover||''); let date=itemData_g.date||'N/A'; const dM=String(date).match(/^([0-9]+ )?([A-Za-z ]+)$/i); let dH=dM?`<span class="tile-date_${htmlEscape(dM[2]).toLowerCase().replace(/ /g,"")}">${dM[1]?htmlEscape(dM[1].trim()):""}</span>`:htmlEscape(date); let views=String(itemData_g.views||0); if(itemData_g.views > 1E6)views=(itemData_g.views/1E6).toFixed(1)+"M"; else if(itemData_g.views > 1E3)views=Math.round(itemData_g.views/1E3)+"K"; let likes=htmlEscape(String(itemData_g.likes||0)); let rV=Number(itemData_g.rating)||0; let rD=rV===0?"-":rV.toFixed(1); let rW=20*rV; const newTab=(siteOptions.newTab==="true")?' target="_blank"':''; const smallVer=(siteOptions.version==="small"); let prefixesLeftHTML = ""; let prefixesRightHTML = ""; if (itemData_g.prefixes && sitePrefixData) { itemData_g.prefixes.forEach(prefixId => { const prefixInfo = getPrefixDetails(prefixId, cat); if (prefixInfo) { const prefixDiv = `<div class="${htmlEscape(prefixInfo.class)}">${htmlEscape(prefixInfo.name)}</div>`; if (String(prefixInfo.parentId) === "4") prefixesRightHTML += prefixDiv; // Status prefixes else prefixesLeftHTML += prefixDiv; } }); } tile.innerHTML = ` <a href="${tLink}" class="resource-tile_link" rel="noopener"${newTab}> <div class="resource-tile_thumb-wrap"><div class="resource-tile_thumb" style="background-image:url(${cover?"'"+cover+"'":'none'})">${itemData_g.watched?'<i class="far fa-eye watch-icon"></i>':''}</div></div> <div class="resource-tile_body"> <div class="resource-tile_label-wrap"> <div class="resource-tile_label-wrap_left">${prefixesLeftHTML}</div> <div class="resource-tile_label-wrap_right">${prefixesRightHTML}<div class="resource-tile_label-version">${(cat!=="assets"&&version&&smallVer)?version:""}</div></div> </div> <div class="resource-tile_info"> <header class="resource-tile_info-header"><div class="header_title-wrap"><h2 class="resource-tile_info-header_title">${title}</h2></div><div class="header_title-ver">${(cat!=="assets"&&version&&!smallVer)?version:""}</div><div class="resource-tile_dev fas fa-user">${(cat!=="assets")?` ${creator}`:""}</div></header> <div class="resource-tile_info-meta"><div class="resource-tile_info-meta_time">${dH}</div><div class="resource-tile_info-meta_likes">${likes}</div><div class="resource-tile_info-meta_views">${views}</div>${(cat!=="assets"&&cat!=="comics")?`<div class="resource-tile_info-meta_rating">${rD}</div>`:""}<div class="resource-tile_rating"><span style="width:${rW}%"></span></div></div> </div> </div> </a>`; return tile; } async function loadMoreItems() { if(isLoading||noMorePages)return;isLoading=true; const bP=Number(currentPage); if(isNaN(bP)){console.error("loadMoreItems: currentPage is NaN!",currentPage);isLoading=false;noMorePages=true;const elT=document.getElementById('infinite-scroll-trigger');if(elT)elT.classList.add('no-more');return;} const nP=bP+1; const lT=document.getElementById('infinite-scroll-trigger');if(lT)lT.classList.add('loading'); console.log(`loadMoreItems: Attempting page ${nP}. Filters: '${currentFilters}'`); try{ const p=new URLSearchParams(currentFilters); p.set('cmd','list');p.set('page',nP.toString());p.set('rows',itemsPerRow.toString());p.set('_',Date.now().toString()); const url=`${AJAX_ENDPOINT_URL}?${p.toString()}`; // console.log(`loadMoreItems: Fetching URL: ${url}`); const r=await fetch(url,{method:'GET',headers:{'X-Requested-With':'XMLHttpRequest','Accept':'application/json, text/javascript, */*; q=0.01'}}); if(!r.ok){console.error("loadMoreItems: Fetch fail",r.status,url);noMorePages=true;return;} const d=await r.json(); if(d&&d.status==='ok'&&d.msg&&d.msg.data){ const i=d.msg.data,c=document.querySelector(itemContainerSelector); if(i.length&&c){ const f=document.createDocumentFragment(),aE=[]; i.forEach(iD=>{const el=createItemElement(iD);if(el){f.appendChild(el);aE.push(el);}}); c.appendChild(f); if(typeof XF!=='undefined'&&XF.activate)aE.forEach(el=>XF.activate(el)); currentPage=nP; highlightUnreadLinks(); if(d.msg.pagination&&d.msg.pagination.page>=d.msg.pagination.total)noMorePages=true; }else{noMorePages=true;} }else{noMorePages=true;console.error("loadMoreItems: AJAX response error",d);} }catch(e){console.error('loadMoreItems: Error during AJAX/processing:',e);noMorePages=true;} finally{isLoading=false;if(lT&&!noMorePages)lT.classList.remove('loading');else if(lT)lT.classList.add('no-more');} } function handleSiteStateChange(eventSource = "unknown") { console.log(`handleSiteStateChange by: ${eventSource}. Hash: ${window.location.hash}`); const newPg = getCurrentPageFromUrl(); const newFi = getCurrentFiltersFromUrl(); console.log(`StateChange Check: OldF('${currentFilters}') vs NewF('${newFi}')`); console.log(`StateChange Check: OldP(${currentPage}) vs NewHashP(${newPg})`); if (currentFilters !== newFi || (newPg === 1 && currentPage !== newPg )) { console.log(`State change ACTION. Resetting.`); currentPage = 1; currentFilters = newFi; noMorePages = false; isLoading = false; const lT = document.getElementById('infinite-scroll-trigger'); if (lT) lT.className = ''; console.log(`State reset: curP=${currentPage}, curF='${currentFilters}'`); } } function actualInitInfiniteScroll() { if(infiniteScrollInitialized)return;const mA=document.querySelector(itemContainerSelector); if(!mA||!mA.querySelector(itemSelector)){console.warn('actualInit:No initial items.');return;} currentPage=getCurrentPageFromUrl();currentFilters=getCurrentFiltersFromUrl(); if(isNaN(Number(currentPage))){currentPage=1;} infiniteScrollInitialized=true;console.log(`actualInit: p${currentPage}, f'${currentFilters}'`); if(typeof latestUpdates!=='undefined'&&latestUpdates.options){ siteOptions=latestUpdates.options;itemsPerRow=parseInt(siteOptions.rows,10)||90; if (window.latestUpdates && window.latestUpdates.prefixes) { // Also grab prefix data here sitePrefixData = window.latestUpdates.prefixes; console.log("Site prefix data captured in actualInit."); } } const trg=document.createElement('div');trg.id='infinite-scroll-trigger';mA.insertAdjacentElement('afterend',trg); new IntersectionObserver(e=>{if(e[0].isIntersecting&&!isLoading&&!noMorePages)loadMoreItems();},{threshold:0.01}).observe(trg); window.addEventListener('hashchange', handleSiteStateChange, false); new MutationObserver(ml=>{for(const m of ml){if(m.type==='childList'&&m.removedNodes.length>0){handleSiteStateChange("MutationObserver (content cleared)");break;}}}).observe(mA,{childList:true}); } const style = document.createElement('style'); function adjustPageWidth() { const pbi=document.querySelector('.p-body-inner');const pni=document.querySelector('.p-nav-inner'); const pc=document.querySelector('.pageContent');const nw=window.innerWidth*0.95; if(pbi)pbi.style.maxWidth=`${nw}px`;if(pni)pni.style.maxWidth=`${nw}px`; if(pc&&(pc.closest('.p-header-banner')||!pc.closest('footer')))pc.style.maxWidth=`${nw}px`; }; style.innerHTML = ` .pageContent {max-width: ${(window.innerWidth*0.95)}px !important;max-height:360px!important;transition:none!important;top:110px!important;margin-left:auto!important;margin-right:auto!important;} .p-body-inner,.p-nav-inner {max-width:${(window.innerWidth*0.95)}px !important;margin-left:auto!important;margin-right:auto!important;transition:none!important;box-sizing:border-box!important;} .cover-hasImage {height:360px!important;transition:none!important;} .p-sectionLinks,.uix_extendedFooter,.p-footer-inner,.view-thread.block--similarContents.block-container,.js-notices.notices--block.notices,${originalPaginationSelector}{display:none!important;} .highlight-unread {color:cyan;font-weight:bold;text-shadow:1px 1px 2px black;} .uix_contentWrapper {max-width:100%!important;padding-left:5px!important;padding-right:5px!important;box-sizing:border-box!important;} .p-body-main--withSideNav {display:flex!important;flex-direction:row!important;max-width:100%!important;padding:0!important;box-sizing:border-box!important;} main#latest-page_main-wrap {flex-grow:1!important;margin-left:0!important;margin-right:10px!important;min-width:0;box-sizing:border-box!important;} aside#latest-page_filter-wrap {flex-shrink:0!important;width:280px!important;margin-left:0!important;margin-right:0!important;box-sizing:border-box!important;} aside#latest-page_filter-wrap.filter-hidden,aside#latest-page_filter-wrap[style*="display:none"]{display:none!important;} main#latest-page_main-wrap:has(+ aside#latest-page_filter-wrap.filter-hidden),main#latest-page_main-wrap:has(+ aside#latest-page_filter_wrap[style*="display:none"]){margin-right:0!important;} div#latest-page_items-wrap {width:100%!important;margin-left:0!important;box-sizing:border-box!important;} ${itemContainerSelector}.resource-wrap-game.grid-normal {display:grid!important;grid-template-columns:repeat(auto-fit,minmax(250px,1fr))!important;gap:15px!important;padding:0!important;box-sizing:border-box!important;} #infinite-scroll-trigger {padding:20px;text-align:center;font-size:1.2em;color:#777;border:1px solid transparent!important;min-height:40px!important;margin-top:10px!important;} #infinite-scroll-trigger.loading::after {content:"Loading more items...";} #infinite-scroll-trigger.no-more::after {content:"No more items to load.";} .userscript-generated-tile .resource-tile_thumb{background-size:cover;background-position:center;background-repeat:no-repeat;} .userscript-generated-tile .resource-tile_dev.fas.fa-user::before{margin-right:0.3em;} `; document.documentElement.appendChild(style); function onDomReady() { highlightUnreadLinks(); adjustPageWidth(); window.addEventListener('resize', adjustPageWidth); // Capture sitePrefixData as early as possible if latestUpdates exists if (typeof window.latestUpdates !== 'undefined' && window.latestUpdates.prefixes) { sitePrefixData = window.latestUpdates.prefixes; // console.log("Site prefix data captured on DOM ready."); } setTimeout(() => { const mainContentArea = document.querySelector(itemContainerSelector); if (mainContentArea && mainContentArea.querySelector(itemSelector)) { actualInitInfiniteScroll(); } else { console.error("Initial items NOT found after 3s for init."); } }, 3000); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', onDomReady); else onDomReady(); })();