您需要先安装一个扩展,例如 篡改猴、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.20 // @description Click on collage size = browse through this collage; Alt + click on collage name = remove from this collage // @author Anakunda // @license GPL-3.0-or-later // @copyright 2020, Anakunda (https://openuserjs.org/users/Anakunda) // @namespace https://gf.qytechs.cn/users/321857-anakunda // @match https://*/torrents.php?id=* // @match https://*/collages.php?*id=* // @match https://*/artist.php?*id=* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== 'use strict'; var auth = document.querySelector('input[name="auth"][value]'); if (auth != null) auth = auth.value; else { auth = document.querySelector('li#nav_logout > a'); if (auth != null && /\b(?:auth)=(\w+)\b/.test(auth.search)) auth = RegExp.$1; else throw 'Auth not found'; } let userId = document.querySelector('li#nav_userinfo > a.username'); if (userId != null) { userId = new URLSearchParams(userId.search); userId = parseInt(userId.get('id')); } 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'); function queryAjaxAPI(action, params) { if (!action) return Promise.reject('Action missing'); let retryCount = 0; return new Promise(function(resolve, reject) { params = new URLSearchParams(params || undefined); params.set('action', action); let url = '/ajax.php?' + params, xhr = new XMLHttpRequest; queryInternal(); function queryInternal() { let 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', redacted_api_key); xhr.responseType = 'json'; //xhr.timeout = 5 * 60 * 1000; 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 addToTorrentCollage(collageId, torrentGroupId) { return collageId ? torrentGroupId ? queryAjaxAPI('collage', { id: collageId }).then( collage => !collage.torrentGroupIDList.map(groupId => parseInt(groupId)).includes(torrentGroupId) ? collageId : Promise.reject('already in collage') ).then(collageId => new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest, formData = new URLSearchParams({ action: 'add_torrent', collageid: collageId, groupid: torrentGroupId, url: document.location.origin.concat('/torrents.php?id=', torrentGroupId), auth: auth, }); xhr.open('POST', '/collages.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) return; if (xhr.status >= 200 && xhr.status < 400) resolve(collageId); else reject(defaultErrorHandler(xhr)); xhr.abort(); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler(xhr)) }; xhr.send(formData); })).then(collageId => queryAjaxAPI('collage', { id: collageId }).then( collage => collage.torrentGroupIDList.map(groupId => parseInt(groupId)).includes(torrentGroupId) ? collage : Promise.reject('Error: not added for unknown reason') )) : Promise.reject('torrent group id not defined') : Promise.reject('collage id not defined'); } function removeFromTorrentCollage(collageId, torrentGroupId, question) { if (!confirm(question)) return Promise.reject('Cancelled'); return new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest, formData = new URLSearchParams({ action: 'manage_handle', collageid: collageId, groupid: torrentGroupId, auth: auth, submit: 'Remove', }); xhr.open('POST', '/collages.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) return; if (xhr.status >= 200 && xhr.status < 400) resolve(xhr.status); else reject(defaultErrorHandler(xhr)); xhr.abort(); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler(xhr)) }; xhr.send(formData); }); } function addToArtistCollage(collageId, artistId) { return collageId ? artistId ? queryAjaxAPI('collage', { id: collageId }).then( collage => !collage.artists.map(artist => parseInt(artist.id)).includes(artistId) ? collageId : Promise.reject('already in collage') ).then(collageId => new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest, formData = new URLSearchParams({ action: 'add_artist', collageid: collageId, artistid: artistId, url: document.location.origin.concat('/artist.php?id=', artistId), auth: auth, }); xhr.open('POST', '/collages.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) return; if (xhr.status >= 200 && xhr.status < 400) resolve(collageId); else reject(defaultErrorHandler(xhr)); xhr.abort(); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler(xhr)) }; xhr.send(formData); })).then(collageId => queryAjaxAPI('collage', { id: collageId }).then( collage => collage.artists.map(artist => parseInt(artist.id)).includes(artistId) ? collage : Promise.reject('Error: not added for unknown reason') )) : Promise.reject('artist id not defined') : Promise.reject('collage id not defined'); } function removeFromArtistCollage(collageId, artistId, question) { if (!confirm(question)) return Promise.reject('Cancelled'); return new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest, formData = new URLSearchParams({ action: 'manage_artists_handle', collageid: collageId, artistid: artistId, auth: auth, submit: 'Remove', }); xhr.open('POST', '/collages.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) return; if (xhr.status >= 200 && xhr.status < 400) resolve(xhr.status); else reject(defaultErrorHandler(xhr)); xhr.abort(); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler(xhr)) }; xhr.send(formData); }); } function defaultErrorHandler(response) { console.error('HTTP error:', response); let 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; } function addQuickAddForm() { const timeout = 30000; // some collages take to load long const initTimeCap = 2000; // max time in ms to preload the dropdown if (!userId || !torrentGroupId && !artistId) return; // User id missing let ref = document.querySelector('div.sidebar'); if (ref == null) return; // Sidebar missing const addSuccess = 'Successfully added to collage.'; const alreadyInCollage = 'Error: This ' + (torrentGroupId ? 'torrent group' : artistId ? 'artist' : null) + ' is already in this collage'; new Promise(function(resolve, reject) { try { var categories = JSON.parse(GM_getValue(document.location.hostname + '-categories')); if (categories.length > 0) resolve(categories); else throw 'empty list cached'; } catch(e) { let xhr = new XMLHttpRequest; xhr.open('GET', '/collages.php', true); xhr.responseType = 'document'; xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 400) { categories = [ ]; xhr.response.querySelectorAll('tr#categories > td > label').forEach(function(label, index) { let input = xhr.response.querySelector('tr#categories > td > input#' + label.htmlFor); categories[input != null && /\[(\d+)\]/.test(input.name) ? parseInt(RegExp.$1) : index] = label.textContent.trim(); }); if (categories.length > 0) { GM_setValue(document.location.hostname + '-categories', JSON.stringify(categories)); resolve(categories); } else reject('Site categories could not be extracted'); } else reject(defaultErrorHandler(xhr)); }; xhr.onerror = function() { reject(defaultErrorHandler(xhr)) }; xhr.ontimeout = function() { reject(defaultTimeoutHandler()) }; xhr.timeout = timeout; xhr.send(); } }).then(function(categories) { const artistsIndex = categories.indexOf('Artists'); if (artistId && artistsIndex < 0) throw 'Artists index not found'; document.head.appendChild(document.createElement('style')).innerHTML = ` form#addtocollage optgroup { background-color: slategray; color: white; } form#addtocollage option { background-color: white; color: black; max-width: 290pt; } div.box_addtocollage > form { padding: 0px 10px; } `; let elem = document.createElement('div'); elem.className = 'box box_addtocollage'; elem.style = 'padding: 0 0 10px;'; elem.innerHTML = ` <div class="head" style="margin-bottom: 5px;"><strong>Add to Collage</strong></div> <div id="ajax_message" class="hidden center" style="padding: 7px 0px;"></div> <form id="searchcollages"> <input id="searchforcollage" placeholder="Collage search" type="text"> <input id="searchforcollagebutton" value="Search" type="submit" style="max-width: 4em;"> </form> <form id="addtocollage" class="add_form" name="addtocollage"> <select name="collageid" id="matchedcollages" class="add_to_collage_select" style="width: 96%;"> <input id="opencollage-btn" value="Open collage" type="button"> <input id="addtocollage-btn" value="Add to collage" type="button"> </form> `; ref.append(elem); let ajaxMessage = document.getElementById('ajax_message'); let srchForm = document.getElementById('searchcollages'); if (srchForm == null) throw new Error('#searchcollages missing'); let searchText = document.getElementById('searchforcollage'); if (searchText == null) throw new Error('#searchforcollage missing'); let dropDown = document.getElementById('matchedcollages'); if (dropDown == null) throw new Error('#matchedcollages missing'); let doOpen = document.getElementById('opencollage-btn'); let doAdd = document.getElementById('addtocollage-btn'); if (doAdd == null) throw new Error('#addtocollage-btn missing'); srchForm.onsubmit = searchSubmit; searchText.ondrop = evt => dataHandler(evt.target, evt.dataTransfer); searchText.onpaste = evt => dataHandler(evt.target, evt.clipboardData); if (doOpen != null) doOpen.onclick = openCollage; doAdd.onclick = addToCollage; findCollages({ userid: userId, contrib: 1 }, initTimeCap); function clearList() { while (dropDown.childElementCount > 0) dropDown.removeChild(dropDown.firstElementChild); } function findCollages(query, maxSearchTime) { return typeof query == 'object' ? new Promise(function(resolve, reject) { let start = Date.now(); searchFormEnable(false); clearList(); elem = document.createElement('option'); elem.text = 'Searching...'; dropDown.add(elem); dropDown.selectedIndex = 0; let retryCount = 0, options = [ ]; searchInternal(); function searchInternal(page) { if (maxSearchTime > 0 && Date.now() - start > maxSearchTime) { reject('Time limit exceeded'); return; } let xhr = new XMLHttpRequest, _query = new URLSearchParams(query); if (!page) page = 1; _query.set('page', page); xhr.open('GET', '/collages.php?' + _query, true); xhr.responseType = 'document'; xhr.onload = function() { if (xhr.status < 200 || xhr.status >= 400) throw defaultErrorHandler(xhr); xhr.response.querySelectorAll('table.collage_table > tbody > tr[class^="row"]').forEach(function(tr, rowNdx) { if ((ref = tr.querySelector(':scope > td:nth-of-type(1) > a')) == null) { console.warn('Page parsing error'); return; } elem = document.createElement('option'); if ((elem.category = categories.findIndex(category => category.toLowerCase() == ref.textContent.toLowerCase())) < 0 && /\b(?:cats)\[(\d+)\]/i.test(ref.search)) elem.category = parseInt(RegExp.$1); // unsafe due to site bug if ((ref = tr.querySelector(':scope > td:nth-of-type(2) > a')) == null || !/\b(?:id)=(\d+)\b/i.test(ref.search)) { console.warn(`Unknown collage id (${xhr.responseURL}/${rowNdx})`); return; } elem.value = elem.collageId = parseInt(RegExp.$1); elem.text = elem.title = ref.textContent.trim(); if ((ref = tr.querySelector(':scope > td:nth-of-type(3)')) != null) elem.size = parseInt(ref.textContent); if ((ref = tr.querySelector(':scope > td:nth-of-type(4)')) != null) elem.subscribers = parseInt(ref.textContent); if ((ref = tr.querySelector(':scope > td:nth-of-type(6) > a')) != null && /\b(?:id)=(\d+)\b/i.test(ref.search)) elem.author = parseInt(RegExp.$1); if (elem.category < categories.length && (torrentGroupId && elem.category != artistsIndex || artistId && elem.category == artistsIndex) && (elem.category != 0 || elem.author == userId)) options.push(elem); }); if (xhr.response.querySelector('div.linkbox > a.pager_next') != null) searchInternal(page + 1); else { if (!Object.keys(query).includes('order')) options.sort((a, b) => (b.size || 0) - (a.size || 0)/*a.title.localeCompare(b.title)*/); resolve(options); } }; xhr.onerror = function() { if (xhr.status == 0 && retryCount++ <= 10) setTimeout(function() { searchInternal(page) }, 200); else reject(defaultErrorHandler(xhr)); }; xhr.ontimeout = function() { reject(defaultTimeoutHandler()) }; xhr.timeout = timeout; xhr.send(); } }).then(function(options) { clearList(); categories.forEach(function(category, ndx) { let _category = options.filter(option => option.category == ndx); if (_category.length <= 0) return; elem = document.createElement('optgroup'); elem.label = category; elem.append(..._category); dropDown.add(elem); }); dropDown.selectedIndex = 0; searchFormEnable(true); return options; }).catch(function(reason) { clearList(); searchFormEnable(true); console.warn(reason); }) : Promise.reject('Invalid parameter'); } function searchFormEnable(enabled) { for (let i = 0; i < srchForm.length; ++i) srchForm[i].disabled = !enabled; } function searchSubmit(evt) { let searchTerm = searchText.value.trim(); if (searchTerm.length <= 0) return false; let query = { action: 'search', search: searchTerm, type: 'c.name', order: 'Updated', sort: 'desc', order_way: 'Descending', }; categories.map((category, ndx) => 'cats[' + ndx + ']') .filter((category, ndx) => torrentGroupId && ndx != artistsIndex || artistId && ndx == artistsIndex) .forEach(param => { query[param] = 1 }); findCollages(query); return false; } function addToCollage(evt) { (function() { evt.target.disabled = true; if (ajaxMessage != null) ajaxMessage.classList.add('hidden'); let collageId = parseInt(dropDown.value); if (!collageId) return Promise.reject('No collage selected'); /* if (Array.from(document.querySelectorAll('table.collage_table > tbody > tr:not([class="colhead"]) > td > a')) .map(node => /\b(?:id)=(\d+)\b/i.test(node.search) && parseInt(RegExp.$1)).includes(collageId)) return Promise.reject(alreadyInCollage); */ if (torrentGroupId) return addToTorrentCollage(collageId, torrentGroupId); if (artistId) return addToArtistCollage(collageId, artistId); return Promise.reject('munknown page class'); })().then(function(collage) { if (ajaxMessage != null) { ajaxMessage.innerHTML = '<span style="color: #0A0;">' + addSuccess + '</span>'; ajaxMessage.classList.remove('hidden'); } evt.target.disabled = false; let mainColumn = document.querySelector('div.main_column'); if (mainColumn == null) return collage; let tableName = collage.collageCategoryID != 0 ? 'collages' : 'personal_collages' let tbody = mainColumn.querySelector('table#' + tableName + ' > tbody'); if (tbody == null) { tbody = document.createElement('tbody'); tbody.innerHTML = '<tr class="colhead"><td width="85%"><a href="#">↑</a> </td><td># torrents</td></tr>'; elem = document.createElement('table'); elem.id = tableName; elem.className = 'collage_table'; elem.append(tbody); mainColumn.insertBefore(elem, [ 'table#personal_collages', 'table#vote_matches', 'div.torrent_description', 'div#similar_artist_map', 'div#artist_information', ].reduce((acc, selector) => acc || document.querySelector(selector), null)); } tableName = '\xA0This ' + (collage.collageCategoryID != artistsIndex ? 'album' : 'artist') + ' is in ' + tbody.childElementCount + ' ' + (collage.collageCategoryID != 0 ? 'collage' : 'personal collage'); if (tbody.childElementCount > 1) tableName += 's'; tbody.firstElementChild.firstElementChild.childNodes[1].data = tableName; elem = document.createElement('tr'); elem.className = 'collage_rows'; if (tbody.querySelector('tr.collage_rows.hidden') != null) elem.classList.add('hidden'); elem.innerHTML = '<td><a href="/collages.php?id=' + collage.id + '">' + collage.name + '</a></td><td class="number_column">' + (collage.collageCategoryID != artistsIndex ? collage.torrentgroups : collage.artists).length + '</td>'; tbody.append(elem); return collage; }).catch(function(reason) { evt.target.disabled = false; if (ajaxMessage == null) return; ajaxMessage.innerHTML = '<span style="color: #A00;">' + reason.toString() + '</span>'; ajaxMessage.classList.remove('hidden'); }); } function openCollage(evt) { let collageId = parseInt(dropDown.value); if (collageId <= 0) return false; let win = window.open('/collages.php?id=' + collageId, '_blank'); win.focus(); } function dataHandler(target, data) { var text = data.getData('text/plain'); if (!text) return true; target.value = text; srchForm.onsubmit(); return false; } }); } switch (document.location.pathname) { case '/torrents.php': { var torrentGroupId = new URLSearchParams(document.location.search).get('id'), collages; if (torrentGroupId) torrentGroupId = parseInt(torrentGroupId); else break; // Unexpected URL format const searchforcollage = document.getElementById('searchforcollage'); if (searchforcollage != null) { if (typeof SearchCollage == 'function') SearchCollage = () => { const searchTerm = $('#searchforcollage').val(), personalCollages = $('#personalcollages'); ajax.get(`ajax.php?action=collages&search=${encodeURIComponent(searchTerm)}`, responseText => { const { response, status } = JSON.parse(responseText); if (status !== 'success') return; const categories = response.reduce((accumulator, item) => { const { collageCategoryName } = item; accumulator[collageCategoryName] = (accumulator[collageCategoryName] || []).concat(item); return accumulator; }, {}); personalCollages.children().remove(); Object.entries(categories).forEach(([category, collages]) => { console.log(collages); personalCollages.append(` <optgroup label="${category}"> ${collages.reduce((accumulator, { id, name }) => `${accumulator}<option value="${id}">${name}</option>` ,'')} </optgroup> `); }); }); }; function inputHandler(evt, key) { const data = evt[key].getData('text/plain').trim(); if (!data) return true; evt.target.value = data; SearchCollage(); setTimeout(function() { const add_to_collage_select = document.querySelector('select.add_to_collage_select'); if (add_to_collage_select != null && add_to_collage_select.options.length > 1) { // TODO: expand } }, 3000); return false; } searchforcollage.onpaste = evt => inputHandler(evt, 'clipboardData'); searchforcollage.ondrop = evt => inputHandler(evt, 'dataTransfer'); searchforcollage.onkeypress = evt => { if (evt.key == 'Enter') SearchCollage() }; } else addQuickAddForm(); try { 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; let collageId = parseInt(RegExp.$1), toggle, navLinks = [], numberColumn = link.parentNode.parentNode.querySelector('td.number_column'); link.onclick = function(evt) { return evt.button == 0 && evt.altKey ? removeFromTorrentCollage(collageId, torrentGroupId, 'Are you sure to remove this group from collage "' + link.textContent.trim() + '"?') .then(status => { link.parentNode.parentNode.remove() }) : 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 == torrentGroupId); if (index < 0) { console.warn('Assertion failed: torrent', torrentGroupId, '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; let 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) { span.remove(); cacheCollage(collage); addCollageLinks(collage); evt.target.disabled = false; }, function(reason) { span.remove(); 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); } break; } case '/artist.php': { var artistId = new URLSearchParams(document.location.search).get('id'); if (artistId) artistId = parseInt(artistId); else break; // Unexpected URL format addQuickAddForm(); break; } case '/collages.php': { var collageId = new URLSearchParams(document.location.search).get('id'); if (collageId) collageId = parseInt(collageId); else break; // Collage id missing let category = document.querySelector('div.box_category > div.pad > a'); category = category != null ? category.textContent : undefined; function scanPage() { if (category != 'Artists') { var sel = [ 'tr.group > td[colspan] > strong > a[href^="torrents.php?id="]', 'ul.collage_images > li > a[href^="torrents.php?id="]', ] document.querySelectorAll(sel.join(', ')).forEach(function(a) { a.onclick = function(evt) { if (evt.button != 0 || !evt.altKey) return true; let torrentGroupId = new URLSearchParams(a.search); torrentGroupId = torrentGroupId.get('id'); if (torrentGroupId) torrentGroupId = parseInt(torrentGroupId); else { console.warn('Assertion failed: no id', a); throw 'no id'; } removeFromTorrentCollage(collageId, torrentGroupId, 'Are you sure to remove selected group from this collage?').then(function(status) { document.querySelectorAll(sel.join(', ')).forEach(function(a) { if (parseInt(new URLSearchParams(a.search).get('id')) == torrentGroupId) switch (a.parentNode.nodeName) { case 'STRONG': a.parentNode.parentNode.parentNode.remove(); break; case 'LI': a.parentNode.remove(); break; } }); }); }; }); } else { sel = [ 'table#discog_table > tbody > tr > td > a[href^="artist.php?id="]', 'ul.collage_images > li > a[href^="artist.php?id="]', ]; document.querySelectorAll(sel.join(', ')).forEach(function(a) { a.onclick = function(evt) { if (evt.button != 0 || !evt.altKey) return true; let artistId = new URLSearchParams(a.search); artistId = artistId.get('id'); if (artistId) artistId = parseInt(artistId); else { console.warn('Assertion failed: no id', a); throw 'no id'; } removeFromArtistCollage(collageId, artistId, 'Are you sure to remove selected artist from this collage?').then(function(status) { document.querySelectorAll(sel.join(', ')).forEach(function(a) { if (parseInt(new URLSearchParams(a.search).get('id')) == artistId) switch (a.parentNode.nodeName) { case 'TD': a.parentNode.parentNode.remove(); break; case 'LI': a.parentNode.remove(); break; } }); }); }; }); } } scanPage(); document.querySelectorAll('div#pageslinksdiv > span > a.pageslink') .forEach(a => { a.addEventListener('click', evt => { setTimeout(scanPage, 1000) }) }); break; } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址