您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a "Download Cover" button below Share/Embed on all Bandcamp album/track pages. Downloads the highest resolution album cover (_0.jpg/png)
// ==UserScript== // @name Bandcamp Download Cover Button // @namespace nj4442.bc.downloadscript // @version 2.0 // @description Adds a "Download Cover" button below Share/Embed on all Bandcamp album/track pages. Downloads the highest resolution album cover (_0.jpg/png) // @author nj4442 // @match *://*.bandcamp.com/album/* // @match *://*.bandcamp.com/track/* // @license CC-BY-4.0 // ==/UserScript== (function() { 'use strict'; // Stig's Art Grabr logic for Bandcamp covers only function getHiResBandcampCover(url) { // Only operate on jpg/png ending with _<number>.jpg/png let hiRes = url.replace(/_\d{1,2}\.(jpg|png)$/i, '_0.$1'); return hiRes; } function getAccentColor() { // Try to get accent color from .primaryText or .compound-button or use fallback const accentElem = document.querySelector('.primaryText, .compound-button'); if (accentElem) { const color = getComputedStyle(accentElem).color || ''; // Convert rgb to hex if needed if (color.startsWith('rgb')) { const rgb = color.match(/\d+/g); if (rgb && rgb.length >= 3) { return `#${((1 << 24) + (parseInt(rgb[0]) << 16) + (parseInt(rgb[1]) << 8) + parseInt(rgb[2])).toString(16).slice(1)}`; } } return color; } // Fallback accent return '#f2a6ea'; } function onReady(fn) { if (document.readyState !== 'loading') { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } } onReady(function() { const shareLi = document.querySelector('.share-collect-controls li.share-embed'); if (!shareLi) return; if (document.querySelector('.bandcamp-cover-download-btn')) return; // Find the cover image <a> and <img> const artContainer = document.querySelector('#tralbumArt'); if (!artContainer) return; const imgLink = artContainer.querySelector('a.popupImage'); if (!imgLink) return; const img = imgLink.querySelector('img'); if (!img) return; let coverUrl = imgLink.getAttribute('href'); if (!coverUrl) return; // Upgrade to hi-res using Stig's logic for Bandcamp coverUrl = getHiResBandcampCover(coverUrl); // Filename let defaultFilename = 'bandcamp_cover.jpg'; const title = document.querySelector('.trackTitle')?.textContent.trim(); const artist = document.querySelector('#name-section h3 a')?.textContent.trim() || document.querySelector('.albumTitle span[itemprop="byArtist"]')?.textContent.trim(); if (title && artist) { defaultFilename = `${artist.replace(/[^\w-]/g, '_')}-${title.replace(/[^\w-]/g, '_')}_cover.jpg`; } // Accent color const accent = getAccentColor(); // Create the button const btn = document.createElement('button'); btn.textContent = 'Download Cover'; btn.className = 'bandcamp-cover-download-btn'; btn.style.margin = '5px 0 0 0'; btn.style.background = accent + '22'; // transparent (hex alpha 22) btn.style.color = accent; btn.style.border = 'none'; btn.style.padding = '2px 10px'; btn.style.fontSize = '0.95em'; btn.style.borderRadius = '3px'; btn.style.cursor = 'pointer'; btn.style.display = 'block'; btn.style.fontWeight = '400'; btn.style.opacity = '0.92'; btn.style.transition = 'background 0.2s, opacity 0.2s, color 0.2s'; btn.onmouseenter = () => { btn.style.background = accent; btn.style.color = '#fff'; btn.style.opacity = '1'; }; btn.onmouseleave = () => { btn.style.background = accent + '22'; btn.style.color = accent; btn.style.opacity = '0.92'; }; btn.addEventListener('click', function(e) { e.preventDefault(); const a = document.createElement('a'); a.href = coverUrl; a.download = defaultFilename; document.body.appendChild(a); a.click(); document.body.removeChild(a); }); // Place directly after the Share/Embed li const newLi = document.createElement('li'); newLi.style.listStyle = 'none'; newLi.appendChild(btn); shareLi.insertAdjacentElement('afterend', newLi); }); })();