DEV Community

Cover image for Spotify Chrome Extension: Music Controller | Phase 6
an-object-is-a
an-object-is-a

Posted on • Edited on

Spotify Chrome Extension: Music Controller | Phase 6

Spotify Chrome Extension - Merging the Front-end & Back-end


This is Phase Six of a multi-phase project where we build a Spotify Chrome Extension powered by ReactJS that allows us to control the user's Spotify session

Phase One can be found here.


This tutorial assumes you know how Google Chrome Extensions work. Learn more here.


React-Chrome Spotify Controller

Like any Chrome Extension, we need to inject the foreground page into the User's browser.

We, of course, inject from our Background.js script.
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo.status === 'complete' && tab.url.includes('http')) {
        active_tabId = tabId;

        chrome.tabs.executeScript(tabId, { file: './inject_script.js' }, function () {
            chrome.tabs.executeScript(tabId, { file: './foreground.bundle.js' }, function () {
                console.log("INJECTED AND EXECUTED");
            });
        });
    }
});

chrome.tabs.onActivated.addListener(activeInfo => {
    chrome.tabs.get(activeInfo.tabId, function (tab) {
        if (tab.url.includes('http')) active_tabId = activeInfo.tabId;
    });
});
Enter fullscreen mode Exit fullscreen mode

Now that we've done that, let create GET and SET state functions for our entire App.

Staying in our Background.js file, we'll create those two functions...
function get_state() {
    return new Promise((resolve, reject) => {
        chrome.storage.local.get('chrome-ext-Spotify-controller', item => {
            if (chrome.runtime.lastError) {
                reject('fail');
            } else {
                const state = item['chrome-ext-Spotify-controller'] ? item['chrome-ext-Spotify-controller'] : "{}";

                resolve(JSON.parse(state));
            }
        });
    });
}

function set_state(_state) {
    return new Promise((resolve, reject) => {
        get_state()
            .then(res => {
                const updated_state = {
                    ...res,
                    ..._state
                }

                chrome.storage.local.set({ 'chrome-ext-Spotify-controller': JSON.stringify(updated_state) }, () => {
                    if (chrome.runtime.lastError) {
                        reject('fail');
                    } else {
                        resolve('success');
                    }
                });
            });
    });
}
Enter fullscreen mode Exit fullscreen mode

All that's left to do is pair our Spotify API logic in the Background script to the function calls in our Foreground script.

We won't go into every function pairing here, we'll show you one.
See the video tutorial for a detailed walk-through.

In the Foreground.js component we have our start_pause function message our Background.js script.

start_pause = () => {
    chrome.runtime.sendMessage({ message: this.state.isPlaying ? 'pause' : 'play', payload: { isPlaying: !this.state.isPlaying } }, response => {
        if (response.message === 'success') {
            this.setState(_state => {
                return {
                    isPlaying: !_state.isPlaying,
                    current_track: response.current_track
                }
            });
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

In our Background.js script, we catch that message, call the Spotify API, and send back a response to the Foreground.js component.

...
if (request.message === 'play') {
    player.play()
        .then(res => set_state(request.payload))
        .then(res => player.current())
        .then(res => sendResponse({ message: 'success', current_track: res.current_track }))
        .catch(err => sendResponse({ message: 'fail' }));

    return true;
} else if (request.message === 'pause') {
    player.pause()
        .then(res => set_state(request.payload))
        .then(res => player.current())
        .then(res => sendResponse({ message: 'success', current_track: res.current_track }))
        .catch(err => sendResponse({ message: 'fail' }));

    return true;
...
Enter fullscreen mode Exit fullscreen mode

After merging our Background and Foreground, we handle the Login System.

If you want to see how that's done see the video tutorial below.

You can find the final source files for this project here.


If you want a more in-depth guide, check out my full video tutorial on YouTube, An Object Is A.

Build a Cyberpunk 2077-inspired Spotify Controller - Phase 6

Top comments (0)