soundcloud shuffle likes

Adds a shuffle play button to "Likes" and playlists

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         soundcloud shuffle likes
// @version      1.7
// @description  Adds a shuffle play button to "Likes" and playlists
// @author       bhackel
// @match        https://soundcloud.com/*
// @grant        none
// @run-at       document-end
// @license MIT
// @noframes
// @namespace https://greasyfork.org/en/users/324178-bhackel
// ==/UserScript==

(function() {
    'use strict';

    /* Injects Button into the page once it has loaded,
       then tries to re-add it if it disappears due to page change
    */
    function insertButtonLoop() {
        let url = window.location.href;
        url = url.split('?')[0];
        let btnShuffle = document.querySelector('.bhackel-shuffle-likes');

        // Check if button does not exist already, and that user is on likes or a playlist
        if (!btnShuffle && (url.includes("/likes") || url.includes("/sets/") || url.includes("/discover/"))) {
            btnShuffle = document.createElement('Button');
            btnShuffle.innerHTML = 'Shuffle Play';
            btnShuffle.onclick = function(){ setupLoad(this); };
            btnShuffle.scrolling = false;
            btnShuffle.interval = 0;

            // Case for likes
            if (url.includes("you/likes")) {
                btnShuffle.className = 'bhackel-shuffle-likes sc-button sc-button-large';
                btnShuffle.pageType = "Likes";
                // Check if top bar has loaded
                let collectionTop = document.querySelector('.collectionSection__top');
                if (collectionTop) {
                    // Insert the button above the grid of tracks
                    collectionTop.insertBefore(btnShuffle, collectionTop.children[2]);
                } else {
                    setTimeout(insertButtonLoop, 1000);
                }
            }
            // Case for generic user likes
            else if (url.includes("/likes") && !url.includes("you/likes")) {
                btnShuffle.className = 'bhackel-shuffle-likes sc-button sc-button-medium';
                btnShuffle.pageType = "GenericLikes";
                // Check if top bar has loaded
                let titleBar = document.querySelector(".userNetworkTabs");
                if (titleBar) {
                    // Insert the button above the list of tracks
                    titleBar.appendChild(btnShuffle);
                } else {
                    setTimeout(insertButtonLoop, 1000);
                }
            }
            // Case for a playlist
            else if (url.includes("/sets/") && !url.includes("/discover/")) {
                btnShuffle.className = 'bhackel-shuffle-likes sc-button sc-button-medium';
                btnShuffle.pageType = "Playlist";
                // Check if action bar has loaded
                let soundActions = document.querySelector('.soundActions');
                if (soundActions) {
                    // Insert the button after other action buttons
                    soundActions.children[0].appendChild(btnShuffle);
                } else {
                    setTimeout(insertButtonLoop, 1000);
                }
            }
            // Case for discover playlists
            else if (url.includes("/discover/sets/")) {
                btnShuffle.className = 'bhackel-shuffle-likes sc-button sc-button-medium';
                btnShuffle.pageType = "Discover";
                // Check if action bar has loaded
                let playlistControls = document.querySelector('.systemPlaylistDetails__controls');
                if (playlistControls) {
                    // Insert the button after other action buttons
                    playlistControls.appendChild(btnShuffle);
                } else {
                    setTimeout(insertButtonLoop, 1000);
                }
            }
        }
        // Perform another check in 3 seconds, in the case button has been removed
        setTimeout(insertButtonLoop, 3000);
    }

    /* Changes the text of the button, resets the queue to have the user's
       likes, then starts the scrolling loop. Or it stops the loop from running.
    */
    function setupLoad(btn) {
        // Check whether the loop is running or not
        if (btn.scrolling === false) {
            btn.innerHTML = 'Click to Stop Loading';
            btn.scrolling = true;
            // The list of tracks visible on screen, which changes for a playlist or likes
            let tracks;
            if (btn.pageType === "Likes") {
                tracks = document.querySelector('.lazyLoadingList__list');
            } else if (btn.pageType === "GenericLikes") {
                tracks = document.querySelector('.lazyLoadingList__list');
            } else if (btn.pageType === "Playlist") {
                tracks = document.querySelector('.trackList__list');
            } else if (btn.pageType === "Discover") {
                tracks = document.querySelector('.systemPlaylistTrackList__list');
            }
            if (tracks.childElementCount > 2) {
                // Reset the queue to the beginning of the list of tracks
                let firstTrack = tracks.children[0];
                let secondTrack = tracks.children[1];

                let firstPlayButton = firstTrack.querySelector(".playButton");
                let secondPlayButton = secondTrack.querySelector(".playButton");
                // Reset by playing 2, playing 1, then pausing playback
                secondPlayButton.click();
                setTimeout(function(){ firstPlayButton.click(); }, 150);
                setTimeout(function(){
                    let playButton = document.querySelector('.playControl');
                    if (playButton.classList.contains('playing')) {
                        playButton.click();
                    }
                }, 500);

                // Add the first track to the queue so it gets shuffled
                tracks.getElementsByClassName("sc-button-more")[0].click()
                document.getElementsByClassName("moreActions__button addToNextUp")[0].click()

                // Open the queue to load it
                toggleQueue('open');

                // Setup the scrolling loop - Needs time before running so the queue loads
                btn.timeout = setTimeout(function(){
                    btn.interval = setInterval(function() { scrollQueue(btn); }, 500);
                }, 3000);
            } else {
                // The list has two or less tracks - cannot shuffle play
                btn.innerHTML = 'Error: Too Few Tracks';
            }
        } else {
            clearInterval(btn.interval);
            clearTimeout(btn.timeout);
            btn.interval = 0;
            btn.scrolling = false;
            btn.innerHTML = 'Shuffle Play';
        }
    }

    /* Scrolls the queue down, ensuring that the queue is open by opening it
    */
    function scrollQueue(btn) {
        let queue = document.querySelector('.queue');
        // Check if the queue is open
        if (queue.classList.contains('m-visible')) {
            // Scroll the queue to the bottom, loading new tracks below
            let scrollableQueue = document.querySelector('.queue__scrollableInner');
            let queueContainer = document.querySelector('.queue__itemsHeight');
            let scrollToHeight = parseInt(queueContainer.style.height);
            scrollableQueue.scroll(0,scrollToHeight);

            // Check if all tracks are loaded, then play
            let autoplayDiv = document.querySelector('.queue__fallback');
            if (autoplayDiv) {
                clearInterval(btn.interval);
                btn.scrolling = false;
                btn.interval = 0;
                play(btn);
            }
        } else {
            // Open the queue if it is closed
            toggleQueue('open');
        }
    }

    /* Shuffles the queue, skips the first track, then plays it
    */
    function play(btn) {
        btn.innerHTML = 'Shuffle Play';
        let playButton = document.querySelector('.playControl');
        let shuffleButton = document.querySelector('.shuffleControl');
        let skipButton = document.querySelector(".skipControl__next");

        // Re-Shuffle tracks if shuffle is enabled, and enable shuffle if it is disabled
        if (shuffleButton.classList.contains('m-shuffling')) {
            shuffleButton.click();
            shuffleButton.click();
        } else if (!shuffleButton.classList.contains('m-shuffling')) {
            shuffleButton.click();
        }

        // Skip the duplicate first track that was added previously
        // This also begins playback
        skipButton.click();

        // Close the queue if it is open
        toggleQueue('close');

        // Add focus back to the play/pause button so keybinds work
        playButton.focus()
    }

    /* Opens or closes the song queue
    */
    function toggleQueue(changeToState) {
        let queue = document.querySelector('.queue');
        let isQueueOpen = queue.classList.contains('m-visible');
        // Toggle queue if the queue is open and it should be closed, or if it's closed and should be open
        if ((isQueueOpen && changeToState === 'close') || (!isQueueOpen && changeToState === 'open')) {
            let queueTrigger = document.querySelector('.playbackSoundBadge__queueCircle');
            queueTrigger.click();
        }
    }

    insertButtonLoop();

})();