您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Click on collage size = browse through this collage; Alt + click on collage name = remove from this collage
当前为
// ==UserScript== // @name Torrent Collage Extensions for Gazelle // @version 1.02 // @description Click on collage size = browse through this collage; Alt + click on collage name = remove from this collage // @author Anakunda // @namespace https://gf.qytechs.cn/users/321857-anakunda // @match https://*/torrents.php?id=* // @grant GM_getValue // ==/UserScript== 'use strict'; if (!/\b(?:id)=(\d+)\b/i.test(document.location.search)) throw 'Unexpected URL format'; var torrentId = parseInt(RegExp.$1), auth = document.querySelector('input[name="auth"]'); if (auth == null) throw 'Auth not found'; const siteApiTimeframeStorageKey = document.location.hostname + ' API time frame'; const gazelleApiFrame = 10500; if (typeof GM_getValue == 'function') var redacted_api_key = GM_getValue('redacted_api_key'); try { var collages = JSON.parse(window.sessionStorage.collages) } catch(e) { collages = {} } if (!collages[document.domain]) collages[document.domain] = {}; document.querySelectorAll('table[id$="collages"] > tbody > tr > td > a').forEach(function(link) { if (!link.pathname.startsWith('/collages.php') || !/\b(?:id)=(\d+)\b/.test(link.search)) return; var collageId = parseInt(RegExp.$1), toggle, navLinks = [], numberColumn = link.parentNode.parentNode.querySelector('td.number_column'); link.onclick = evt => evt.button == 0 && evt.altKey ? removeFromCollage(collageId, link) : true; link.title = 'Use Alt + left click to remove from this collage'; if (numberColumn != null) { numberColumn.style.cursor = 'pointer'; numberColumn.onclick = loadCollage; numberColumn.title = collages[document.domain][collageId] ? 'Refresh' : 'Load collage for direct browsing'; } if (collages[document.domain][collageId]) { expandSection(); addCollageLinks(collages[document.domain][collageId]); } function addCollageLinks(collage) { var index = collage.torrentgroups.findIndex(group => group.id == torrentId); if (index < 0) { console.warn('Assertion failed: torrent', torrentId, 'not found in the collage', collage); return false; } link.style.color = 'white'; link.parentNode.parentNode.style = 'color:white; background-color: darkgoldenrod;'; var stats = document.createElement('span'); stats.textContent = `${index + 1} / ${collage.torrentgroups.length}`; stats.style = 'font-size: 8pt; color: antiquewhite; font-weight: 100; margin-left: 10px;'; navLinks.push(stats); link.parentNode.append(stats); if (collage.torrentgroups[index - 1]) { var a = document.createElement('a'); a.href = '/torrents.php?id=' + collage.torrentgroups[index - 1].id; a.textContent = '[\xA0<\xA0]'; a.title = getTitle(index - 1); a.style = 'color: chartreuse; margin-right: 10px;'; navLinks.push(a); link.parentNode.prepend(a); a = document.createElement('a'); a.href = '/torrents.php?id=' + collage.torrentgroups[0].id; a.textContent = '[\xA0<<\xA0]'; a.title = getTitle(0); a.style = 'color: chartreuse; margin-right: 5px;'; navLinks.push(a); link.parentNode.prepend(a); } if (collage.torrentgroups[index + 1]) { a = document.createElement('a'); a.href = '/torrents.php?id=' + collage.torrentgroups[index + 1].id; a.textContent = '[\xA0>\xA0]'; a.title = getTitle(index + 1); a.style = 'color: chartreuse; margin-left: 10px;'; navLinks.push(a); link.parentNode.append(a); a = document.createElement('a'); a.href = '/torrents.php?id=' + collage.torrentgroups[collage.torrentgroups.length - 1].id; a.textContent = '[\xA0>>\xA0]'; a.title = getTitle(collage.torrentgroups.length - 1); a.style = 'color: chartreuse; margin-left: 5px;'; navLinks.push(a); link.parentNode.append(a); } return true; function getTitle(index) { if (typeof index != 'number' || index < 0 || index >= collage.torrentgroups.length) return undefined; var title = collage.torrentgroups[index].musicInfo && Array.isArray(collage.torrentgroups[index].musicInfo.artists) ? collage.torrentgroups[index].musicInfo.artists.map(artist => artist.name).join(', ') + ' - ' : ''; if (collage.torrentgroups[index].name) title += collage.torrentgroups[index].name; if (collage.torrentgroups[index].year) title += ' (' + collage.torrentgroups[index].year + ')'; return title; } } function expandSection() { if (toggle === undefined) toggle = link.parentNode.parentNode.parentNode.querySelector('td > a[href="#"][onclick]'); if (toggle === null || toggle.dataset.expanded) return false; toggle.dataset.expanded = true; toggle.click(); return true; } function loadCollage(evt) { evt.target.disabled = true; navLinks.forEach(a => { a.remove() }); navLinks = []; var span = document.createElement('span'); span.textContent = '[\xA0loading...\xA0]'; span.style = 'color: red; background-color: white; margin-left: 10px;'; link.parentNode.append(span); queryAjaxAPI('collage', { id: collageId }).then(function(collage) { cacheCollage(collage); span.remove(); addCollageLinks(collage); evt.target.disabled = false; }); return false; } }); function cacheCollage(collage) { collages[document.domain][collage.id] = { id: collage.id, name: collage.name, torrentgroups: collage.torrentgroups.map(group => ({ id: group.id, musicInfo: group.musicInfo ? { artists: Array.isArray(group.musicInfo.artists) ? group.musicInfo.artists.map(artist => ({ name: artist.name })) : undefined, } : undefined, name: group.name, year: group.year, })), }; window.sessionStorage.collages = JSON.stringify(collages); } function removeFromCollage(collageId, node = null) { if (!confirm('Are you sure to remove from collage "' + node.textContent.trim() + '"?')) return false; var xhr = new XMLHttpRequest, params = new URLSearchParams({ action: 'manage_handle', collageid: collageId, groupid: torrentId, auth: auth.value, submit: 'Remove', }); xhr.open('POST', '/collages.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.setRequestHeader('Content-Length', params.toString().length); xhr.onreadystatechange = function() { if (xhr.readyState != XMLHttpRequest.HEADERS_RECEIVED) return; if (xhr.status >= 200 && xhr.status < 400) { if (node instanceof HTMLElement) node.parentNode.parentNode.remove(); else document.location.reload(); } else errorHandler(); xhr.abort(); }; xhr.onerror = errorHandler; xhr.send(params); return false; function errorHandler() { console.error('Failed to remove', torrentId, 'from collage', collageId, xhr) } } function queryAjaxAPI(action, params) { if (!action) return Promise.reject('Action missing'); var retryCount = 0; return new Promise(function(resolve, reject) { params = new URLSearchParams(params || undefined); params.set('action', action); var url = '/ajax.php?' + params, xhr = new XMLHttpRequest; queryInternal(); function queryInternal() { var now = Date.now(); try { var apiTimeFrame = JSON.parse(window.localStorage[siteApiTimeframeStorageKey]) } catch(e) { apiTimeFrame = {} } if (!apiTimeFrame.timeStamp || now > apiTimeFrame.timeStamp + gazelleApiFrame) { apiTimeFrame.timeStamp = now; apiTimeFrame.requestCounter = 1; } else ++apiTimeFrame.requestCounter; window.localStorage[siteApiTimeframeStorageKey] = JSON.stringify(apiTimeFrame); if (apiTimeFrame.requestCounter <= 5) { xhr.open('GET', url, true); xhr.setRequestHeader('Accept', 'application/json'); if (redacted_api_key) xhr.setRequestHeader('Authorization', prefs.redacted_api_key); xhr.responseType = 'json'; xhr.onload = function() { if (xhr.status == 404) return reject('not found'); if (xhr.status < 200 || xhr.status >= 400) return reject(defaultErrorHandler(xhr)); if (xhr.response.status == 'success') return resolve(xhr.response.response); if (xhr.response.error == 'not found') return reject(xhr.response.error); console.warn('queryAjaxAPI.queryInternal(...) response:', xhr, xhr.response); if (xhr.response.error == 'rate limit exceeded') { console.warn('queryAjaxAPI.queryInternal(...) ' + xhr.response.error + ':', apiTimeFrame, now, retryCount); if (retryCount++ <= 10) return setTimeout(queryInternal, apiTimeFrame.timeStamp + gazelleApiFrame - now); } reject('API ' + xhr.response.status + ': ' + xhr.response.error); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler(xhr)) }; xhr.send(); } else { setTimeout(queryInternal, apiTimeFrame.timeStamp + gazelleApiFrame - now); console.debug('AJAX API request quota exceeded: /ajax.php?action=' + action + ' (' + apiTimeFrame.requestCounter + ')'); } } }); } function defaultErrorHandler(response) { console.error('HTTP error:', response); var e = 'HTTP error ' + response.status; if (response.statusText) e += ' (' + response.statusText + ')'; if (response.error) e += ' (' + response.error + ')'; return e; } function defaultTimeoutHandler(response) { console.error('HTTP timeout:', response); const e = 'HTTP timeout'; return e; }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址