您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
make templates copy links to clipboard
当前为
// ==UserScript== // @name Qobuz Linkifier // @version 0.1.1 // @description make templates copy links to clipboard // @author You // @match https://www.qobuz.com/*/shop // @match https://www.qobuz.com/*/shop/*/* // @match https://www.qobuz.com/*/search* // @match https://www.qobuz.com/*/label/*/*/* // @match https://www.qobuz.com/*/interpreter/*/* // @match https://www.qobuz.com/*/album/*/* // @match https://www.qobuz.com/*/playlists/*/* // @match https://www.qobuz.com/*/genre/*/* // @icon https://www.qobuz.com/favicon.ico // @grant none // @namespace https://greasyfork.org/users/1465219 // ==/UserScript== (function () { 'use strict'; const BASE_URL = 'https://play.qobuz.com/', LOAD_MORE_TRACKS_DELAY = 500, COPY_MESSAGE_DISPLAY_DURATION = 1500, DEFAULT_LOC = { lang: 'en', country: '_' }; addCustomStyle(` .store-wallpaper, .album-addtocart, .player__ad, .store-cart, .shop-cart, .price-box .price, .on-sale { display: none !important; } #store-search { padding-right: 0 !important; border-right: none !important } .shop-search { margin-right: 16px !important; } .track__item--button span.pct { position: absolute !important; top: 8px !important; left: 5px !important; } .catalog-heading__button span.pct { margin-right: 18px; font-size: 12px; font-weight: 700; } .product__button span.pct { left: 11px; position: absolute; } .player__webplayer span.pct { margin-right: 8px; } .player__webplayer span:last-child { padding-top: 2px; } .no-wrap { white-space: nowrap !important; } .color-white { color: #FFF !important; } `); const templates = infuseTemplates(window.location.pathname.split('/')[1].split('-').reverse(), { en: { _: { label: 'label', artist: 'artist', album: 'album', playlist: 'playlist', track: 'track', copyLink: function (type) { return type ? `Copy ${this[type]} link` : 'Copy link' }, copyLinkWithHighlight: function (type) { return `<span class="color-white">Copy</span> ${this[type]} link` }, linkCopied: function (type) { return type ? `${this[type].toTitleCase()} link copied!` : 'Link copied!' }, linkCopiedWithHighlight: function (type) { return `<span class="color-white">${this[type].toTitleCase()} link</span> copied!` }, }, get uk() { return this._ }, get ie() { return this._ }, get us() { return this._ }, get au() { return this._ }, get ca() { return this._ }, get nz() { return this._ }, get dk() { return this._ }, get fi() { return this._ }, get se() { return this._ }, get no() { return this._ } }, de: { _: { label: 'Verlag', artist: 'Interpret', album: 'Album', playlist: 'Wiedergabeliste', track: 'Titel', copyLink: function (type) { return type ? `${this[type]}-Link kopieren` : 'Link kopieren' }, copyLinkWithHighlight: function (type) { return `<span class="color-white">${this[type]}-Link</span> kopieren` }, linkCopied: function (type) { return type ? `${this[type]}-Link kopiert!` : 'Link kopiert!' }, linkCopiedWithHighlight: function (type) { return `<span class="color-white">${this[type]}-Link</span> kopiert!` }, }, get de() { return this._ }, get at() { return this._ }, get ch() { return this._ }, get lu() { return this._ } }, /* es: { _: { }, get es() { return this._ }, get mx() { return this._ }, get ar() { return this._ }, get cl() { return this._ }, get co() { return this._ } }, pt: { get pt() { return this._ }, get br() { return this._ } }, nl: { get nl() { return this._ }, get be() { return this._ } }, fr: { get fr() { return this._ }, get ch() { return this._ }, get lu() { return this._ }, get be() { return this._ }, get ca() { return this._ } }, it: { get it() { return this._ } } */ }, (data) => ({ track: { content: () => ` <span class="pct pct pct-edit"></span> <span class="no-wrap">${data.copyLink()}</span> `, message: () => ` <span class="pct pct pct-checkbox"></span> <span class="no-wrap">${data.linkCopied()}</span> ` }, albumGrid: { content: () => ` <span class="pct pct pct-edit"></span> <span class="product__button--highlight"> ${data.copyLinkWithHighlight('album')} </span> `, message: () => ` <span class="pct pct pct-checkbox"></span> <span class="product__button--highlight"> ${data.linkCopiedWithHighlight('album')}</span> </span> ` }, search: { content: () => ` <span class="no-wrap">${data.copyLink('album')}</span> `, message: () => ` <span class="no-wrap">${data.linkCopied('album')}</span> ` }, main: { content: (type) => ` <span class="pct pct pct-edit"></span> <span class="no-wrap">${data.copyLink(type)}</span> `, message: (type) => ` <span class="pct pct pct-checkbox"></span> <span class="no-wrap">${data.linkCopied(type)}</span> ` } })); templates["main"].content("album") const selectors = { main: '.catalog-heading__button, .player__webplayer', search: '.btn__qobuz.btn__qobuz--see-album', album: '.product__button.add_to_cart', track: '.track__item.track__item--button', loadMore: '.player-more' } const mainButton = document.querySelector(selectors.main); if (mainButton) { const [type, id] = mainButton.attributes.href.value.split('/').slice(-2); replaceButton(mainButton, id, type, 'main'); document.querySelectorAll(selectors.track).forEach((el, i) => { if (el.classList.contains('track__unavailable')) return; const trackButton = replaceButton( el, el.dataset.url.split('/').slice(-1)[0], 'track' ); trackButton.addEventListener('dblclick', ev => { ev.preventDefault(); ev.stopPropagation(); }) }); } document.querySelectorAll(selectors.album).forEach((el, i) => { replaceButton( el, el.dataset.url.split('/').slice(-1)[0], 'album', 'albumGrid' ); }); document.querySelectorAll(selectors.search).forEach((el, i) => { replaceButton( el, el.attributes.href.value.split('/').slice(-1)[0], 'album', 'search' ); }); const loadMore = document.querySelector(selectors.loadMore) if (loadMore) { loadMore.addEventListener('click', ev => { setTimeout(() => { document.querySelectorAll(selectors.track).forEach((el, i) => { if (el.classList.contains('track__unavailable')) return; const trackButton = replaceButton( el, el.dataset.url.split('/').slice(-1)[0], 'track' ); trackButton.addEventListener('dblclick', ev => { ev.preventDefault(); ev.stopPropagation(); }) }); }, LOAD_MORE_TRACKS_DELAY); }) } function replaceButton(button, id, type, contentType = type) { let timeout; const content = templates[contentType].content(type), url = BASE_URL + `${type}/${id}`, newButton = button.cloneNode(true); newButton.setAttribute('title', url); newButton.setAttribute('href', url); newButton.innerHTML = content; button.replaceWith(newButton); button.remove(); let wasCopied = false; newButton.addEventListener('click', ev => { ev.preventDefault(); navigator.clipboard.writeText(url); if (wasCopied) { clearTimeout(timeout); } else { newButton.innerHTML = templates[contentType].message(type); wasCopied = true; } timeout = window.setTimeout( () => { newButton.innerHTML = content; wasCopied = false; }, COPY_MESSAGE_DISPLAY_DURATION ); ev.stopPropagation(); return false; }); return newButton; } function addCustomStyle(style) { document.body.append( document.createElement('style') .appendChild( document.createTextNode(style) ) .parentNode ); } function infuseTemplates([country, lang], strings, templates) { return templates(strings[country]?.[lang] || strings[DEFAULT_LOC.lang][DEFAULT_LOC.country]); } Object.defineProperty(String.prototype, "toTitleCase", { value: function () { return this[0].toUpperCase() + this.slice(1); }, writable: true, configurable: true, }); })();