您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为Spotify网页播放器添加下载全尺寸封面艺术的按钮
当前为
// ==UserScript== // @name Spotify Web - Download Cover // @name:es Spotify Web - Descargar portada // @name:pt Spotify Web - Descarregar capa // @name:pt-BR Spotify Web - Baixar capa // @name:it Spotify Web - Scarica copertina // @name:fr Spotify Web - Télécharger pochette // @name:de Spotify Web - Cover herunterladen // @name:ru Spotify Web - Скачать обложку // @name:zh-CN Spotify Web - 下载封面 // @name:ja Spotify Web - カバーをダウンロード // @namespace http://tampermonkey.net/ // @description Adds a button to download the full size cover art from Spotify Web Player // @description:es Agrega un botón para descargar la portada en tamaño completo del reproductor web de Spotify // @description:pt Adiciona um botão para baixar a capa em tamanho completo do reproductor web do Spotify // @description:pt-BR Adiciona um botão para baixar a capa em tamanho real do Spotify Web Player // @description:it Aggiunge un pulsante per scaricare la copertina a dimensione piena dal lettore web di Spotify // @description:fr Ajoute un bouton pour télécharger la pochette en taille réelle depuis le lecteur web Spotify // @description:de Fügt eine Schaltfläche zum Herunterladen des Covers in voller Größe vom Spotify Web Player hinzu // @description:ru Добавляет кнопку для скачивания обложки в полном размере из веб-плеера Spotify // @description:zh-CN 为Spotify网页播放器添加下载全尺寸封面艺术的按钮 // @description:ja Spotify Web Playerからフルサイズのカバーアートをダウンロードするボタンを追加します // @version 1.7.0 // @match https://open.spotify.com/* // @author Levi Somerset // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=spotify.com // @grant GM_download // @grant GM_xmlhttpRequest // @grant window.onurlchange // @connect i.scdn.co // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // ==/UserScript== (function() { 'use strict'; const CONFIG = { COVER_BASE: 'https://i.scdn.co/image/', SIZES: ['ab67616d0000b273', 'ab67616d00001e02', 'ab67616d00004851'], FULL_SIZE: 'ab67616d000082c1', DEBOUNCE_DELAY: 300 }; const translations = { en: ['Download Cover', 'Cover downloaded: %s', 'Failed to download cover'], es: ['Descargar portada', 'Portada descargada: %s', 'No se pudo descargar la portada'], pt: ['Baixar capa', 'Capa baixada: %s', 'Falha ao baixar a capa'], "pt-BR": ['Baixar capa', 'Capa baixada: %s', 'Falha ao baixar a capa'], it: ['Scarica copertina', 'Copertina scaricata: %s', 'Impossibile scaricare la copertina'], fr: ['Télécharger pochette', 'Pochette téléchargée: %s', 'Échec du téléchargement de la pochette'], de: ['Cover herunterladen', 'Cover heruntergeladen: %s', 'Cover konnte nicht heruntergeladen werden'], ru: ['Скачать обложку', 'Обложка скачана: %s', 'Не удалось скачать обложку'], "zh-CN": ['下载封面', '封面已下载: %s', '下载封面失败'], ja: ['カバーをダウンロード', 'カバーがダウンロードされました: %s', 'カバーのダウンロードに失敗しました'] }; function initScript(saveAs) { let [buttonText, downloadedText, errorText] = translations.en; // Set language based on browser settings const lang = navigator.language.split('-')[0]; if (lang in translations) { [buttonText, downloadedText, errorText] = translations[lang]; } // Add styles const style = document.createElement('style'); style.innerText = ` .cover-download-btn { display: flex; align-items: center; justify-content: center; background-color: transparent; border: none; color: #b3b3b3; cursor: pointer; transition-duration: 33ms; transition-property: color, transform; transition-timing-function: cubic-bezier(.3,0,.4,1); padding: 0; box-sizing: border-box; margin-left: 0; position: relative; } .cover-download-btn:hover { color: #ffffff; transform: scale(1.04); } .cover-download-btn:active { transform: scale(1); } `; document.head.appendChild(style); function downloadImage(imageSrc, fileName) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: imageSrc, responseType: 'blob', onload: function(response) { try { const blob = response.response; saveAs(blob, fileName); showInfo(downloadedText.replace('%s', fileName), 'success'); resolve(); } catch (error) { console.error('Error saving file:', error); reject(error); } }, onerror: function(error) { console.error('Error downloading image:', error); reject(error); } }); }); } const albumInfoCache = new Map(); function getAlbumInfo() { const cacheKey = window.location.href; if (albumInfoCache.has(cacheKey)) { return albumInfoCache.get(cacheKey); } let artistName, albumName; const artistElements = document.querySelectorAll('a[data-testid="creator-link"]'); if (artistElements.length > 0) { const artistNames = Array.from(artistElements).map(el => el.textContent.trim()); artistName = artistNames.join(', '); } const albumHeading = document.querySelector('span[data-testid="entityTitle"] h1[data-encore-id="text"]'); if (albumHeading) { albumName = albumHeading.textContent.trim(); } if (!albumName) { const possibleAlbumSelectors = [ 'h1[data-encore-id="text"]', '.gj6rSoF7K4FohS2DJDEm', 'span[data-testid="entityTitle"]' ]; for (const selector of possibleAlbumSelectors) { const element = document.querySelector(selector); if (element) { albumName = element.textContent.trim(); break; } } } console.log("Found album info:", { artist: artistName, album: albumName }); const info = { artist: artistName || 'Unknown Artist', album: albumName || 'Unknown Album' }; albumInfoCache.set(cacheKey, info); return info; } function findAlbumCover() { const albumPageSection = document.querySelector('section[data-testid="album-page"]'); if (!albumPageSection) { return null; } // Пробуем несколько селекторов для обложки let coverElement = albumPageSection.querySelector('img[srcset*="i.scdn.co/image/"][sizes]') || albumPageSection.querySelector('img[src*="i.scdn.co/image/"]') || albumPageSection.querySelector('button img[src*="i.scdn.co/image/"]'); if (!coverElement) { const modalButton = albumPageSection.querySelector('button[class*="_osiFNXU9Cy1X0CYaU9Z"]'); if (modalButton) { coverElement = modalButton.querySelector('img[src*="i.scdn.co/image/"]'); } } if (coverElement) { return coverElement; } return null; } function getFullSizeCoverUrl() { const coverElement = findAlbumCover(); if (!coverElement) { console.log('Cover element not found'); return null; } const coverUrl = coverElement.src; for (const size of CONFIG.SIZES) { if (coverUrl.includes(size)) { return coverUrl.replace(size, CONFIG.FULL_SIZE); } } console.log('Failed to extract cover hash'); return null; } function debounce(func, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } function shouldShowButton() { return window.location.pathname.startsWith('/album/'); } function createDownloadButton() { const button = document.createElement('button'); button.className = 'Button-sc-1dqy6lx-0 iwlsM e-9890-overflow-wrap-anywhere e-9890-button-tertiary--icon-only e-9890-button-tertiary--condensed cover-download-btn'; button.setAttribute('data-encore-id', 'buttonTertiary'); button.setAttribute('title', buttonText); button.setAttribute('aria-label', buttonText); button.innerHTML = ` <span aria-hidden="true" class="e-9890-button__icon-wrapper"> <svg data-encore-id="icon" role="img" aria-hidden="true" class="e-9890-icon e-9890-baseline" viewBox="0 0 24 24" style="--encore-icon-height: var(--encore-graphic-size-decorative-larger); --encore-icon-width: var(--encore-graphic-size-decorative-larger);"> <path d="M11.999 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zm-11 9c0-6.075 4.925-11 11-11s11 4.925 11 11-4.925 11-11 11-11-4.925-11-11z"></path> <path d="M12 6.05a1 1 0 0 1 1 1v7.486l1.793-1.793a1 1 0 1 1 1.414 1.414L12 18.364l-4.207-4.207a1 1 0 1 1 1.414-1.414L11 14.536V7.05a1 1 0 0 1 1-1z"></path> </svg> </span> `; return button; } function addDownloadButton() { if (!shouldShowButton()) return; let actionBarRow = document.querySelector('[data-testid="action-bar-row"]'); if (!actionBarRow) return; if (actionBarRow.querySelector('.cover-download-btn')) return; const moreButton = actionBarRow.querySelector('[data-testid="more-button"]'); if (!moreButton) return; const downloadButton = createDownloadButton(); moreButton.parentNode.insertBefore(downloadButton, moreButton.nextSibling); downloadButton.addEventListener('click', async function() { const fullSizeCoverUrl = getFullSizeCoverUrl(); if (fullSizeCoverUrl) { try { const albumInfo = getAlbumInfo(); const fileName = `${albumInfo.artist} - ${albumInfo.album}.jpg`; await downloadImage(fullSizeCoverUrl, fileName); } catch (error) { showInfo(errorText, 'error'); } } else { showInfo(errorText, 'error'); } }); } function removeDownloadButton() { const existingButton = document.querySelector('.cover-download-btn'); if (existingButton) { existingButton.remove(); } } function addOrRemoveButton() { if (shouldShowButton()) { addDownloadButton(); } else { removeDownloadButton(); } } function showInfo(str, type = 'success') { const infoDiv = document.createElement('div'); infoDiv.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: ${type === 'success' ? '#1db954' : '#ff4444'}; color: white; padding: 10px 20px; border-radius: 5px; z-index: 9999; font-family: spotify-circular, Helvetica, Arial, sans-serif; font-weight: 700; `; infoDiv.textContent = str; document.body.appendChild(infoDiv); setTimeout(() => infoDiv.remove(), 3000); } const debouncedAddOrRemoveButton = debounce(addOrRemoveButton, CONFIG.DEBOUNCE_DELAY); function init() { // Initial check addOrRemoveButton(); // Listen for URL changes if ('onurlchange' in window) { window.addEventListener('urlchange', () => { debouncedAddOrRemoveButton(); }); } // Observe DOM changes const observer = new MutationObserver(() => { debouncedAddOrRemoveButton(); }); observer.observe(document.body, { childList: true, subtree: true }); // Listen for History API changes const originalPushState = history.pushState; history.pushState = function() { originalPushState.apply(this, arguments); debouncedAddOrRemoveButton(); }; window.addEventListener('popstate', debouncedAddOrRemoveButton); } init(); } if (typeof saveAs === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js'; script.onload = () => initScript(saveAs); document.head.appendChild(script); } else { initScript(saveAs); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址