Skip to content

Instantly share code, notes, and snippets.

@daniel-j
Last active December 30, 2015 18:08
Show Gist options
  • Save daniel-j/7865057 to your computer and use it in GitHub Desktop.
Save daniel-j/7865057 to your computer and use it in GitHub Desktop.
This script takes a Spotify playlist URI and creates a Mopidy playlist with local file support! It uses mpc to search your media library using the spotify local tags, and replaces them with the real filename on your drive. It then saves the playlist in your local playlist folder. Make sure you modify this script before running it!
#!/usr/bin/env node
'use strict';
// Created by djazz
// Use with Mopidy to use Spotify playlist with local files in them
// Dependencies:
// $ npm install spotify-web ini
//
// mopidy (or mpd) must be running, mpc must be installed
var fs = require("fs");
var spawn = require('child_process').spawn;
var Spotify = require('spotify-web');
var ini = require('ini');
// Configurable
var playlistUri = 'spotify:user:djazzy:playlist:4S55vHEhqaxyLKgxnOXjSL';
var playlistFile = '/.local/share/mopidy/local/playlists/random-pony.m3u';
var mopidyConfigFile = '/.config/mopidy/mopidy.conf';
var stopScanIfNotFound = false;
var home = process.env.HOME;
var escapeSearch = true; // true for mopidy, false for mpd..
var list = [];
var listi = 0;
var mpdList = [];
var mopidy = ini.parse(fs.readFileSync(home+mopidyConfigFile, 'utf-8'));
console.log("Logging in to Spotify...");
Spotify.login(mopidy.spotify.username, mopidy.spotify.password, function (err, spotify) {
if (err) {
console.log("Error logging in: "+err);
return;
}
console.log("Fetching playlist...");
list = [];
getNextPage(0);
function getNextPage(offset) {
spotify.playlist(playlistUri, offset, function (err, playlist) {
if (err) {
console.error("Error loading playlist: "+err);
return;
}
if (offset === 0) {
console.log("Found playlist "+playlist.attributes.name+" ("+playlist.length+" tracks)");
}
if (playlist.length === 0) {
console.log("Playlist is empty!");
spotify.disconnect();
return;
}
var items = playlist.contents.items;
var str = "";
for (var i = 0; i < items.length; i++) {
list.push(items[i].uri);
}
if (list.length >= playlist.length) {
console.log("Scanning library for matching files...");
spotify.disconnect();
doNext();
} else {
getNextPage(list.length);
}
});
}
});
function doNext() {
if (listi > list.length-1) {
console.log("Completed scanning!");
var playlist = mpdList.join("\n");
fs.writeFile(home+playlistFile, playlist, function (err) {
if (err) {
console.log("Error saving playlist file! "+err);
return;
}
console.log("Playlist saved successfully!");
});
return;
}
var uri = list[listi++];
if (uri.indexOf("spotify:local:") !== 0) {
addToList(uri);
doNext();
return;
}
uri = uri.split(":");
var artist = decodeURIComponent(uri[2].replace(/\+/g,' '));
var album = decodeURIComponent(uri[3].replace(/\+/g,' '));
var title = decodeURIComponent(uri[4].replace(/\+/g,' '));
findByTitle(title, function (result) {
if (result.length === 0) {
findByName(title, function (result) {
if (result.length === 0) {
console.log([title, artist, album]);
console.log("Track not found in filename search!");
if (stopScanIfNotFound) {
return;
} else {
doNext();
return;
}
} else if (result.length > 1) {
console.log("Multiples:", result, [title, artist, album]);
}
addToList(result[0]);
doNext();
});
} else if (result.length > 1) {
refineSearch(title, artist, album, function (result) {
if (result.length === 0) {
console.log([title, artist, album]);
console.log("Track not found in refined search!");
if (stopScanIfNotFound) {
return;
} else {
doNext();
return;
}
} else if (result.length > 1) {
console.log("Multiples:", result, [title, artist, album]);
}
addToList(result[0]);
doNext();
});
} else {
addToList(result[0]);
doNext();
}
});
}
function addToList(name) {
mpdList.push(name);
}
function findByTitle(title, cb) {
mpc(['find', 'title', title], cb);
}
function findByName(name, cb) {
mpc(['search', 'filename', escapeSearch? escape(name):name], cb);
}
function refineSearch(title, artist, album, cb) {
var args = ['search', 'title', title];
if (album !== '') args = args.concat("album", album);
if (artist !== '') args = args.concat("artist", artist);
mpc(args, cb);
}
function mpc(args, cb) {
var mpc = spawn("mpc", args, {stdio: 'pipe'});
var result = "";
mpc.stdout.on('data', function (data) {
result += data.toString();
});
mpc.on('close', function () {
result = result.split("\n");
result.pop();
cb(result);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment