// ==UserScript== // @name Lucida Downloader // @description Download music from Spotify, Qobuz, Tidal, Soundcloud, Deezer, Amazon Music and Yandex Music via Lucida. Adds a draggable floating button that opens in Lucida for downloading. // @icon https://lucida.to/favicon.png // @version 1.0 // @author afkarxyz // @namespace https://github.com/afkarxyz/misc-scripts/ // @supportURL https://github.com/afkarxyz/misc-scripts/issues // @license MIT // @match https://open.spotify.com/* // @match https://listen.tidal.com/* // @match https://music.yandex.com/* // @match https://music.amazon.com/* // @match https://www.deezer.com/* // @match https://soundcloud.com/* // @match https://www.qobuz.com/* // @grant GM_setValue // @grant GM_getValue // @downloadURL none // ==/UserScript== (function() { 'use strict'; const DOMAINS = ['lucida.to', 'lucida.su']; const LOGO_SVG = ``; const style = document.createElement('style'); style.textContent = ` .floating-button { position: fixed; width: 80px; height: 80px; background-color: transparent; border-radius: 50%; display: flex; justify-content: center; align-items: center; cursor: move; z-index: 9999; opacity: 0.3; transition: opacity 0.3s ease; border: none; } .floating-button:hover { opacity: 1; } .floating-button svg { width: 48px; height: auto; cursor: pointer; } `; document.head.appendChild(style); const button = document.createElement('button'); button.className = 'floating-button'; button.innerHTML = LOGO_SVG; const savedPosition = { left: GM_getValue('buttonLeft', '20'), top: GM_getValue('buttonTop', '20') }; button.style.left = savedPosition.left + 'px'; button.style.top = savedPosition.top + 'px'; let isDragging = false; let startX, startY; button.addEventListener('mousedown', e => { if (e.target.tagName.toLowerCase() !== 'svg') { isDragging = true; startX = e.clientX - button.offsetLeft; startY = e.clientY - button.offsetTop; } }); document.addEventListener('mousemove', e => { if (!isDragging) return; let left = e.clientX - startX; let top = e.clientY - startY; left = Math.max(0, Math.min(window.innerWidth - button.offsetWidth, left)); top = Math.max(0, Math.min(window.innerHeight - button.offsetHeight, top)); button.style.left = left + 'px'; button.style.top = top + 'px'; }); document.addEventListener('mouseup', () => { if (!isDragging) return; isDragging = false; const SNAP = 20; const rect = button.getBoundingClientRect(); if (rect.left < SNAP) button.style.left = '0px'; if (rect.top < SNAP) button.style.top = '0px'; if (window.innerWidth - rect.right < SNAP) button.style.left = (window.innerWidth - rect.width) + 'px'; if (window.innerHeight - rect.bottom < SNAP) button.style.top = (window.innerHeight - rect.height) + 'px'; GM_setValue('buttonLeft', button.style.left.replace('px', '')); GM_setValue('buttonTop', button.style.top.replace('px', '')); }); button.addEventListener('click', e => { if (e.target.closest('svg')) { const currentUrl = encodeURIComponent(window.location.href); const randomDomain = DOMAINS[Math.floor(Math.random() * DOMAINS.length)]; window.open(`https://${randomDomain}/?url=${currentUrl}&country=auto`, '_blank'); } }); document.body.appendChild(button); })();