Greasy Fork

Greasy Fork is available in English.

Apple Music Enhanced

增强Apple Music页面功能,添加ID复制、Telegram Bot下载和地区切换

当前为 2024-07-12 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Apple Music Enhanced
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  增强Apple Music页面功能,添加ID复制、Telegram Bot下载和地区切换
// @match        https://music.apple.com/*
// @grant        GM_setClipboard
// @grant        GM_addStyle
// @license      GNU GPLv3
// ==/UserScript==

(function () {
    'use strict';

    const regions = [
        { name: '🇭🇰', code: 'hk', fullName: 'Hongkong' },
        { name: '🇯🇵', code: 'jp', fullName: 'Japan' },
        { name: '🇺🇸', code: 'us', fullName: 'US' },
        { name: '🇨🇳', code: 'cn', fullName: 'China' }
    ];

    GM_addStyle(`
        .region-dropdown {
            appearance: none;
            background-color: #1c1c1e;
            border: none;
            color: white;
            font-size: 14px;
            font-family: inherit;
            padding: 8px 12px;
            width: 150px;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        .region-dropdown:hover {
            background-color: #2c2c2e;
        }
        .region-dropdown:focus {
            outline: none;
        }
        .region-dropdown option {
            background-color: #1c1c1e;
            color: white;
        }
        .custom-button {
            background-color: #1d1d1f;
            border: none;
            color: #fff;
            font-size: 14px;
            font-weight: bold;
            padding: 8px 16px;
            border-radius: 16px;
            cursor: pointer;
            margin-right: 10px;
            transition: background-color 0.3s, transform 0.1s;
        }

        .custom-button:hover {
            background-color: #2c2c2e;
        }

        .custom-button:active {
            transform: scale(0.95);
        }
        .feedback-message {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            z-index: 9999;
            transition: opacity 0.3s;
        }
    `);

    function createButton(text, onClick, title) {
        const button = document.createElement('button');
        button.textContent = text;
        button.className = 'custom-button';
        button.addEventListener('click', onClick);
        if (title) button.title = title;
        return button;
    }

    function showFeedback(message) {
        const feedback = document.createElement('div');
        feedback.textContent = message;
        feedback.className = 'feedback-message';
        document.body.appendChild(feedback);
        setTimeout(() => {
            feedback.style.opacity = '0';
            setTimeout(() => feedback.remove(), 300);
        }, 2000);
    }

    function getAlbumId(url) {
        const match = url.match(/\/album\/.*?\/(\d+)(?:\?i=\d+)?$/);
        return match ? match[1] : null;
    }

    function addAlbumButtons() {
        const existingButtons = document.querySelector('#album-buttons-container');
        if (existingButtons) return;

        const previewButton = document.querySelector('button[data-testid="click-action"]');
        if (!previewButton) return;

        const container = document.createElement('div');
        container.id = 'album-buttons-container';
        container.style.display = 'flex';
        container.style.alignItems = 'center';
        container.style.marginTop = '10px';

        const copyIdButton = createButton('ID', function () {
            const albumId = getAlbumId(window.location.href);
            if (albumId) {
                GM_setClipboard(albumId);
                showFeedback('ID已复制');
            } else {
                showFeedback('未找到ID');
            }
        }, '复制专辑ID');

        const searchCacheButton = createButton('搜索缓存', function () {
            const albumId = getAlbumId(window.location.href);
            if (albumId) {
                GM_setClipboard(albumId);
                showFeedback('ID已复制,正在打开搜索缓存');
                window.location.href = 'tg://privatepost?channel=1841657952&post=184451';
            } else {
                showFeedback('未找到ID');
            }
        }, '复制ID并打开Telegram搜索缓存');

        const TelegramBotName = 'BeatsRobot'

        const downloadCacheButton = createButton('下载缓存', function () {
            const clipboardContent = prompt("请粘贴内容:");
            if (clipboardContent) {
                const telegramUrl = `tg://resolve?domain=${TelegramBotName}&text=${encodeURIComponent(`/cache ${clipboardContent}`)}`;
                window.location.href = telegramUrl;
                showFeedback('正在发送到Telegram下载缓存');
            } else {
                showFeedback('未获取到内容');
            }
        }, '发送内容到Telegram下载缓存');

        const directDownloadButton = createButton('直接下载', function () {
            const url = window.location.href.split('?')[0];
            const telegramUrl = `tg://resolve?domain=${TelegramBotName}&text=${encodeURIComponent(`/dl ${url} 1`)}`;
            window.location.href = telegramUrl;
            showFeedback('正在打开Telegram进行下载');
        }, '在Telegram中直接下载专辑');

        container.appendChild(copyIdButton);
        container.appendChild(searchCacheButton);
        container.appendChild(downloadCacheButton);
        container.appendChild(directDownloadButton);

        regions.forEach(region => {
            const regionButton = createButton(region.name, function () {
                const currentUrl = window.location.href.split('?')[0];
                const newUrl = currentUrl.replace(/\/\/music\.apple\.com\/[a-z]{2}/, `//music.apple.com/${region.code}`);
                GM_setClipboard(newUrl);
                showFeedback(`${region.fullName} 链接已复制`);
            }, `复制 ${region.fullName} 链接`);
            container.appendChild(regionButton);
        });

        previewButton.parentNode.insertAdjacentElement('afterend', container);
    }

    function addRegionDropdown() {
        const navigationList = document.querySelector('ul[role="list"]');
        if (!navigationList || document.querySelector('.region-dropdown')) return;

        const dropdownContainer = document.createElement('li');
        dropdownContainer.className = 'navigation-item svelte-11z6bd0';
        dropdownContainer.role = 'listitem';

        const dropdown = document.createElement('select');
        dropdown.className = 'region-dropdown';
        dropdown.innerHTML = `<option value="">地区</option>` +
            regions.map(region => `<option value="${region.code}">${region.name} ${region.fullName}</option>`).join('');

        dropdown.addEventListener('change', function () {
            if (this.value) {
                const currentUrl = new URL(window.location.href);
                currentUrl.hostname = `music.apple.com/${this.value}`;
                currentUrl.pathname = currentUrl.pathname.replace(/\/[a-z]{2}\//, `/${this.value}/`);
                window.location.href = currentUrl.toString();
            }
        });

        dropdownContainer.appendChild(dropdown);
        navigationList.appendChild(dropdownContainer);
    }

    function persistentlyAddButtons() {
        addRegionDropdown();
        addAlbumButtons();
        setTimeout(persistentlyAddButtons, 1000);
    }

    persistentlyAddButtons();

    let lastUrl = location.href;
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            setTimeout(addAlbumButtons, 1000);
        }
    }).observe(document, { subtree: true, childList: true });

})();