Spotify - Append Artist Name and Title to Copied Link

Spotify - Append Artist Name and Title to Copied Link.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Spotify - Append Artist Name and Title to Copied Link
// @description  Spotify - Append Artist Name and Title to Copied Link.
// @author       to
// @namespace    https://github.com/to
// @license      MIT
// @version      0.6
//
// @noframes
// @connect      spotify.com
// @connect      song.link
// @match        https://open.spotify.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=spotify.com
//
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        unsafeWindow
// ==/UserScript==

// SpotifyのAPIを利用すると 日本のアーティストが日本語表記になりやすい
const CLIENT_ID = '';
const CLIENT_SECRET = '';
const MARKETS = ['JP', 'US'];

const PREFIX = "";

let useSpotify = !!CLIENT_ID;
let market = MARKETS[0];

// Clipboard APIではcopyイベントが発生しないため 強制的にexecCommandを利用させる
unsafeWindow.navigator.clipboard.write = null;
unsafeWindow.navigator.clipboard.writeText = null;

// マーケットの国を切り替える
// (海外のアーティストがカタカナ表記になってしまうことがあるため)
MARKETS.forEach(m => {
    GM_registerMenuCommand ('Change Market [' + m + ']', () => {
        market = m;
    });
});

if(useSpotify){
    GM_registerMenuCommand ('Use Odesil', () => {
        useSpotify = false;
    });
}

document.addEventListener('copy', e => {
	// URL以外がコピーされたか、または、通常のテキストコピー操作か?
    let url = e.target.value;
	if(!url || !(/^http/.test(url) || !(e.target instanceof HTMLTextAreaElement)))
		return;

    url = url.replace(/\?.+/, '');

    // SpotifyのAPIを利用するか?
    if(useSpotify){
        let ts = url.match(/\/(track|album)\/(.+)/);
        if(ts){
            requestToSpotify(`https://api.spotify.com/v1/${ts[1]}s/${ts[2]}?market=${market}`, r => {
                GM_setClipboard([
                    r.artists.map(a => a.name).join(', '),
                    '-',
                    r.name,
                    url,
                    'https://' + (r.type == 'track' ? 'song' : r.type) + '.link/s/' + r.id].join(' ') + PREFIX);
            });
        }
    } else {
        // JPロケールが適用されていない(USと同じ値が返される)
        GM_xmlhttpRequest({
            url: `https://api.song.link/v1-alpha.1/links?userCountry=${market}&url=${encodeURIComponent(url)}`,
            onload: function(r){
                r = JSON.parse(r.responseText);

                GM_setClipboard([
                    r.entitiesByUniqueId[r.entityUniqueId].artistName,
                    '-',
                    r.entitiesByUniqueId[r.entityUniqueId].title,
                    url,
                    r.pageUrl].join(' ') + PREFIX);
            }});
    }
}, true);

function requestToSpotify(url, callback){
    GM_xmlhttpRequest({
        url: 'https://accounts.spotify.com/api/token',
        method: 'POST',
        data: 'grant_type=client_credentials',
        headers: {
            'Authorization': 'Basic ' + btoa(CLIENT_ID + ':' + CLIENT_SECRET),
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        onload: function(r){
            r = JSON.parse(r.responseText);

            GM_xmlhttpRequest({
                url: url,
                headers: {
                    'Authorization': r.token_type + ' ' + r.access_token,
                    'Content-Type': 'application/json',
                },
                onload: function(r){
                    callback(JSON.parse(r.responseText));
                }});
        }});
}