您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
[BETA] Infinity scrolling for videos (main, search, channels) & photos (photos, search, channels)
当前为
// ==UserScript== // @name GBT scroller-coaster (GBTSC) // @namespace _pc // @version 0.9 // @license MIT // @description [BETA] Infinity scrolling for videos (main, search, channels) & photos (photos, search, channels) // @author verydelight // @match *://*.gayboystube.com/* // @icon https://www.gayboystube.com/favicon.ico // @run-at document-end // @grant GM.xmlHttpRequest // @grant GM_download // @grant GM_xmlHttpRequest // @grant GM.download // ==/UserScript== 'use strict'; if( (window.location.pathname=="") || (window.location.pathname=="/") || (window.location.pathname.startsWith("/channels")) || (window.location.pathname.startsWith("/search/videos")) || (window.location.pathname.startsWith("/photos")) || (window.location.pathname.startsWith("/search/photos")) ){ let area = window.location.pathname.split("/"); let testArea,baseUrl let videoPage=false; const identifier = $('div[id]')[2].id; testArea = area[2] ? `${area[1]}/${area[2]}` : (area[1] || "videos"); switch(testArea) { case "videos": baseUrl = "https://www.gayboystube.com/page"; gbtScroller(identifier,baseUrl); videoPage = true; break; case "search/videos": baseUrl = "https://www.gayboystube.com/search/videos/"+area[area.length - 2]+"/page"; gbtScroller(identifier,baseUrl); videoPage = true; break; case testArea.match(/^channels\/[0-9]{1,3}/)?.input: baseUrl = "https://www.gayboystube.com/channels/"+area[area.length - 3]+"/"+area[area.length - 2]+"/page"; gbtScroller(identifier,baseUrl); videoPage = true; break; case "photos": baseUrl = "https://www.gayboystube.com/photos/page"; gbtScroller(identifier,baseUrl); break; case "search/photos": baseUrl = "https://www.gayboystube.com/search/photos/"+area[area.length - 2]+"/page"; gbtScroller(identifier,baseUrl); break; case "photos/channels": baseUrl = "https://www.gayboystube.com/photos/channels/"+area[area.length - 2]+"/page"; gbtScroller(identifier,baseUrl); break; default: } function gbtScroller(identifier,baseUrl){ const style = document.createElement('style') style.type = 'text/css'; style.textContent = ` .gbtloader { /*color: #ffffff;*/ width: fit-content; font-weight: bold; font-family: monospace; font-size: 30px; background:linear-gradient(90deg,#000 50%,#0000 0) right/200% 100%; animation: l21 1.5s infinite linear; } .gbtloader::before { content :"Loading..."; color: #0000; padding: 0 5px; background: inherit; background-image: linear-gradient(90deg,#fff 50%,#000 0); -webkit-background-clip:text; background-clip:text; } @keyframes l21{ 100%{background-position: left} } `; document.head.appendChild(style); let videoListing = document.getElementById(identifier); videoListing.nextElementSibling.remove(); let loadTrigger = document.createElement("postloader"); loadTrigger.id = 'postloader-1'; loadTrigger.classList.add('item','item-col','gbtloader'); //loadTrigger.append("(Loading...)"); videoListing.append(loadTrigger) let target = videoListing.getElementsByTagName('postloader')[0]; let options = { root: null, rootMargin: '0px', threshold: 0 } let firstCallImminent = true; let observer = new IntersectionObserver(callback, options); if (target){ observer.observe(target); } function callback() { if(!firstCallImminent){ observer.unobserve(target); var nextPage = parseInt(loadTrigger.id.split("-")[1])+1; var nextPageUrl = baseUrl+nextPage+".html"; loadNextPage(nextPageUrl,nextPage); }else{ firstCallImminent = false; } } async function loadNextPage(url,nextPage) { try { const response = await GM.xmlHttpRequest({ method: 'GET', responseType: 'document', url: url, }); const newResults = response.response; var childResults = newResults.getElementById(identifier).children; while (childResults.length > 0) { //video case if (videoPage){ if(childResults[0].querySelector('img')){ const firstChildNode = childResults[0].firstElementChild; const lastChildNode = childResults[0].lastElementChild; const newWrapper = document.createElement("div"); newWrapper.classList.add("item", "item-col"); const aImg = childResults[0].querySelector('a'); aImg.removeAttribute('class'); aImg.classList.add("image"); const videoImage = firstChildNode.querySelector('img'); const videoElement = document.createElement("video"); videoElement.alt = videoImage.getAttribute("alt"); videoElement.poster = videoImage.getAttribute("data-src"); videoElement.controls = false; videoElement.style.objectFit = "cover"; videoElement.preload = "none"; videoElement.height = videoImage.getAttribute("height"); videoElement.width = videoImage.getAttribute("width"); videoElement.crossOrigin = "use-credentials"; videoElement.addEventListener('mouseenter', () => { if(!videoElement.src){ const previewUrl = videoImage.getAttribute("data-preview") downloadPreview(previewUrl); } async function downloadPreview(url) { try { const response = await GM.xmlHttpRequest({ method: 'GET', responseType: 'blob', url: url, headers: { "Content-Type": "video/mp4", "Accept": "video/mp4" }, }); const blob = new Blob([response.response],{type: 'video/mp4'}); videoElement.src = URL.createObjectURL(blob); } catch (err) { console.error("GBTSC: Error in fetching and downloading preview file:", err); } } videoElement.play(); }); videoElement.addEventListener('mouseleave', () => { videoElement.load(); }); videoImage.replaceWith(videoElement); newWrapper.append(firstChildNode); newWrapper.append(lastChildNode); videoListing.appendChild(newWrapper); }else{ childResults[0].remove() } //end of video case }else{ //photo case videoListing.appendChild(childResults[0]); } } firstCallImminent = true; loadTrigger.remove(); loadTrigger.id = 'postloader-'+nextPage; videoListing.append(loadTrigger); observer.observe(target); } catch (err) { console.error("GBTSC: Error in fetching and downloading next videos:", err); observer.unobserve(target); loadTrigger.remove(); } } } }