SP2netease Custom

Click a floating button to get the last played song from Last.fm and search it on Netease Music

// ==UserScript==
// @name         SP2netease Custom
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Click a floating button to get the last played song from Last.fm and search it on Netease Music
// @author       You
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      last.fm
// ==/UserScript==

(function() {
    'use strict';

    // 存储工具函数
    const storage = {
        // 设置存储
        setItem: function(key, value) {
            try {
                // 首先尝试使用油猴存储API(跨域)
                if (typeof GM_setValue !== 'undefined') {
                    GM_setValue(key, value);
                    console.log('使用GM_setValue保存:', key, value);
                    return;
                }
            } catch (e) {
                console.log('GM_setValue不可用:', e);
            }
            
            try {
                // 然后尝试使用localStorage
                localStorage.setItem(key, value);
                console.log('使用localStorage保存:', key, value);
            } catch (e) {
                // localStorage不可用时使用cookie
                console.log('localStorage不可用,使用cookie保存:', key, value);
                this.setCookie(key, value, 365);
            }
        },
        
        // 获取存储
        getItem: function(key) {
            try {
                // 首先尝试使用油猴存储API(跨域)
                if (typeof GM_getValue !== 'undefined') {
                    const value = GM_getValue(key, null);
                    console.log('从GM_getValue读取:', key, value);
                    return value;
                }
            } catch (e) {
                console.log('GM_getValue不可用:', e);
            }
            
            try {
                // 然后尝试使用localStorage
                const value = localStorage.getItem(key);
                console.log('从localStorage读取:', key, value);
                return value;
            } catch (e) {
                // localStorage不可用时使用cookie
                console.log('localStorage不可用,从cookie读取:', key);
                return this.getCookie(key);
            }
        },
        
        // 设置cookie
        setCookie: function(name, value, days) {
            let expires = "";
            if (days) {
                const date = new Date();
                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                expires = "; expires=" + date.toUTCString();
            }
            // 设置cookie为跨域共享
            document.cookie = name + "=" + (value || "") + expires + "; path=/; domain=." + window.location.hostname.split('.').slice(-2).join('.');
        },
        
        // 获取cookie
        getCookie: function(name) {
            const nameEQ = name + "=";
            const ca = document.cookie.split(';');
            for (let i = 0; i < ca.length; i++) {
                let c = ca[i];
                while (c.charAt(0) === ' ') c = c.substring(1, c.length);
                if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
            }
            return null;
        }
    };
    
    // 创建设置面板
    const createSettingsPanel = () => {
        // 创建面板元素
        const panel = document.createElement('div');
        panel.id = 'netease-settings-panel';
        
        // 添加面板内容
        panel.innerHTML = `
            <div class="netease-settings-header">
                <h3>Last.fm 用户名设置</h3>
                <button id="close-settings">×</button>
            </div>
            <div class="netease-settings-content">
                <label for="lastfm-username">用户名:</label>
                <input type="text" id="lastfm-username" placeholder="请输入Last.fm用户名">
                <button id="save-settings">保存</button>
            </div>
        `;
        
        // 设置输入框的默认值
        const usernameInput = panel.querySelector('#lastfm-username');
        const savedUsername = storage.getItem('lastfmUsername');
        
        // 调试信息
        console.log('从存储中读取到的用户名:', savedUsername);
        
        if (savedUsername !== null && savedUsername !== '') {
            usernameInput.value = savedUsername;
            console.log('设置输入框默认值为:', savedUsername);
        } else {
            console.log('未设置输入框默认值');
        }
        
        // 设置面板为浮动窗口样式
        panel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 300px;
            background: white;
            border: 1px solid #ccc;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            z-index: 10002;
            padding: 20px;
        `;
        
        // 设置面板头部样式
        const header = panel.querySelector('.netease-settings-header');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        `;
        
        // 设置关闭按钮样式
        const closeButton = panel.querySelector('#close-settings');
        closeButton.style.cssText = `
            background: none;
            border: none;
            font-size: 20px;
            cursor: pointer;
            padding: 0;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
        `;
        
        // 设置内容区域样式
        const content = panel.querySelector('.netease-settings-content');
        content.style.cssText = `
            display: flex;
            flex-direction: column;
            gap: 10px;
        `;
        
        // 设置标签样式
        const label = panel.querySelector('label');
        label.style.cssText = `
            font-weight: bold;
        `;
        
        // 设置输入框样式
        const input = panel.querySelector('input');
        input.style.cssText = `
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
        `;
        
        // 设置保存按钮样式
        const saveButton = panel.querySelector('#save-settings');
        saveButton.style.cssText = `
            padding: 10px;
            background-color: #E20000;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        `;
        
        // 将面板添加到页面
        document.body.appendChild(panel);
        
        // 添加事件监听器
        document.getElementById('close-settings').addEventListener('click', () => {
            panel.remove();
        });
        
        document.getElementById('save-settings').addEventListener('click', () => {
            const username = document.getElementById('lastfm-username').value.trim();
            if (username) {
                try {
                    storage.setItem('lastfmUsername', username);
                    alert('设置已保存');
                    panel.remove();
                } catch (e) {
                    alert('保存失败: ' + e.message);
                    // 保存失败时不移除面板,让用户重新尝试
                }
            } else {
                alert('请输入有效的用户名');
                // 不移除面板,让用户重新输入
            }
        });
        
        // 点击面板外部关闭面板
        panel.addEventListener('click', (e) => {
            if (e.target === panel) {
                panel.remove();
            }
        });
        
        // 阻止事件冒泡到面板外部
        const contentElement = panel.querySelector('.netease-settings-content');
        contentElement.addEventListener('click', (e) => {
            e.stopPropagation();
        });
    };
    
    // 创建浮动按钮
    const createFloatingButton = () => {
        // 创建按钮元素
        const button = document.createElement('div');
        button.id = 'netease-search-button';
        
        // 添加SVG图标
        button.innerHTML = '<svg t="1754156884017" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3730" width="32" height="32"><path d="M512 32c265.12 0 480 214.88 480 480 0 265.088-214.88 480-480 480-265.088 0-480-214.912-480-480C32 246.848 246.912 32 512 32z m82.08 173.568c-51.84 17.152-76.736 65.44-61.856 120.32l5.344 20.192c-11.2 2.432-22.208 5.696-32.928 9.824-50.656 19.52-90.848 62.816-104.896 113.024a153.696 153.696 0 0 0-5.088 55.04 137.92 137.92 0 0 0 57.536 100.576 121.504 121.504 0 0 0 103.264 17.6 120.96 120.96 0 0 0 63.68-42.56c24.736-32.288 32.096-74.752 20.8-119.52-4.16-16.32-9.344-34.368-14.4-51.904l-5.376-18.976c21.44 5.376 41.184 16.032 57.44 31.04 56 52.288 66.784 142.368 25.088 209.536-36.608 59.008-107.936 97.088-181.664 97.088a225.76 225.76 0 0 1-225.536-225.472c0-28.992 5.696-57.696 16.832-84.448a221.664 221.664 0 0 1 41.856-65.6 223.712 223.712 0 0 1 81.408-56.416A31.712 31.712 0 0 0 412.064 256a299.52 299.52 0 0 0-25.696 11.808 289.504 289.504 0 0 0-100 86.432 286.56 286.56 0 0 0-54.304 167.136c0 159.296 129.6 288.896 288.96 288.896 95.2 0 187.648-49.856 235.552-127.072 58.304-93.888 43.232-215.584-35.712-289.344-32.32-30.208-74.368-47.872-118.784-51.776-2.304-8.96-5.888-22.592-8.64-32.832-2.08-7.584-3.104-16.16-0.864-23.808a31.808 31.808 0 0 1 38.4-21.44c4.416 1.184 8.608 3.264 12.256 6.048 3.84 2.88 6.848 6.624 10.368 9.888a31.744 31.744 0 0 0 49.856-37.664l-0.64-1.056a65.312 65.312 0 0 0-14.4-16.448 100.48 100.48 0 0 0-53.376-23.392 96.128 96.128 0 0 0-40.96 4.224z m-40.224 201.92c3.36 12.416 7.04 25.344 10.752 38.176 4.928 17.28 9.888 34.432 13.824 49.92 4.576 18.176 6.624 44.192-9.664 65.472a57.056 57.056 0 0 1-30.24 19.936 58.464 58.464 0 0 1-50.144-8.544 73.92 73.92 0 0 1-30.528-53.952 89.6 89.6 0 0 1 2.944-32.416c8.8-31.36 34.304-58.528 66.624-71.008 8.672-3.36 17.536-5.856 26.432-7.584z" fill="#FFFFFF" p-id="3731"></path></svg>';
        
        // 添加按钮样式
        GM_addStyle(`
            #netease-search-button {
                position: fixed;
                width: 32px;
                height: 32px;
                border-radius: 50%;
                background-color: #E20000; /* 红色背景 */
                cursor: pointer;
                z-index: 10000;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                transition: opacity 0.3s;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            
            #netease-search-button:hover {
                opacity: 0.8;
            }
            
            #netease-search-button svg {
                width: 100%;
                height: 100%;
            }
        `);
        
        // 设置按钮初始位置
        // 从存储中读取保存的位置,如果没有则使用默认位置
        const savedPosition = storage.getItem('neteaseButtonPosition');
        if (savedPosition) {
            const position = JSON.parse(savedPosition);
            button.style.left = position.x + 'px';
            button.style.top = position.y + 'px';
        } else {
            button.style.left = '20px';
            button.style.top = '20px';
        }
        
        // 添加拖动功能
        let isDragging = false;
        let offsetX, offsetY;
        
        button.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - button.getBoundingClientRect().left;
            offsetY = e.clientY - button.getBoundingClientRect().top;
            button.style.cursor = 'grabbing';
            e.preventDefault();
        });
        
        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            button.style.left = (e.clientX - offsetX) + 'px';
            button.style.top = (e.clientY - offsetY) + 'px';
        });
        
        document.addEventListener('mouseup', () => {
            isDragging = false;
            button.style.cursor = 'pointer';
            
            // 保存按钮位置到存储
            const position = {
                x: button.offsetLeft,
                y: button.offsetTop
            };
            storage.setItem('neteaseButtonPosition', JSON.stringify(position));
        });
        
        // 添加右键点击功能打开设置
        button.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            createSettingsPanel();
        });
    
    // 添加油猴脚本管理页面的设置入口
    if (window.location.href.startsWith('chrome-extension://') || window.location.href.startsWith('moz-extension://')) {
        // 创建设置按钮
        const settingsButton = document.createElement('button');
        settingsButton.textContent = 'SP2netease 设置';
        settingsButton.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            z-index: 10001;
            padding: 10px;
            background-color: #E20000;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        `;
        
        settingsButton.addEventListener('click', (e) => {
            e.preventDefault();
            createSettingsPanel();
        });
        
        document.body.appendChild(settingsButton);
    }
        
        // 添加左键点击功能
        button.addEventListener('click', () => {
            if (!isDragging) {
                // 直接搜索最近播放的歌曲
                searchDirectly();
            }
        });
        
        // 将按钮添加到页面
        document.body.appendChild(button);
    };
    
    // 直接搜索功能 - 在网易云音乐中搜索
    const searchDirectly = () => {
        // 从存储中读取保存的Last.fm用户名
        const lastfmUsername = storage.getItem('lastfmUsername');
        
        // 调试信息
        console.log('读取到的Last.fm用户名:', lastfmUsername);
        
        // 检查用户名是否存在
        if (!lastfmUsername || lastfmUsername.trim() === '') {
            alert('请先设置Last.fm用户名');
            createSettingsPanel();
            return;
        }
        
        // 自动获取Last.fm最近播放的歌曲信息
        GM_xmlhttpRequest({
            method: 'GET',
            url: `https://www.last.fm/zh/user/${lastfmUsername}`,
            onload: function(response) {
                const parser = new DOMParser();
                const doc = parser.parseFromString(response.responseText, 'text/html');
                
                // 获取最近播放的歌曲信息
                const recentTracks = doc.querySelector('.chartlist tbody tr');
                
                if (!recentTracks) {
                    alert('无法找到最近播放的歌曲信息');
                    return;
                }
                
                const songNameElement = recentTracks.querySelector('.chartlist-name a');
                const artistElement = recentTracks.querySelector('.chartlist-artist a');
                
                if (!songNameElement || !artistElement) {
                    alert('无法获取歌曲信息');
                    return;
                }
                
                const songName = songNameElement.textContent.trim();
                const artist = artistElement.textContent.trim();
                
                // 构建搜索URL
                const searchQuery = encodeURIComponent(`${songName} ${artist}`);
                const searchUrl = `https://music.163.com/#/search/m/?s=${searchQuery}`;
                
                // 在新窗口打开搜索页面
                window.open(searchUrl, '_blank');
            },
            onerror: function(error) {
                alert('获取歌曲信息失败: ' + error.statusText);
            }
        });
    };
    
    // 页面加载完成后创建按钮
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createFloatingButton);
    } else {
        createFloatingButton();
    }
})();