cody-music
Version:
mac osx spotify and itunes music player controller, spotify audio features, itunes and spotify genre, and playlist control
364 lines (318 loc) • 10.2 kB
text/typescript
import {
PlayerName,
Track,
TrackStatus,
PlayerType,
CodyResponse,
} from "./models";
const cp = require("child_process");
export class MusicUtil {
isLinux() {
return this.isWindows() || this.isMac() ? false : true;
}
// process.platform return the following...
// -> 'darwin', 'freebsd', 'linux', 'sunos' or 'win32'
isWindows() {
return process.platform.indexOf("win32") !== -1;
}
isMac() {
return process.platform.indexOf("darwin") !== -1;
}
isEmptyObj(obj: any) {
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
isResponseOk(resp: any) {
if (resp && resp.status === 200) {
return true;
}
return false;
}
isItemsResponseOk(codyResp: CodyResponse) {
if (
codyResp &&
codyResp.status === 200 &&
codyResp.data &&
codyResp.data.items
) {
return true;
}
return false;
}
isResponseOkWithData(resp: any) {
if (resp && resp.status === 200 && resp.data) {
return true;
}
return false;
}
isBooleanString(val: string) {
if (
(val && val.toLowerCase() === "true") ||
val.toLowerCase() === "false"
) {
return true;
}
return false;
}
async execCmd(cmd: string, projectDir: any = null) {
let result: any = null;
try {
let opts =
projectDir !== undefined && projectDir !== null
? { cwd: projectDir }
: {};
result = await this.execPromise(cmd, opts);
} catch (e: any) {
result = { error: e.message };
}
return result;
}
async execPromise(command: string, opts: {}) {
return new Promise((resolve, reject) => {
cp.exec(
command,
opts,
(error: any, stdout: string, stderr: any) => {
if (error) {
reject(error);
return;
}
resolve(stdout.trim());
}
);
});
}
// Sleep for the designated milliseconds.
// It should not be used in prod but only in the test.
// It has a max of 5 seconds as this is resource intensive
sleep(delayInMillis: number) {
delayInMillis = Math.min(delayInMillis, 5000);
var start = new Date().getTime();
while (new Date().getTime() < start + delayInMillis);
}
getPlayerName(player: string) {
if (!player || player.trim().length === 0) {
return PlayerName.SpotifyDesktop;
}
player = player.trim().toLowerCase();
if (player === "itunes") {
return PlayerName.ItunesDesktop;
} else if (player === "spotify-web") {
return PlayerName.SpotifyWeb;
}
return PlayerName.SpotifyDesktop;
}
formatString(source: string, params: any) {
let formatted = source;
if (params && params.length > 0) {
for (let i = 0; i < params.length; i++) {
let regexp = new RegExp("\\{" + i + "\\}", "gi");
formatted = formatted.replace(regexp, params[i]);
}
}
return formatted;
}
isTrackRunning(track: Track) {
if (!track || !track.id) {
return false;
}
if (
track.state === TrackStatus.Paused ||
track.state === TrackStatus.Playing
) {
return true;
}
return false;
}
isTrackPlaying(track: Track) {
if (!track || !track.id) {
return false;
}
if (track.state === TrackStatus.Playing) {
return true;
}
return false;
}
createPlaylistUriFromPlaylistId(playlist_id: string) {
if (!playlist_id.includes("spotify:playlist:")) {
playlist_id = `spotify:playlist:${playlist_id}`;
}
return playlist_id;
}
createSpotifyAlbumIdFromUri(uri: string) {
// "spotify:album:6ZG5lRT77aJ3btmArcykra"
if (uri && uri.indexOf("spotify:") === 0) {
return uri.substring(uri.lastIndexOf(":") + 1);
}
return uri;
}
createTrackIdsFromUris(uris: string[]) {
let trackIds = [];
for (let i = 0; i < uris.length; i++) {
trackIds.push(this.createSpotifyIdFromUri(uris[i]));
}
return trackIds;
}
createUriFromTrackId(track_id: string) {
if (track_id && !track_id.includes("spotify:track:")) {
track_id = `spotify:track:${track_id}`;
}
return track_id;
}
createUrisFromTrackIds(track_ids: string[], useUriObj: boolean = false) {
let tracks = [];
for (let i = 0; i < track_ids.length; i++) {
let uri = track_ids[i];
if (!uri) {
continue;
}
uri = this.createUriFromTrackId(uri);
if (useUriObj) {
const urlObj = {
uri,
};
tracks.push(urlObj);
} else {
tracks.push(uri);
}
}
return tracks;
}
createSpotifyUserUriFromId(id: string) {
if (id && !id.includes("spotify:user:")) {
id = `spotify:user:${id}`;
}
return id;
}
createSpotifyIdFromUri(uri: string) {
if (uri && uri.indexOf("spotify:") === 0) {
return uri.substring(uri.lastIndexOf(":") + 1);
}
return uri;
}
createSpotifyIdsFromUris(uris: string[]) {
const ids: string[] = [];
if (uris && uris.length) {
uris.forEach((uri) => {
ids.push(this.createSpotifyIdFromUri(uri));
});
}
return ids;
}
extractAristFromSpotifyTrack(track: any) {
if (!track) {
return;
}
if (track["artists"]) {
const len = track["artists"].length;
let artistNames = [];
let artists = [];
for (let y = 0; y < len; y++) {
const artist = track["artists"][y];
artistNames.push(artist.name);
artists.push({
name: artist.name,
uri: artist.uri,
id: artist.id,
});
}
delete track.artists;
track.artists = artists;
track["artist"] = artistNames.join(", ");
track["artist_names"] = artistNames;
}
}
launchWebUrl(url: string): Promise<any> {
let open = "open";
let args = [url];
if (this.isWindows()) {
open = "cmd";
// adds the following args to the beginning of the array
args.unshift("/c", "start", '""');
} else if (!this.isMac()) {
open = "xdg-open";
}
args.unshift(open);
const cmd = args.join(" ");
return this.execCmd(cmd);
}
copySpotifyTrackToCodyTrack(spotifyTrack: any): Track {
let track: Track;
if (spotifyTrack) {
// delete some attributes that are currently not needed
if (spotifyTrack.album) {
delete spotifyTrack.album.available_markets;
delete spotifyTrack.album.external_urls;
}
if (spotifyTrack.external_urls) {
delete spotifyTrack.external_urls;
}
if (spotifyTrack.external_ids) {
delete spotifyTrack.external_ids;
}
// pull out the artist info into a more readable set of attributes
this.extractAristFromSpotifyTrack(spotifyTrack);
// assign the track
track = {
...spotifyTrack
};
if (spotifyTrack.duration_ms) {
track.duration = spotifyTrack.duration_ms;
}
} else {
track = new Track();
}
track.type = "spotify";
track.playerType = PlayerType.WebSpotify;
return track;
}
buildQueryString(obj: any, encodeVals: boolean = true) {
let params = [];
if (obj) {
let keys = Object.keys(obj);
if (keys) {
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let val = obj[key];
if (val && val !== undefined) {
if (encodeVals) {
let encodedVal = encodeURIComponent(val);
params.push(`${key}=${encodedVal}`);
} else {
params.push(`${key}=${val}`);
}
}
}
}
}
if (params.length > 0) {
return "?" + params.join("&");
} else {
return "";
}
}
buildTrack(spotifyTrack: any) {
let artists: string[] = [];
if (spotifyTrack.artists) {
artists = spotifyTrack.artists.map((artist: any) => {
return artist.name;
});
}
let track: Track = new Track();
track.playerType = PlayerType.WebSpotify;
track.type = spotifyTrack.type;
track.artist = artists.join(", ");
track.artist_names = artists;
track.artists = spotifyTrack.artists;
track.uri = spotifyTrack.uri;
track.id = spotifyTrack.id;
track.name = spotifyTrack.name;
track.popularity = spotifyTrack.popularity;
track.duration_ms = spotifyTrack.duration_ms;
track.duration = spotifyTrack.duration_ms;
track.disc_number = spotifyTrack.disc_number;
track.explicit = spotifyTrack.explicit;
track.href = spotifyTrack.href;
track.album = spotifyTrack.album;
return track;
}
}