cody-music
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -15,2 +15,3 @@ export declare function isSpotifyRunning(): Promise<boolean>; | ||
export declare function getState(player: string): Promise<any>; | ||
export declare function getTracksByPlaylistName(player: string, playListName: string): Promise<any>; | ||
/** | ||
@@ -43,1 +44,3 @@ * | ||
export declare function unMute(player: string): Promise<any>; | ||
export declare function setItunesLoved(loved: boolean): Promise<any>; | ||
export declare function playlistNames(player: string): Promise<any>; |
@@ -48,2 +48,19 @@ "use strict"; | ||
exports.getState = getState; | ||
async function getTracksByPlaylistName(player, playListName) { | ||
const params = null; | ||
const argv = [playListName]; | ||
const result = await musicCtr.run(player, "playlistTracksOfPlaylist", params, argv); | ||
let jsonResult = {}; | ||
if (result) { | ||
let jsonList = result.split("[TRACK_END],"); | ||
if (jsonList && jsonList.length > 0) { | ||
for (let i = 0; i < jsonList.length; i++) { | ||
let jsonStr = jsonList[i].trim(); | ||
jsonResult[i] = JSON.parse(jsonStr); | ||
} | ||
} | ||
} | ||
return jsonResult; | ||
} | ||
exports.getTracksByPlaylistName = getTracksByPlaylistName; | ||
/** | ||
@@ -141,1 +158,18 @@ * | ||
exports.unMute = unMute; | ||
function setItunesLoved(loved) { | ||
return musicCtr.setItunesLoved(loved); | ||
} | ||
exports.setItunesLoved = setItunesLoved; | ||
async function playlistNames(player) { | ||
let result = await musicCtr.run(player, "playlistNames"); | ||
// turn this into a string list | ||
if (result) { | ||
result = result.split(","); | ||
// now trim | ||
result = result.map((name) => { | ||
return name.trim(); | ||
}); | ||
} | ||
return result; | ||
} | ||
exports.playlistNames = playlistNames; |
@@ -8,7 +8,8 @@ export declare class MusicController { | ||
startPlayer(player: string): Promise<any>; | ||
execScript(player: string, scriptName: string, params?: any): Promise<any>; | ||
execScript(player: string, scriptName: string, params?: any, argv?: any): Promise<any>; | ||
playTrack(player: string, trackId: string): Promise<any>; | ||
run(player: string, scriptName: string, params?: any): Promise<any>; | ||
run(player: string, scriptName: string, params?: any, argv?: any): Promise<any>; | ||
setVolume(player: string, volume: number): Promise<any>; | ||
setItunesLoved(loved: boolean): Promise<any>; | ||
playTrackInContext(player: string, params: any[]): Promise<any>; | ||
} |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util_1 = require("./util"); | ||
const util_2 = __importDefault(require("util")); | ||
class MusicController { | ||
constructor() { | ||
this.scriptsPath = __dirname + '/scripts/'; | ||
this.scriptsPath = __dirname + "/scripts/"; | ||
this.lastVolumeLevel = null; | ||
@@ -15,25 +11,41 @@ // applscript music commands and scripts | ||
state: { | ||
file: 'get_state.%s.applescript' | ||
file: "get_state.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
volumeUp: { | ||
file: 'volume_up.%s.applescript' | ||
file: "volume_up.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
volumeDown: { | ||
file: 'volume_down.%s.applescript' | ||
file: "volume_down.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
playTrackInContext: 'tell application "%s" to play track "%s" in context "%s"', | ||
play: 'tell application "%s" to play', | ||
playTrack: 'tell application "%s" to play track %s', | ||
pause: 'tell application "%s" to pause', | ||
playPause: 'tell application "%s" to playpause', | ||
next: 'tell application "%s" to play (next track)', | ||
previous: 'tell application "%s" to play (previous track)', | ||
repeatOn: 'tell application "%s" to set %s to %s', | ||
repeatOff: 'tell application "%s" to set %s to %s', | ||
isRepeating: 'tell application "%s" to return %s', | ||
setVolume: 'tell application "%s" to set sound volume to %s', | ||
mute: 'tell application "%s" to set sound volume to 0', | ||
unMute: 'tell application "%s" to set sound volume to %s', | ||
setShuffling: 'tell application "%s" to set %s to %s', | ||
isShuffling: 'tell application "%s" to %s' | ||
playTrackInContext: 'tell application "{0}" to play track "{1}" in context "{2}"', | ||
play: 'tell application "{0}" to play', | ||
playFromLibrary: 'tell application "{0}" to play of playlist "{1}"', | ||
playSongFromLibrary: 'tell application "{0}" to play track "{1}" of playlist "{2}"', | ||
playTrack: 'tell application "{0}" to play track {1}', | ||
pause: 'tell application "{0}" to pause', | ||
playPause: 'tell application "{0}" to playpause', | ||
next: 'tell application "{0}" to play (next track)', | ||
previous: 'tell application "{0}" to play (previous track)', | ||
repeatOn: 'tell application "{0}" to set {1} to {2}', | ||
repeatOff: 'tell application "{0}" to set {1} to {2}', | ||
isRepeating: 'tell application "{0}" to return {1}', | ||
setVolume: 'tell application "{0}" to set sound volume to {1}', | ||
mute: 'tell application "{0}" to set sound volume to 0', | ||
unMute: 'tell application "{0}" to set sound volume to {1}', | ||
setShuffling: 'tell application "{0}" to set {1} to {2}', | ||
isShuffling: 'tell application "{0}" to {1}', | ||
playlistNames: { | ||
file: "get_playlist_names.{0}.applescript" | ||
}, | ||
playTrackOfPlaylist: { | ||
file: "play_track_of_playlist.{0}.applescript" | ||
}, | ||
playlistTracksOfPlaylist: { | ||
file: "get_playlist_songs.{0}.applescript", | ||
requiresArgv: true | ||
}, | ||
setItunesLoved: 'tell application "{0}" to set loved of current track to {1}' | ||
}; | ||
@@ -56,3 +68,3 @@ } | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -66,7 +78,7 @@ return result; | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
async execScript(player, scriptName, params = null) { | ||
async execScript(player, scriptName, params = null, argv = null) { | ||
player = util_1.getPlayerName(player); | ||
@@ -82,15 +94,28 @@ let script = this.scripts[scriptName]; | ||
} | ||
let command = ''; | ||
let command = ""; | ||
// get the script file if the attribut has one | ||
if (script.file) { | ||
// apply the params (which should only have the player name) | ||
const scriptFile = util_2.default.format.apply(util_2.default, [script.file].concat(params)); | ||
const scriptFile = util_1.formatString(script.file, params); | ||
let file = `${this.scriptsPath}${scriptFile}`; | ||
command = `osascript ${file}`; | ||
if (argv) { | ||
// make sure they have quotes around the argv | ||
argv = argv.map((val) => { | ||
return `"${val}"`; | ||
}); | ||
const argvOptions = argv.join(" "); | ||
command = `osascript ${file} ${argvOptions}`; | ||
} | ||
else { | ||
command = `osascript ${file}`; | ||
} | ||
// script = fs.readFileSync(file).toString(); | ||
} | ||
else { | ||
if (scriptName === "play" && player.toLowerCase() === "itunes") { | ||
script = this.scripts.playFromLibrary; | ||
params.push("Library"); | ||
} | ||
// apply the params to the one line script | ||
script = util_2.default.format.apply(util_2.default, [script].concat(params)); | ||
// console.log("script to use: ", script); | ||
script = util_1.formatString(script, params); | ||
command = `osascript -e \'${script}\'`; | ||
@@ -100,3 +125,3 @@ } | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -107,3 +132,3 @@ return result; | ||
let params = null; | ||
if (player === 'Spotify') { | ||
if (player === "Spotify") { | ||
params = [`"${trackId}"`]; | ||
@@ -114,5 +139,5 @@ } | ||
} | ||
return this.execScript(player, 'playTrack', params).then(result => { | ||
return this.execScript(player, "playTrack", params).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -122,62 +147,62 @@ return result; | ||
} | ||
async run(player, scriptName, params = null) { | ||
if (player === 'Spotify') { | ||
if (scriptName === 'repeatOn') { | ||
params = ['repeating', 'true']; | ||
async run(player, scriptName, params = null, argv = null) { | ||
if (player === "Spotify") { | ||
if (scriptName === "repeatOn") { | ||
params = ["repeating", "true"]; | ||
} | ||
else if (scriptName === 'repeatOff') { | ||
params = ['repeating', 'false']; | ||
else if (scriptName === "repeatOff") { | ||
params = ["repeating", "false"]; | ||
} | ||
else if (scriptName === 'isRepeating') { | ||
params = ['repeating']; | ||
else if (scriptName === "isRepeating") { | ||
params = ["repeating"]; | ||
} | ||
else if (scriptName === 'setShuffling') { | ||
else if (scriptName === "setShuffling") { | ||
// this will already have params | ||
params.unshift('shuffling'); | ||
params.unshift("shuffling"); | ||
} | ||
else if (scriptName === 'isShuffling') { | ||
params = ['return shuffling']; | ||
else if (scriptName === "isShuffling") { | ||
params = ["return shuffling"]; | ||
} | ||
} | ||
else if (player === 'iTunes') { | ||
if (scriptName === 'repeatOn') { | ||
else if (player === "iTunes") { | ||
if (scriptName === "repeatOn") { | ||
// repeat one for itunes | ||
params = ['song repeat', 'one']; | ||
params = ["song repeat", "one"]; | ||
} | ||
else if (scriptName === 'repeatOff') { | ||
else if (scriptName === "repeatOff") { | ||
// repeat off for itunes | ||
params = ['song repeat', 'off']; | ||
params = ["song repeat", "off"]; | ||
} | ||
else if (scriptName === 'isRepeating') { | ||
else if (scriptName === "isRepeating") { | ||
// get the song repeat value | ||
params = ['song repeat']; | ||
params = ["song repeat"]; | ||
} | ||
else if (scriptName === 'setShuffling') { | ||
params.unshift('shuffle enabled'); | ||
else if (scriptName === "setShuffling") { | ||
params.unshift("shuffle enabled"); | ||
} | ||
else if (scriptName === 'isShuffling') { | ||
params = ['get shuffle enabled']; | ||
else if (scriptName === "isShuffling") { | ||
params = ["get shuffle enabled"]; | ||
} | ||
} | ||
if (scriptName === 'mute') { | ||
if (scriptName === "mute") { | ||
// get the current volume state | ||
let stateResult = await this.execScript(player, 'state'); | ||
let stateResult = await this.execScript(player, "state"); | ||
let json = JSON.parse(stateResult); | ||
this.lastVolumeLevel = json.volume; | ||
} | ||
else if (scriptName === 'unMute') { | ||
else if (scriptName === "unMute") { | ||
params = [this.lastVolumeLevel]; | ||
} | ||
else if (scriptName === 'next' || scriptName === 'previous') { | ||
else if (scriptName === "next" || scriptName === "previous") { | ||
// make sure it's not on repeat | ||
if (player === 'Spotify') { | ||
await this.execScript(player, 'state', ['repeating', 'false']); | ||
if (player === "Spotify") { | ||
await this.execScript(player, "state", ["repeating", "false"]); | ||
} | ||
else { | ||
await this.execScript(player, 'state', ['song repeat', 'off']); | ||
await this.execScript(player, "state", ["song repeat", "off"]); | ||
} | ||
} | ||
return this.execScript(player, scriptName, params).then(result => { | ||
return this.execScript(player, scriptName, params, argv).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -189,5 +214,5 @@ return result; | ||
this.lastVolumeLevel = volume; | ||
return this.execScript(player, 'setVolume', [volume]).then(result => { | ||
return this.execScript(player, "setVolume", [volume]).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -197,6 +222,14 @@ return result; | ||
} | ||
setItunesLoved(loved) { | ||
return this.execScript(util_1.ITUNES_NAME, "setItunesLoved", [loved]).then(result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
}); | ||
} | ||
playTrackInContext(player, params) { | ||
return this.execScript(player, 'playTrackInContext', params).then(result => { | ||
return this.execScript(player, "playTrackInContext", params).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok'; | ||
result = "ok"; | ||
} | ||
@@ -203,0 +236,0 @@ return result; |
@@ -10,1 +10,2 @@ export declare const SPOTIFY_NAME = "Spotify"; | ||
export declare function getPlayerName(player: string): string; | ||
export declare function formatString(source: string, params: any): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const child_process_1 = require("child_process"); | ||
exports.SPOTIFY_NAME = 'Spotify'; | ||
exports.ITUNES_NAME = 'iTunes'; | ||
exports.SPOTIFY_NAME = "Spotify"; | ||
exports.ITUNES_NAME = "iTunes"; | ||
function isLinux() { | ||
@@ -13,11 +13,12 @@ return isWindows() || isMac() ? false : true; | ||
function isWindows() { | ||
return process.platform.indexOf('win32') !== -1; | ||
return process.platform.indexOf("win32") !== -1; | ||
} | ||
exports.isWindows = isWindows; | ||
function isMac() { | ||
return process.platform.indexOf('darwin') !== -1; | ||
return process.platform.indexOf("darwin") !== -1; | ||
} | ||
exports.isMac = isMac; | ||
function isBooleanString(val) { | ||
if ((val && val.toLowerCase() === 'true') || val.toLowerCase() === 'false') { | ||
if ((val && val.toLowerCase() === "true") || | ||
val.toLowerCase() === "false") { | ||
return true; | ||
@@ -31,3 +32,5 @@ } | ||
try { | ||
let opts = projectDir !== undefined && projectDir !== null ? { cwd: projectDir } : {}; | ||
let opts = projectDir !== undefined && projectDir !== null | ||
? { cwd: projectDir } | ||
: {}; | ||
result = await execPromise(cmd, opts); | ||
@@ -64,7 +67,7 @@ } | ||
if (!player || player.trim().length === 0) { | ||
player = 'Spotify'; | ||
player = "Spotify"; | ||
return player; | ||
} | ||
player = player.trim().toLowerCase(); | ||
if (player === 'itunes') { | ||
if (player === "itunes") { | ||
return exports.ITUNES_NAME; | ||
@@ -75,1 +78,12 @@ } | ||
exports.getPlayerName = getPlayerName; | ||
function formatString(source, params) { | ||
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; | ||
} | ||
exports.formatString = formatString; |
44
index.ts
@@ -48,2 +48,28 @@ import { MusicController } from "./lib/controller"; | ||
export async function getTracksByPlaylistName( | ||
player: string, | ||
playListName: string | ||
) { | ||
const params = null; | ||
const argv = [playListName]; | ||
const result = await musicCtr.run( | ||
player, | ||
"playlistTracksOfPlaylist", | ||
params, | ||
argv | ||
); | ||
let jsonResult: any = {}; | ||
if (result) { | ||
let jsonList = result.split("[TRACK_END],"); | ||
if (jsonList && jsonList.length > 0) { | ||
for (let i = 0; i < jsonList.length; i++) { | ||
let jsonStr = jsonList[i].trim(); | ||
jsonResult[i] = JSON.parse(jsonStr); | ||
} | ||
} | ||
} | ||
return jsonResult; | ||
} | ||
/** | ||
@@ -141,1 +167,19 @@ * | ||
} | ||
export function setItunesLoved(loved: boolean) { | ||
return musicCtr.setItunesLoved(loved); | ||
} | ||
export async function playlistNames(player: string) { | ||
let result = await musicCtr.run(player, "playlistNames"); | ||
// turn this into a string list | ||
if (result) { | ||
result = result.split(","); | ||
// now trim | ||
result = result.map((name: string) => { | ||
return name.trim(); | ||
}); | ||
} | ||
return result; | ||
} |
@@ -1,190 +0,242 @@ | ||
import { execCmd, getPlayerName } from './util' | ||
import util from 'util' | ||
import { execCmd, getPlayerName, formatString, ITUNES_NAME } from "./util"; | ||
export class MusicController { | ||
private scriptsPath: string = __dirname + '/scripts/' | ||
private lastVolumeLevel: any = null | ||
private scriptsPath: string = __dirname + "/scripts/"; | ||
private lastVolumeLevel: any = null; | ||
// applscript music commands and scripts | ||
private scripts: any = { | ||
state: { | ||
file: 'get_state.%s.applescript' | ||
}, | ||
volumeUp: { | ||
file: 'volume_up.%s.applescript' | ||
}, | ||
volumeDown: { | ||
file: 'volume_down.%s.applescript' | ||
}, | ||
playTrackInContext: | ||
'tell application "%s" to play track "%s" in context "%s"', | ||
play: 'tell application "%s" to play', | ||
playTrack: 'tell application "%s" to play track %s', | ||
pause: 'tell application "%s" to pause', | ||
playPause: 'tell application "%s" to playpause', | ||
next: 'tell application "%s" to play (next track)', | ||
previous: 'tell application "%s" to play (previous track)', | ||
repeatOn: 'tell application "%s" to set %s to %s', | ||
repeatOff: 'tell application "%s" to set %s to %s', | ||
isRepeating: 'tell application "%s" to return %s', | ||
setVolume: 'tell application "%s" to set sound volume to %s', | ||
mute: 'tell application "%s" to set sound volume to 0', | ||
unMute: 'tell application "%s" to set sound volume to %s', | ||
setShuffling: 'tell application "%s" to set %s to %s', | ||
isShuffling: 'tell application "%s" to %s' | ||
} | ||
// applscript music commands and scripts | ||
private scripts: any = { | ||
state: { | ||
file: "get_state.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
volumeUp: { | ||
file: "volume_up.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
volumeDown: { | ||
file: "volume_down.{0}.applescript", | ||
requiresArgv: false | ||
}, | ||
playTrackInContext: | ||
'tell application "{0}" to play track "{1}" in context "{2}"', | ||
play: 'tell application "{0}" to play', | ||
playFromLibrary: 'tell application "{0}" to play of playlist "{1}"', | ||
playSongFromLibrary: | ||
'tell application "{0}" to play track "{1}" of playlist "{2}"', | ||
playTrack: 'tell application "{0}" to play track {1}', | ||
pause: 'tell application "{0}" to pause', | ||
playPause: 'tell application "{0}" to playpause', | ||
next: 'tell application "{0}" to play (next track)', | ||
previous: 'tell application "{0}" to play (previous track)', | ||
repeatOn: 'tell application "{0}" to set {1} to {2}', | ||
repeatOff: 'tell application "{0}" to set {1} to {2}', | ||
isRepeating: 'tell application "{0}" to return {1}', | ||
setVolume: 'tell application "{0}" to set sound volume to {1}', | ||
mute: 'tell application "{0}" to set sound volume to 0', | ||
unMute: 'tell application "{0}" to set sound volume to {1}', | ||
setShuffling: 'tell application "{0}" to set {1} to {2}', | ||
isShuffling: 'tell application "{0}" to {1}', | ||
playlistNames: { | ||
file: "get_playlist_names.{0}.applescript" | ||
}, | ||
playTrackOfPlaylist: { | ||
file: "play_track_of_playlist.{0}.applescript" | ||
}, | ||
playlistTracksOfPlaylist: { | ||
file: "get_playlist_songs.{0}.applescript", | ||
requiresArgv: true | ||
}, | ||
setItunesLoved: | ||
'tell application "{0}" to set loved of current track to {1}' | ||
}; | ||
async isMusicPlayerActive(player: string) { | ||
player = getPlayerName(player) | ||
const command = `pgrep -x ${player}` | ||
// this returns the PID of the requested player | ||
const result = await execCmd(command) | ||
if (result && !result.error) { | ||
return true | ||
async isMusicPlayerActive(player: string) { | ||
player = getPlayerName(player); | ||
const command = `pgrep -x ${player}`; | ||
// this returns the PID of the requested player | ||
const result = await execCmd(command); | ||
if (result && !result.error) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return false | ||
} | ||
async stopPlayer(player: string) { | ||
player = getPlayerName(player) | ||
const command = `pgrep -x ${player} | xargs kill -9` | ||
let result = await execCmd(command) | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
async stopPlayer(player: string) { | ||
player = getPlayerName(player); | ||
const command = `pgrep -x ${player} | xargs kill -9`; | ||
let result = await execCmd(command); | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
return result | ||
} | ||
async startPlayer(player: string) { | ||
player = getPlayerName(player) | ||
const command = `open -a ${player}` | ||
let result = await execCmd(command) | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
async startPlayer(player: string) { | ||
player = getPlayerName(player); | ||
const command = `open -a ${player}`; | ||
let result = await execCmd(command); | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
return result | ||
} | ||
async execScript(player: string, scriptName: string, params: any = null) { | ||
player = getPlayerName(player) | ||
let script = this.scripts[scriptName] | ||
async execScript( | ||
player: string, | ||
scriptName: string, | ||
params: any = null, | ||
argv: any = null | ||
) { | ||
player = getPlayerName(player); | ||
let script = this.scripts[scriptName]; | ||
if (!params) { | ||
// set player to the params | ||
params = [player] | ||
} else { | ||
// push the player to the front of the params array | ||
params.unshift(player) | ||
if (!params) { | ||
// set player to the params | ||
params = [player]; | ||
} else { | ||
// push the player to the front of the params array | ||
params.unshift(player); | ||
} | ||
let command = ""; | ||
// get the script file if the attribut has one | ||
if (script.file) { | ||
// apply the params (which should only have the player name) | ||
const scriptFile = formatString(script.file, params); | ||
let file = `${this.scriptsPath}${scriptFile}`; | ||
if (argv) { | ||
// make sure they have quotes around the argv | ||
argv = argv.map((val: any) => { | ||
return `"${val}"`; | ||
}); | ||
const argvOptions = argv.join(" "); | ||
command = `osascript ${file} ${argvOptions}`; | ||
} else { | ||
command = `osascript ${file}`; | ||
} | ||
// script = fs.readFileSync(file).toString(); | ||
} else { | ||
if (scriptName === "play" && player.toLowerCase() === "itunes") { | ||
script = this.scripts.playFromLibrary; | ||
params.push("Library"); | ||
} | ||
// apply the params to the one line script | ||
script = formatString(script, params); | ||
command = `osascript -e \'${script}\'`; | ||
} | ||
let result = await execCmd(command); | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
let command = '' | ||
// get the script file if the attribut has one | ||
if (script.file) { | ||
// apply the params (which should only have the player name) | ||
const scriptFile = util.format.apply(util, [script.file].concat(params)) | ||
let file = `${this.scriptsPath}${scriptFile}` | ||
command = `osascript ${file}` | ||
// script = fs.readFileSync(file).toString(); | ||
} else { | ||
// apply the params to the one line script | ||
script = util.format.apply(util, [script].concat(params)) | ||
// console.log("script to use: ", script); | ||
command = `osascript -e \'${script}\'` | ||
playTrack(player: string, trackId: string) { | ||
let params = null; | ||
if (player === "Spotify") { | ||
params = [`"${trackId}"`]; | ||
} else { | ||
params = [`${trackId}`]; | ||
} | ||
return this.execScript(player, "playTrack", params).then(result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
}); | ||
} | ||
let result = await execCmd(command) | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
async run( | ||
player: string, | ||
scriptName: string, | ||
params: any = null, | ||
argv: any = null | ||
) { | ||
if (player === "Spotify") { | ||
if (scriptName === "repeatOn") { | ||
params = ["repeating", "true"]; | ||
} else if (scriptName === "repeatOff") { | ||
params = ["repeating", "false"]; | ||
} else if (scriptName === "isRepeating") { | ||
params = ["repeating"]; | ||
} else if (scriptName === "setShuffling") { | ||
// this will already have params | ||
params.unshift("shuffling"); | ||
} else if (scriptName === "isShuffling") { | ||
params = ["return shuffling"]; | ||
} | ||
} else if (player === "iTunes") { | ||
if (scriptName === "repeatOn") { | ||
// repeat one for itunes | ||
params = ["song repeat", "one"]; | ||
} else if (scriptName === "repeatOff") { | ||
// repeat off for itunes | ||
params = ["song repeat", "off"]; | ||
} else if (scriptName === "isRepeating") { | ||
// get the song repeat value | ||
params = ["song repeat"]; | ||
} else if (scriptName === "setShuffling") { | ||
params.unshift("shuffle enabled"); | ||
} else if (scriptName === "isShuffling") { | ||
params = ["get shuffle enabled"]; | ||
} | ||
} | ||
if (scriptName === "mute") { | ||
// get the current volume state | ||
let stateResult = await this.execScript(player, "state"); | ||
let json = JSON.parse(stateResult); | ||
this.lastVolumeLevel = json.volume; | ||
} else if (scriptName === "unMute") { | ||
params = [this.lastVolumeLevel]; | ||
} else if (scriptName === "next" || scriptName === "previous") { | ||
// make sure it's not on repeat | ||
if (player === "Spotify") { | ||
await this.execScript(player, "state", ["repeating", "false"]); | ||
} else { | ||
await this.execScript(player, "state", ["song repeat", "off"]); | ||
} | ||
} | ||
return this.execScript(player, scriptName, params, argv).then( | ||
result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
); | ||
} | ||
return result | ||
} | ||
playTrack(player: string, trackId: string) { | ||
let params = null | ||
if (player === 'Spotify') { | ||
params = [`"${trackId}"`] | ||
} else { | ||
params = [`${trackId}`] | ||
setVolume(player: string, volume: number) { | ||
this.lastVolumeLevel = volume; | ||
return this.execScript(player, "setVolume", [volume]).then(result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
}); | ||
} | ||
return this.execScript(player, 'playTrack', params).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
} | ||
return result | ||
}) | ||
} | ||
async run(player: string, scriptName: string, params: any = null) { | ||
if (player === 'Spotify') { | ||
if (scriptName === 'repeatOn') { | ||
params = ['repeating', 'true'] | ||
} else if (scriptName === 'repeatOff') { | ||
params = ['repeating', 'false'] | ||
} else if (scriptName === 'isRepeating') { | ||
params = ['repeating'] | ||
} else if (scriptName === 'setShuffling') { | ||
// this will already have params | ||
params.unshift('shuffling') | ||
} else if (scriptName === 'isShuffling') { | ||
params = ['return shuffling'] | ||
} | ||
} else if (player === 'iTunes') { | ||
if (scriptName === 'repeatOn') { | ||
// repeat one for itunes | ||
params = ['song repeat', 'one'] | ||
} else if (scriptName === 'repeatOff') { | ||
// repeat off for itunes | ||
params = ['song repeat', 'off'] | ||
} else if (scriptName === 'isRepeating') { | ||
// get the song repeat value | ||
params = ['song repeat'] | ||
} else if (scriptName === 'setShuffling') { | ||
params.unshift('shuffle enabled') | ||
} else if (scriptName === 'isShuffling') { | ||
params = ['get shuffle enabled'] | ||
} | ||
setItunesLoved(loved: boolean) { | ||
return this.execScript(ITUNES_NAME, "setItunesLoved", [loved]).then( | ||
result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
); | ||
} | ||
if (scriptName === 'mute') { | ||
// get the current volume state | ||
let stateResult = await this.execScript(player, 'state') | ||
let json = JSON.parse(stateResult) | ||
this.lastVolumeLevel = json.volume | ||
} else if (scriptName === 'unMute') { | ||
params = [this.lastVolumeLevel] | ||
} else if (scriptName === 'next' || scriptName === 'previous') { | ||
// make sure it's not on repeat | ||
if (player === 'Spotify') { | ||
await this.execScript(player, 'state', ['repeating', 'false']) | ||
} else { | ||
await this.execScript(player, 'state', ['song repeat', 'off']) | ||
} | ||
playTrackInContext(player: string, params: any[]) { | ||
return this.execScript(player, "playTrackInContext", params).then( | ||
result => { | ||
if (result === null || result === undefined) { | ||
result = "ok"; | ||
} | ||
return result; | ||
} | ||
); | ||
} | ||
return this.execScript(player, scriptName, params).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
} | ||
return result | ||
}) | ||
} | ||
setVolume(player: string, volume: number) { | ||
this.lastVolumeLevel = volume | ||
return this.execScript(player, 'setVolume', [volume]).then(result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
} | ||
return result | ||
}) | ||
} | ||
playTrackInContext(player: string, params: any[]) { | ||
return this.execScript(player, 'playTrackInContext', params).then( | ||
result => { | ||
if (result === null || result === undefined) { | ||
result = 'ok' | ||
} | ||
return result | ||
} | ||
) | ||
} | ||
} |
@@ -1,8 +0,8 @@ | ||
import { exec } from 'child_process' | ||
import { exec } from "child_process"; | ||
export const SPOTIFY_NAME = 'Spotify' | ||
export const ITUNES_NAME = 'iTunes' | ||
export const SPOTIFY_NAME = "Spotify"; | ||
export const ITUNES_NAME = "iTunes"; | ||
export function isLinux() { | ||
return isWindows() || isMac() ? false : true | ||
return isWindows() || isMac() ? false : true; | ||
} | ||
@@ -13,38 +13,43 @@ | ||
export function isWindows() { | ||
return process.platform.indexOf('win32') !== -1 | ||
return process.platform.indexOf("win32") !== -1; | ||
} | ||
export function isMac() { | ||
return process.platform.indexOf('darwin') !== -1 | ||
return process.platform.indexOf("darwin") !== -1; | ||
} | ||
export function isBooleanString(val: string) { | ||
if ((val && val.toLowerCase() === 'true') || val.toLowerCase() === 'false') { | ||
return true | ||
} | ||
return false | ||
if ( | ||
(val && val.toLowerCase() === "true") || | ||
val.toLowerCase() === "false" | ||
) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
export async function execCmd(cmd: string, projectDir: any = null) { | ||
let result: any = null | ||
try { | ||
let opts = | ||
projectDir !== undefined && projectDir !== null ? { cwd: projectDir } : {} | ||
result = await execPromise(cmd, opts) | ||
} catch (e) { | ||
result = { error: e.message } | ||
} | ||
return result | ||
let result: any = null; | ||
try { | ||
let opts = | ||
projectDir !== undefined && projectDir !== null | ||
? { cwd: projectDir } | ||
: {}; | ||
result = await execPromise(cmd, opts); | ||
} catch (e) { | ||
result = { error: e.message }; | ||
} | ||
return result; | ||
} | ||
async function execPromise(command: string, opts: {}) { | ||
return new Promise((resolve, reject) => { | ||
exec(command, opts, (error: any, stdout: string, stderr: any) => { | ||
if (error) { | ||
reject(error) | ||
return | ||
} | ||
resolve(stdout.trim()) | ||
}) | ||
}) | ||
return new Promise((resolve, reject) => { | ||
exec(command, opts, (error: any, stdout: string, stderr: any) => { | ||
if (error) { | ||
reject(error); | ||
return; | ||
} | ||
resolve(stdout.trim()); | ||
}); | ||
}); | ||
} | ||
@@ -56,17 +61,28 @@ | ||
export function sleep(delayInMillis: number) { | ||
delayInMillis = Math.min(delayInMillis, 5000) | ||
var start = new Date().getTime() | ||
while (new Date().getTime() < start + delayInMillis); | ||
delayInMillis = Math.min(delayInMillis, 5000); | ||
var start = new Date().getTime(); | ||
while (new Date().getTime() < start + delayInMillis); | ||
} | ||
export function getPlayerName(player: string) { | ||
if (!player || player.trim().length === 0) { | ||
player = 'Spotify' | ||
return player | ||
} | ||
player = player.trim().toLowerCase() | ||
if (player === 'itunes') { | ||
return ITUNES_NAME | ||
} | ||
return SPOTIFY_NAME | ||
if (!player || player.trim().length === 0) { | ||
player = "Spotify"; | ||
return player; | ||
} | ||
player = player.trim().toLowerCase(); | ||
if (player === "itunes") { | ||
return ITUNES_NAME; | ||
} | ||
return SPOTIFY_NAME; | ||
} | ||
export function 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; | ||
} |
{ | ||
"name": "cody-music", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "mac osx spotify and itunes music player controller", | ||
@@ -41,3 +41,3 @@ "main": "dist/index.js", | ||
"chai": "^4.2.0", | ||
"mocha": "^6.1.2", | ||
"mocha": "^6.1.4", | ||
"typescript": "^3.3.4000" | ||
@@ -44,0 +44,0 @@ }, |
@@ -20,3 +20,3 @@ # cody-music | ||
```javascript | ||
import * as music from 'cody-music'; | ||
import * as music from "cody-music"; | ||
``` | ||
@@ -27,3 +27,3 @@ | ||
```javascript | ||
const music = require('cody-music'); | ||
const music = require("cody-music"); | ||
``` | ||
@@ -33,2 +33,6 @@ | ||
### playTrack(uri) | ||
Play a track with Music URI `uri`. | ||
Specify either "Spotify" or "iTunes" (case-insensitive). | ||
@@ -38,3 +42,3 @@ | ||
// get the track info using get state | ||
await music.getState('iTunes').then(state => { | ||
await music.getState("iTunes").then(state => { | ||
// - "genre" will be empty from Spotify | ||
@@ -48,3 +52,3 @@ // - duration is in milliseconds | ||
await music | ||
.playTrack('Spotify', 'spotify:track:2YarjDYjBJuH63dUIh9OWv') | ||
.playTrack("Spotify", "spotify:track:2YarjDYjBJuH63dUIh9OWv") | ||
.then(result => { | ||
@@ -55,3 +59,3 @@ // track is playing | ||
// play an iTunes track number | ||
await music.playTrack('iTunes', 1).then(result => { | ||
await music.playTrack("iTunes", 1).then(result => { | ||
// track is playing | ||
@@ -61,3 +65,3 @@ }); | ||
// handling errors | ||
await music.playTrack('iTunes', 1000000000).then(result => { | ||
await music.playTrack("iTunes", 1000000000).then(result => { | ||
// result will contain the "error" attribute with the error message | ||
@@ -103,3 +107,3 @@ if (result.error) { | ||
```javascript | ||
music.setVolume('Spotify', 42).then(() => { | ||
music.setVolume("Spotify", 42).then(() => { | ||
music.getState(state => { | ||
@@ -124,3 +128,3 @@ console.log(state.volume); | ||
```javascript | ||
music.isRunning('Spotify').then(isRunning => { | ||
music.isRunning("Spotify").then(isRunning => { | ||
console.log(isRunning); // true || false | ||
@@ -135,3 +139,3 @@ }); | ||
```js | ||
music.isRepeating('Spotify').then(isRepeating => { | ||
music.isRepeating("Spotify").then(isRepeating => { | ||
console.log(isRepeating); // true || false | ||
@@ -146,3 +150,3 @@ }); | ||
```js | ||
music.isShuffling('Spotify').then(isShuffling => { | ||
music.isShuffling("Spotify").then(isShuffling => { | ||
console.log(isShuffling); // true || false | ||
@@ -152,2 +156,13 @@ }); | ||
Toggle iTunes loved state | ||
```js | ||
music.setItunesLoved(true).then(async result => { | ||
// get the state again | ||
result = await music.getState("iTunes"); | ||
// should equal to true | ||
console.log("loved status: ", result.loved); | ||
}); | ||
``` | ||
## Contributors | ||
@@ -154,0 +169,0 @@ |
@@ -44,2 +44,32 @@ const expect = require("chai").expect; | ||
it("Should Show The Playlist Names AND Show The Tracks Of A Playlist", done => { | ||
music.playlistNames("iTunes").then(names => { | ||
expect(names).to.not.equal(0); | ||
// get the last name in the list and get the tracks | ||
music | ||
.getTracksByPlaylistName("iTunes", names[names.length - 1]) | ||
.then(result => { | ||
expect(result.length).to.not.equal(0); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("Should Set An Itunes Song's Love State", done => { | ||
music.startItunesIfNotRunning().then(async () => { | ||
util.sleep(1500); | ||
await music.setVolume("iTunes", 5); | ||
await music.play("iTunes"); | ||
util.sleep(1500); | ||
let result = await music.getState("iTunes"); | ||
let loved = result.loved; | ||
music.setItunesLoved(!loved).then(async result => { | ||
// get the state again | ||
result = await music.getState("iTunes"); | ||
expect(result.loved).to.equal(!loved); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("Should Show An Error", done => { | ||
@@ -81,12 +111,11 @@ // play a bad track number | ||
await music.setVolume("Spotify", 5); | ||
let params = [ | ||
"spotify:track:0R8P9KfGJCDULmlEoBagcO", | ||
"spotify:album:6ZG5lRT77aJ3btmArcykra" | ||
]; | ||
let params = ["spotify:track:2xbuycY0MolcTZGENc4PuK"]; | ||
await music.playTrackInContext("Spotify", params); | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
let result = await music.getState("Spotify"); | ||
expect(result.artist).to.equal("Coldplay"); | ||
expect(result.name).to.equal("Trouble"); | ||
expect(result.artist).to.equal("Hozier"); | ||
expect(result.name).to.equal( | ||
"Say My Name - Recorded at Spotify Studios NYC" | ||
); | ||
done(); | ||
@@ -102,6 +131,6 @@ }); | ||
music.startItunesIfNotRunning().then(async () => { | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
await music.setVolume("iTunes", 5); | ||
await music.play("iTunes"); | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
let result = await music.getState("iTunes"); | ||
@@ -117,3 +146,3 @@ expect(result.artist).to.not.equal(null); | ||
.then(async () => { | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
let params = [ | ||
@@ -125,3 +154,3 @@ "spotify:track:0R8P9KfGJCDULmlEoBagcO", | ||
await music.playTrackInContext("Spotify", params); | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
@@ -177,6 +206,6 @@ let result = await music.getState("Spotify"); | ||
"Spotify", | ||
"spotify:track:2YarjDYjBJuH63dUIh9OWv" | ||
"spotify:track:4ut5G4rgB1ClpMTMfjoIuy" | ||
); | ||
result = await music.getState("Spotify"); | ||
expect(result.artist).to.equal("Wolfgang Amadeus Mozart"); | ||
expect(result.artist).to.equal("Martin Garrix"); | ||
@@ -202,5 +231,5 @@ // shuffle test | ||
.then(async () => { | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
await music.play("iTunes"); | ||
util.sleep(1000); | ||
util.sleep(1500); | ||
@@ -214,4 +243,5 @@ let result = await music.getState("iTunes"); | ||
await music.next("iTunes"); | ||
// check | ||
result = await music.getState("Spotify"); | ||
result = await music.getState("iTunes"); | ||
expect(result.name).to.not.equal(songName); | ||
@@ -218,0 +248,0 @@ songName = result.name; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36
1514
161
82599