您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Iterates through div.tile--img, clicks, extracts, closes (fixed)
当前为
- // ==UserScript==
- // @name DuckDuckGo Image Link Extractor (Iterate Tiles)
- // @namespace yournamespace
- // @match https://duckduckgo.com/*images*
- // @grant none
- // @version 1.7
- // @license GNU General Public License v3.0
- // @description Iterates through div.tile--img, clicks, extracts, closes (fixed)
- // ==/UserScript==
- (function() {
- 'use strict';
- let isProcessing = false;
- let stopProcessing = false;
- let processedCount = 0;
- let totalCount = 0;
- async function processImageTiles() {
- if (isProcessing) return;
- isProcessing = true;
- stopProcessing = false;
- processedCount = 0;
- const imageTiles = document.querySelectorAll('div.tile--img');
- totalCount = imageTiles.length;
- updateProgress(0, totalCount);
- for (const tile of imageTiles) {
- if (stopProcessing) break;
- const imgElement = tile.querySelector('.tile--img__img');
- const dimensions = tile.querySelector('.tile--img__dimensions');
- if (imgElement && dimensions) {
- // Parse dimensions (format: "2560 × 1677")
- const [width, height] = dimensions.textContent.split(' × ').map(Number);
- // Calculate total pixels and compare to 1920x1080 (2,073,600 pixels)
- const totalPixels = width * height;
- if (totalPixels < 2073600) {
- processedCount++; // Count as processed
- updateProgress(processedCount, totalCount);
- continue;
- }
- try {
- imgElement.click();
- const detailViewSuccess = await waitForDetailView();
- if (detailViewSuccess) {
- await extractAndClose();
- processedCount++;
- updateProgress(processedCount, totalCount);
- }
- } catch (error) {
- console.error('Error processing tile:', error);
- // Continue with next tile even if one fails
- }
- }
- await new Promise(resolve => setTimeout(resolve, 500)); // Increased delay between tiles
- }
- isProcessing = false;
- showPopup(stopProcessing ? "Extraction stopped" : "Extraction complete");
- // Show select all button
- const selectAllBtn = document.querySelector('#extractedLinksList + div button');
- if (selectAllBtn) {
- selectAllBtn.style.display = 'block';
- }
- }
- async function waitForDetailView() {
- return new Promise(resolve => {
- const checkInterval = setInterval(() => {
- const detailBtn = document.querySelector('a.c-detail__btn, .detail__media, .detail__content');
- if (detailBtn) {
- clearInterval(checkInterval);
- resolve(true);
- }
- }, 200);
- setTimeout(() => {
- clearInterval(checkInterval);
- resolve(false);
- }, 3000);
- });
- }
- async function extractAndClose() {
- const linkElement = document.querySelector('a.c-detail__btn');
- if (linkElement) {
- const href = linkElement.getAttribute('href');
- if (href) {
- displaySingleLink(href);
- }
- }
- const closeButton = document.querySelector('a.detail__close');
- if (closeButton) {
- closeButton.click();
- await new Promise(resolve => setTimeout(resolve, 500)); // Increased delay after close
- // await waitForClose(); //removed waitForClose function
- }
- }
- function displaySingleLink(link) {
- let linkList = document.getElementById('extractedLinksList');
- if (!linkList) {
- createLinkLists();
- linkList = document.getElementById('extractedLinksList');
- }
- if (!linkList) {
- linkList = document.createElement('div');
- linkList.id = 'extractedLinksList';
- linkList.style.position = 'fixed';
- linkList.style.top = '10px';
- linkList.style.left = '10px';
- linkList.style.backgroundColor = '#f5f5f5';
- linkList.style.border = '1px solid #ddd';
- linkList.style.padding = '10px';
- linkList.style.zIndex = '1000';
- linkList.style.maxHeight = '33vh';
- linkList.style.overflowY = 'auto';
- linkList.style.width = '300px';
- linkList.style.borderRadius = '4px';
- linkList.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
- document.body.appendChild(linkList);
- }
- const ul = document.createElement('ul');
- ul.style.listStyle = 'none';
- ul.style.margin = '0';
- ul.style.padding = '0';
- const li = document.createElement('li');
- li.style.margin = '5px 0';
- li.style.padding = '8px';
- li.style.backgroundColor = 'white';
- li.style.border = '1px solid #eee';
- li.style.borderRadius = '3px';
- const a = document.createElement('a');
- a.href = link;
- a.textContent = link;
- a.target = "_blank";
- a.style.color = '#0077cc';
- a.style.textDecoration = 'none';
- a.style.wordBreak = 'break-all';
- a.style.display = 'block';
- a.addEventListener('mouseover', () => {
- a.style.textDecoration = 'underline';
- });
- a.addEventListener('mouseout', () => {
- a.style.textDecoration = 'none';
- });
- li.appendChild(a);
- ul.appendChild(li);
- linkList.appendChild(ul);
- // Update link counter
- const linkCounter = document.getElementById('linkCounter');
- if (linkCounter) {
- const linkCount = linkList.querySelectorAll('ul').length;
- linkCounter.textContent = `${linkCount} link${linkCount !== 1 ? 's' : ''}`;
- }
- }
- function showPopup(message) {
- const popup = document.createElement('div');
- popup.textContent = message;
- popup.style.position = 'fixed';
- popup.style.top = '50%';
- popup.style.left = '50%';
- popup.style.transform = 'translate(-50%, -50%)';
- popup.style.backgroundColor = 'white';
- popup.style.border = '1px solid black';
- popup.style.padding = '10px';
- popup.style.zIndex = '1001';
- document.body.appendChild(popup);
- setTimeout(() => {
- document.body.removeChild(popup);
- }, 2000);
- }
- function createLinkLists() {
- const container = document.createElement('div');
- container.style.position = 'fixed';
- container.style.top = '10px';
- container.style.left = '10px';
- container.style.zIndex = '1000';
- container.style.display = 'flex';
- container.style.flexDirection = 'column';
- container.style.gap = '10px';
- // Create select all button
- const selectAllBtn = document.createElement('button');
- selectAllBtn.textContent = 'Select All';
- selectAllBtn.style.position = 'absolute';
- selectAllBtn.style.left = '320px'; // Position to the right of the link boxes
- selectAllBtn.style.top = '10px'; // Align with top of first box
- selectAllBtn.style.zIndex = '1001';
- selectAllBtn.style.padding = '4px 8px';
- selectAllBtn.style.borderRadius = '3px';
- selectAllBtn.style.border = '1px solid #ccc';
- selectAllBtn.style.backgroundColor = '#f5f5f5';
- selectAllBtn.style.cursor = 'pointer';
- selectAllBtn.addEventListener('click', () => {
- const linkList = document.getElementById('extractedLinksList');
- if (linkList) {
- const range = document.createRange();
- range.selectNodeContents(linkList);
- const selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(range);
- }
- });
- // Create good links list
- const goodList = document.createElement('div');
- goodList.id = 'extractedLinksList';
- goodList.style.backgroundColor = '#f5f5f5';
- goodList.style.border = '1px solid #ddd';
- goodList.style.padding = '10px';
- goodList.style.maxHeight = '33vh';
- goodList.style.overflowY = 'auto';
- goodList.style.width = '300px';
- goodList.style.borderRadius = '4px';
- goodList.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
- goodList.style.position = 'relative'; // Needed for absolute positioning of counter
- // Create link counter
- const linkCounter = document.createElement('div');
- linkCounter.id = 'linkCounter';
- linkCounter.style.position = 'absolute';
- linkCounter.style.bottom = '5px';
- linkCounter.style.right = '10px';
- linkCounter.style.backgroundColor = 'rgba(255,255,255,0.8)';
- linkCounter.style.padding = '2px 6px';
- linkCounter.style.borderRadius = '3px';
- linkCounter.style.fontSize = '0.8em';
- linkCounter.style.color = '#666';
- linkCounter.textContent = '0 links';
- goodList.appendChild(linkCounter);
- container.appendChild(goodList);
- container.appendChild(selectAllBtn);
- document.body.appendChild(container);
- }
- function createControlPanel() {
- const panel = document.createElement('div');
- panel.style.position = 'fixed';
- panel.style.top = '10px';
- panel.style.right = '10px';
- panel.style.zIndex = '1000';
- panel.style.display = 'flex';
- panel.style.gap = '5px';
- panel.style.backgroundColor = 'white';
- panel.style.padding = '5px';
- panel.style.border = '1px solid #ccc';
- panel.style.borderRadius = '4px';
- const startButton = document.createElement('button');
- startButton.textContent = 'Start Extraction';
- startButton.addEventListener('click', processImageTiles);
- const stopButton = document.createElement('button');
- stopButton.textContent = 'Stop';
- stopButton.style.backgroundColor = '#ff4444';
- stopButton.addEventListener('click', () => {
- stopProcessing = true;
- });
- const progress = document.createElement('div');
- progress.id = 'extractionProgress';
- progress.style.marginLeft = '10px';
- progress.style.padding = '5px 10px';
- panel.appendChild(startButton);
- panel.appendChild(stopButton);
- panel.appendChild(progress);
- document.body.appendChild(panel);
- }
- function updateProgress(current, total) {
- const progress = document.getElementById('extractionProgress');
- if (progress) {
- progress.textContent = `${current}/${total} (${Math.round((current/total)*100)}%)`;
- progress.style.color = current === total ? 'green' : 'black';
- }
- }
- createControlPanel();
- })();