您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
-
当前为
// ==UserScript== // @name:ko 구글 무한 스크롤 // @name Google Infinite Scroll // @description:ko - // @description - // @namespace https://ndaesik.tistory.com/ // @version 2025.01.09.10.50 // @author ndaesik // @icon https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://www.google.com // @match *://www.google.com/search* // @grant GM_xmlhttpRequest // @run-at document-end // @connect * // ==/UserScript== if(new URL(window.location.href).searchParams.has('udm')) return; document.head.appendChild(Object.assign(document.createElement('style'), { textContent: ` #botstuff [role="navigation"] { display: none !important; } .youtube-thumbnail { object-fit: cover !important; } img[src="data:text/plain;base64,"] { opacity: 0 !important; } ` })); const PLACEHOLDER_SELECTOR = '[src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="]'; function getYoutubeVideoId(url) { try { const urlObj = new URL(url); if (urlObj.hostname.includes('youtube.com')) { return urlObj.searchParams.get('v'); } return null; } catch (error) { console.error('Error parsing YouTube URL:', error); return null; } } async function replaceYoutubeThumbnail(imgElement) { try { const container = imgElement.closest('[data-curl*="youtube.com/watch"]'); if (!container) return; const youtubeUrl = container.getAttribute('data-curl'); const videoId = getYoutubeVideoId(youtubeUrl); if (!videoId) return; const thumbnailUrl = `https://img.youtube.com/vi/${videoId}/sddefault.jpg`; const dataUrl = await convertImageToDataUrl(thumbnailUrl); if (dataUrl) { imgElement.src = dataUrl; imgElement.classList.add('youtube-thumbnail'); } } catch (error) { console.error('Error replacing YouTube thumbnail:', error); if (imgElement.src.startsWith('data:text/plain;base64,')) { imgElement.style.opacity = '0'; } } } async function convertImageToDataUrl(imageUrl) { try { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: imageUrl, responseType: "blob", onload: function(response) { const reader = new FileReader(); reader.onloadend = function() { resolve(reader.result); }; reader.readAsDataURL(response.response); }, onerror: function(error) { console.error('Error fetching image:', error); resolve(null); } }); }); } catch (error) { console.error('Error converting image:', error); return null; } } async function getOGImage(url) { try { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, "text/html"); const ogImage = doc.querySelector('meta[property="og:image"]')?.content; if (ogImage) { resolve(ogImage); return; } const firstImage = doc.querySelector('img[src^="http"]')?.src; resolve(firstImage || null); }, onerror: function(error) { console.error('Error fetching page:', error); resolve(null); } }); }); } catch (error) { console.error('Error in getOGImage:', error); return null; } } async function replacePlaceholderImage(imgElement) { try { const youtubeContainer = imgElement.closest('[data-curl*="youtube.com/watch"]'); if (youtubeContainer) { await replaceYoutubeThumbnail(imgElement); imgElement.classList.add('youtube-thumbnail'); return; } const url = imgElement.parentElement?.parentElement?.parentElement?.parentElement?.querySelector('a[data-ved]')?.href; if (!url) return; const ogImageUrl = await getOGImage(url); if (!ogImageUrl) return; const dataUrl = await convertImageToDataUrl(ogImageUrl); if (dataUrl) { imgElement.src = dataUrl; } } catch (error) { console.error('Error replacing placeholder:', error); } } const fetchNextPage = async pageNumber => { const baseUrl = new URL(window.location.href); const text = await (await fetch(`${baseUrl.origin}${baseUrl.pathname}?q=${baseUrl.searchParams.get('q')}&start=${pageNumber * 10}`)).text(); const newDoc = new DOMParser().parseFromString(text, 'text/html'); const container = document.createElement('div'); container.id = `page-${pageNumber}`; container.style.cssText = 'margin-top: 20px;'; newDoc.querySelectorAll('#rso > div').forEach(result => container.appendChild(result.cloneNode(true))); const lastAddedPage = document.querySelector(`#page-${pageNumber - 1}`) || document.querySelector('#botstuff'); lastAddedPage.after(container); // 새로 추가된 페이지의 이미지만 처리 const newPlaceholders = container.querySelectorAll(PLACEHOLDER_SELECTOR); const youtubeResults = container.querySelectorAll('[data-curl*="youtube.com/watch"]'); // 유튜브 결과가 있는 경우에만 이미지 처리 수행 if (youtubeResults.length > 0) { newPlaceholders.forEach(replacePlaceholderImage); } return !!newDoc.querySelector('#pnnext'); }; let [pageNumber, isLoading, hasMore] = [1, false, true]; window.addEventListener('scroll', async () => { if (!isLoading && hasMore && window.innerHeight + window.pageYOffset >= document.documentElement.offsetHeight - 1000) { isLoading = true; hasMore = await fetchNextPage(pageNumber); pageNumber += hasMore ? 1 : 0; isLoading = false; } });