diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/3B4DA55E-BCAC-4E4C-A7A6-0F74FDF23E83.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/3B4DA55E-BCAC-4E4C-A7A6-0F74FDF23E83.png new file mode 100644 index 0000000..1649ca9 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/3B4DA55E-BCAC-4E4C-A7A6-0F74FDF23E83.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/84082CB4-3371-4A78-BEFE-E2DCE977B277.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/84082CB4-3371-4A78-BEFE-E2DCE977B277.png new file mode 100644 index 0000000..1649ca9 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/84082CB4-3371-4A78-BEFE-E2DCE977B277.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/icon.png new file mode 100644 index 0000000..1649ca9 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/info.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/info.plist new file mode 100644 index 0000000..c76c8de --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.08510401-A445-45AE-BCE5-4C95CD85B3EF/info.plist @@ -0,0 +1,119 @@ + + + + + bundleid + jdfwarrior.getip + connections + + 4DE38804-DD3A-4619-B68A-D9290EC54602 + + + destinationuid + B21F5F58-454A-4396-A924-15452A297612 + modifiers + 0 + modifiersubtext + + + + + createdby + David Ferguson + description + What is my IP address? + disabled + + name + IP Address v1.2.0 + objects + + + config + + autopaste + + clipboardtext + {query} + + type + alfred.workflow.output.clipboard + uid + B21F5F58-454A-4396-A924-15452A297612 + version + 0 + + + config + + argumenttype + 2 + escaping + 63 + keyword + ip + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + Reading ip address + script + LOCAL=$(ifconfig | grep -A 1 "en" | grep broadcast | cut -d " " -f 2 | tr "\\n" " ") +EXTERNAL=$(curl --silent http://icanhazip.com) + +cat<<EOB +<?xml version="1.0"?> +<items> +<item uid="localip" arg="$LOCAL"> +<title>Local IP: $LOCAL</title> +<subtitle>Press Enter to paste, or Cmd+C to copy</subtitle> +<icon>icon.png</icon> +</item> +<item uid="externalip" arg="$EXTERNAL"> +<title>External IP: $EXTERNAL</title> +<subtitle>Press Enter to paste, or Cmd+C to copy</subtitle> +<icon>icon.png</icon> +</item> +</items> +EOB + subtext + Get your local and external IP address + title + Get IP Address + type + 5 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 4DE38804-DD3A-4619-B68A-D9290EC54602 + version + 0 + + + readme + Updated by Andreas Stokholm to be able to handle multiple local IP-addresses. + uidata + + 4DE38804-DD3A-4619-B68A-D9290EC54602 + + ypos + 10 + + B21F5F58-454A-4396-A924-15452A297612 + + ypos + 10 + + + webaddress + jdfwarrior.tumblr.com + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/decode.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/decode.php new file mode 100644 index 0000000..28e1937 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/decode.php @@ -0,0 +1,86 @@ + \u0058"; // URL, +// **************** + +require_once('workflows.php'); + +$w = new Workflows(); +if (!isset($query)) { + $query = $argv[1]; +} + +function force_utf8_safe($str) { + $res = mb_convert_encoding($str, "UTF-8", "UTF-8" ); // replace invalid characters with ? + $res = preg_replace('/\p{Cc}+/u', '?', $res); // replace control characters with ? + return $res; +} + +function prepare_output($items) { + $res = []; + foreach ($items as $key => $value) { + // Make UTF-8 safe results. + $safe_value = force_utf8_safe($value); + if ($value != $safe_value) { + $key .= ' (Invalid characters replaced with ?)'; + $value = $safe_value; + } + $res[$key] = $value; + } + return $res; +} + +function replace_unicode_escape_sequence($match) { + return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); +} + +function html_decode($str) { + return str_replace(array("<", ">", '&', ''', '"','<', '>'), array("<", ">",'&','\'','"','<','>'), htmlspecialchars_decode($str, ENT_NOQUOTES)); +} + +if (0) { + echo "".$query."\n"; + echo "urlencode = ".urldecode($query)."\n"; + echo "utf8_encode = ".utf8_decode($query)."\n"; + echo "unicode = ".preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence', $query)."\n"; + echo "htmlentities = ".html_entity_decode($query)."\n"; + echo "base64_encode = ".base64_decode($query)."\n"; + + exit(); +} + +$decodes = array(); +// url +$url_decode = urldecode($query); +if ($url_decode != $query) $decodes["URL Decoded"] = $url_decode; + +// unicode +$unicode_decode = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence', $query); +if ($unicode_decode != $query) $decodes["Unicode Decoded"] = $unicode_decode; + +// HTML +$html_decode = html_entity_decode($query, ENT_QUOTES, 'UTF-8'); +if ($html_decode != $query) $decodes["HTML Decoded"] = $html_decode; + +// base64 +$base64_decode = base64_decode($query, true); +if ($base64_decode && $base64_decode != $query) { $decodes["base64 Decoded"] = $base64_decode; } + +//$dencodes["UTF-8 Decoded"] = utf8_decode($query); + +$decodes = prepare_output($decodes); + +foreach($decodes as $key => $value) { + $w->result( $key, $value, $value, $key, 'icon.png', 'yes' ); +} + +if ( count( $w->results() ) == 0 ) { + $w->result( 'decode', $query, 'Nothing useful resulted', 'The decoded strings were the same as your query', 'icon.png', 'yes' ); +} + +echo $w->toxml(); +// **************** +?> \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/encode.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/encode.php new file mode 100644 index 0000000..accc895 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/encode.php @@ -0,0 +1,103 @@ + 0) { + $ret = array(); + $len = mb_strlen($str, "UTF-8"); + for ($i = 0; $i < $len; $i += $l) { + $ret[] = mb_substr($str, $i, $l, "UTF-8"); + } + return $ret; + } + return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY); +} + +require_once('workflows.php'); + +$w = new Workflows(); +if (!isset($query)) { + $query = $argv[1]; +} + +function force_utf8_safe($str) { + $res = mb_convert_encoding($str, "UTF-8", "UTF-8" ); // replace invalid characters with ? + $res = preg_replace('/\p{Cc}+/u', '?', $res); // replace control characters with ? + return $res; +} + +function prepare_output($items) { + $res = []; + foreach ($items as $key => $value) { + // Make UTF-8 safe results. + $safe_value = force_utf8_safe($value); + if ($value != $safe_value) { + $key .= ' (Invalid characters replaced with ?)'; + $value = $safe_value; + } + $res[$key] = $value; + } + return $res; +} + +$chars = str_split_unicode($query); + +if (0) { + echo "".$query." - ".implode("", $chars)."\n"; + echo "urlencode = ".urlencode($query)."\n"; + echo "utf8_encode = ".utf8_encode($query)."\n"; + echo "htmlentities = ".htmlentities($query, ENT_QUOTES, 'UTF-8', false)."\n"; + $html_encode = ''; + $table = get_html_translation_table(HTML_ENTITIES); + for ($i = 0, $l = sizeof($chars); $i < $l; $i++) { + echo $chars[$i]." -> ".$table[$chars[$i]]."\n"; + $html_encode .= $table[$chars[$i]] ? $table[$chars[$i]] : $chars[$i]; + } + $html_encode = htmlentities($html_encode, ENT_QUOTES, 'UTF-8', false); + echo " = ".$html_encode."\n"; + echo "base64_encode = ".base64_encode($query)."\n"; + + exit(); +} + + +$encodes = array(); + +// url +$url_encode = urlencode($query); +if ($url_encode != $query) $encodes["URL Encoded"] = $url_encode; + +// HTML +/*$html_encode = ''; +$table = get_html_translation_table(HTML_ENTITIES); +for ($i = 0, $l = sizeof($chars); $i < $l; $i++) { + $html_encode .= $table[$chars[$i]] ? $table[$chars[$i]] : $chars[$i]; +} +$html_encode = htmlentities($html_encode, ENT_QUOTES, 'UTF-8', false);*/ +$html_encode = htmlentities($query, ENT_QUOTES, 'UTF-8'); +if ($html_encode != $query) $encodes["HTML Encoded"] = $html_encode; + +// base64 +$base64_encode = base64_encode($query); +if ($base64_encode != $query) $encodes["base64 Encoded"] = $base64_encode; + + +$encodes = prepare_output($encodes); + +foreach($encodes as $key => $value) { + $w->result( $key, $value, $value, $key, 'icon.png', 'yes' ); +} + +if ( count( $w->results() ) == 0 ) { + $w->result( 'encode', $query, 'Nothing useful resulted', 'The encoded strings were the same as your query', 'icon.png', 'yes' ); +} + +echo $w->toxml(); +// **************** +?> \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/icon.png new file mode 100644 index 0000000..0f045f7 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/info.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/info.plist new file mode 100644 index 0000000..cfdccaa --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/info.plist @@ -0,0 +1,231 @@ + + + + + bundleid + com.farrell.encode-decode.alfredworkflow + category + Productivity + connections + + 807BFA1D-EAEC-4DB7-B04E-6371C601A9E7 + + + destinationuid + 72E910A8-F09C-4863-9F54-F60E273C59AB + modifiers + 0 + modifiersubtext + + + + destinationuid + 1EB2B864-2602-4BF2-AEE5-80092DCE02FF + modifiers + 0 + modifiersubtext + + + + 96A609DD-13FB-44C7-9ADB-F3BC94017A65 + + D9450D59-0E2F-4E83-9BDD-7EAF0878E5DC + + + destinationuid + 72E910A8-F09C-4863-9F54-F60E273C59AB + modifiers + 0 + modifiersubtext + + + + destinationuid + 1EB2B864-2602-4BF2-AEE5-80092DCE02FF + modifiers + 0 + modifiersubtext + + + + + createdby + Will Farrell + description + Encode/Decode Strings + disabled + + name + Encode / Decode v1.8.0 + objects + + + config + + action + 0 + argument + 0 + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 96A609DD-13FB-44C7-9ADB-F3BC94017A65 + version + 1 + + + config + + argumenttype + 0 + escaping + 102 + keyword + encode + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + Encoding "{query}" + script + php encode.php "$(./normalise -form NFC "{query}")" + subtext + Encode "{query}" + title + Encode + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 807BFA1D-EAEC-4DB7-B04E-6371C601A9E7 + version + 0 + + + config + + autopaste + + clipboardtext + {query} + + type + alfred.workflow.output.clipboard + uid + 72E910A8-F09C-4863-9F54-F60E273C59AB + version + 0 + + + config + + argumenttype + 0 + escaping + 102 + keyword + decode + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + Decoding "{query}" + script + php decode.php "$(./normalise -form NFC "{query}")" + subtext + Decode "{query}" + title + Decode + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + D9450D59-0E2F-4E83-9BDD-7EAF0878E5DC + version + 0 + + + config + + lastpathcomponent + + onlyshowifquerypopulated + + output + 0 + removeextension + + sticky + + text + {query} + title + Added to Clipboard + + type + alfred.workflow.output.notification + uid + 1EB2B864-2602-4BF2-AEE5-80092DCE02FF + version + 0 + + + readme + + uidata + + 1EB2B864-2602-4BF2-AEE5-80092DCE02FF + + ypos + 140 + + 72E910A8-F09C-4863-9F54-F60E273C59AB + + ypos + 10 + + 807BFA1D-EAEC-4DB7-B04E-6371C601A9E7 + + ypos + 10 + + 96A609DD-13FB-44C7-9ADB-F3BC94017A65 + + ypos + 10 + + D9450D59-0E2F-4E83-9BDD-7EAF0878E5DC + + ypos + 140 + + + webaddress + github.com/willfarrell + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/normalise b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/normalise new file mode 100755 index 0000000..0b45424 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/normalise differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/update.json b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/update.json new file mode 100644 index 0000000..ccd5251 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/update.json @@ -0,0 +1,4 @@ +{ + "version": 1.8, + "remote_json": "https://raw.github.com/willfarrell/alfred-encode-decode-workflow/master/current-version.json" +} \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/workflows.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/workflows.php new file mode 100644 index 0000000..caa7c63 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.0C313D26-6325-4A12-AB8C-F3E97D245768/workflows.php @@ -0,0 +1,487 @@ +path = exec('pwd'); + $this->home = exec('printf $HOME'); + + if ( file_exists( 'info.plist' ) ): + $this->bundle = $this->get( 'bundleid', 'info.plist' ); + endif; + + if ( !is_null( $bundleid ) ): + $this->bundle = $bundleid; + endif; + + $this->cache = $this->home. "/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/".$this->bundle; + $this->data = $this->home. "/Library/Application Support/Alfred 2/Workflow Data/".$this->bundle; + + if ( !file_exists( $this->cache ) ): + exec("mkdir '".$this->cache."'"); + endif; + + if ( !file_exists( $this->data ) ): + exec("mkdir '".$this->data."'"); + endif; + + $this->results = array(); + } + + /** + * Description: + * Accepts no parameter and returns the value of the bundle id for the current workflow. + * If no value is available, then false is returned. + * + * @param none + * @return false if not available, bundle id value if available. + */ + public function bundle() + { + if ( is_null( $this->bundle ) ): + return false; + else: + return $this->bundle; + endif; + } + + /** + * Description: + * Accepts no parameter and returns the value of the path to the cache directory for your + * workflow if it is available. Returns false if the value isn't available. + * + * @param none + * @return false if not available, path to the cache directory for your workflow if available. + */ + public function cache() + { + if ( is_null( $this->bundle ) ): + return false; + else: + if ( is_null( $this->cache ) ): + return false; + else: + return $this->cache; + endif; + endif; + } + + /** + * Description: + * Accepts no parameter and returns the value of the path to the storage directory for your + * workflow if it is available. Returns false if the value isn't available. + * + * @param none + * @return false if not available, path to the storage directory for your workflow if available. + */ + public function data() + { + if ( is_null( $this->bundle ) ): + return false; + else: + if ( is_null( $this->data ) ): + return false; + else: + return $this->data; + endif; + endif; + } + + /** + * Description: + * Accepts no parameter and returns the value of the path to the current directory for your + * workflow if it is available. Returns false if the value isn't available. + * + * @param none + * @return false if not available, path to the current directory for your workflow if available. + */ + public function path() + { + if ( is_null( $this->path ) ): + return false; + else: + return $this->path; + endif; + } + + /** + * Description: + * Accepts no parameter and returns the value of the home path for the current user + * Returns false if the value isn't available. + * + * @param none + * @return false if not available, home path for the current user if available. + */ + public function home() + { + if ( is_null( $this->home ) ): + return false; + else: + return $this->home; + endif; + } + + /** + * Description: + * Returns an array of available result items + * + * @param none + * @return array - list of result items + */ + public function results() + { + return $this->results; + } + + /** + * Description: + * Convert an associative array into XML format + * + * @param $a - An associative array to convert + * @param $format - format of data being passed (json or array), defaults to array + * @return - XML string representation of the array + */ + public function toxml( $a=null, $format='array' ) { + + if ( $format == 'json' ): + $a = json_decode( $a, TRUE ); + endif; + + if ( is_null( $a ) && !empty( $this->results ) ): + $a = $this->results; + elseif ( is_null( $a ) && empty( $this->results ) ): + return false; + endif; + + $items = new SimpleXMLElement(""); // Create new XML element + + foreach( $a as $b ): // Lop through each object in the array + $c = $items->addChild( 'item' ); // Add a new 'item' element for each object + $c_keys = array_keys( $b ); // Grab all the keys for that item + foreach( $c_keys as $key ): // For each of those keys + if ( $key == 'uid' ): + $c->addAttribute( 'uid', $b[$key] ); + elseif ( $key == 'arg' ): + $c->addAttribute( 'arg', $b[$key] ); + elseif ( $key == 'type' ): + $c->addAttribute( 'type', $b[$key] ); + elseif ( $key == 'valid' ): + if ( $b[$key] == 'yes' || $b[$key] == 'no' ): + $c->addAttribute( 'valid', $b[$key] ); + endif; + elseif ( $key == 'autocomplete' ): + $c->addAttribute( 'autocomplete', $b[$key] ); + elseif ( $key == 'icon' ): + if ( substr( $b[$key], 0, 9 ) == 'fileicon:' ): + $val = substr( $b[$key], 9 ); + $c->$key = $val; + $c->$key->addAttribute( 'type', 'fileicon' ); + elseif ( substr( $b[$key], 0, 9 ) == 'filetype:' ): + $val = substr( $b[$key], 9 ); + $c->$key = $val; + $c->$key->addAttribute( 'type', 'filetype' ); + else: + $c->$key = $b[$key]; + endif; + else: + $c->$key = $b[$key]; + endif; + endforeach; + endforeach; + + return $items->asXML(); // Return XML string representation of the array + + } + + /** + * Description: + * Remove all items from an associative array that do not have a value + * + * @param $a - Associative array + * @return bool + */ + private function empty_filter( $a ) { + if ( $a == '' || $a == null ): // if $a is empty or null + return false; // return false, else, return true + else: + return true; + endif; + } + + /** + * Description: + * Save values to a specified plist. If the first parameter is an associative + * array, then the second parameter becomes the plist file to save to. If the + * first parameter is string, then it is assumed that the first parameter is + * the label, the second parameter is the value, and the third parameter is + * the plist file to save the data to. + * + * @param $a - associative array of values to save + * @param $b - the value of the setting + * @param $c - the plist to save the values into + * @return string - execution output + */ + public function set( $a=null, $b=null, $c=null ) + { + if ( is_array( $a ) ): + if ( file_exists( $b ) ): + if ( file_exists( $this->path.'/'.$b ) ): + $b = $this->path.'/'.$b; + endif; + elseif ( file_exists( $this->data."/".$b ) ): + $b = $this->data."/".$b; + elseif ( file_exists( $this->cache."/".$b ) ): + $b = $this->cache."/".$b; + else: + $b = $this->data."/".$b; + endif; + else: + if ( file_exists( $c ) ): + if ( file_exists( $this->path.'/'.$c ) ): + $c = $this->path.'/'.$c; + endif; + elseif ( file_exists( $this->data."/".$c ) ): + $c = $this->data."/".$c; + elseif ( file_exists( $this->cache."/".$c ) ): + $c = $this->cache."/".$c; + else: + $c = $this->data."/".$c; + endif; + endif; + + if ( is_array( $a ) ): + foreach( $a as $k => $v ): + exec( 'defaults write "'. $b .'" '. $k .' "'. $v .'"'); + endforeach; + else: + exec( 'defaults write "'. $c .'" '. $a .' "'. $b .'"'); + endif; + } + + /** + * Description: + * Read a value from the specified plist + * + * @param $a - the value to read + * @param $b - plist to read the values from + * @return bool false if not found, string if found + */ + public function get( $a, $b ) { + + if ( file_exists( $b ) ): + if ( file_exists( $this->path.'/'.$b ) ): + $b = $this->path.'/'.$b; + endif; + elseif ( file_exists( $this->data."/".$b ) ): + $b = $this->data."/".$b; + elseif ( file_exists( $this->cache."/".$b ) ): + $b = $this->cache."/".$b; + else: + return false; + endif; + + exec( 'defaults read "'. $b .'" '.$a, $out ); // Execute system call to read plist value + + if ( $out == "" ): + return false; + endif; + + $out = $out[0]; + return $out; // Return item value + } + + /** + * Description: + * Read data from a remote file/url, essentially a shortcut for curl + * + * @param $url - URL to request + * @param $options - Array of curl options + * @return result from curl_exec + */ + public function request( $url=null, $options=null ) + { + if ( is_null( $url ) ): + return false; + endif; + + $defaults = array( // Create a list of default curl options + CURLOPT_RETURNTRANSFER => true, // Returns the result as a string + CURLOPT_URL => $url, // Sets the url to request + CURLOPT_FRESH_CONNECT => true + ); + + if ( $options ): + foreach( $options as $k => $v ): + $defaults[$k] = $v; + endforeach; + endif; + + array_filter( $defaults, // Filter out empty options from the array + array( $this, 'empty_filter' ) ); + + $ch = curl_init(); // Init new curl object + curl_setopt_array( $ch, $defaults ); // Set curl options + $out = curl_exec( $ch ); // Request remote data + $err = curl_error( $ch ); + curl_close( $ch ); // End curl request + + if ( $err ): + return $err; + else: + return $out; + endif; + } + + /** + * Description: + * Allows searching the local hard drive using mdfind + * + * @param $query - search string + * @return array - array of search results + */ + public function mdfind( $query ) + { + exec('mdfind "'.$query.'"', $results); + return $results; + } + + /** + * Description: + * Accepts data and a string file name to store data to local file as cache + * + * @param array - data to save to file + * @param file - filename to write the cache data to + * @return none + */ + public function write( $a, $b ) + { + if ( file_exists( $b ) ): + if ( file_exists( $this->path.'/'.$b ) ): + $b = $this->path.'/'.$b; + endif; + elseif ( file_exists( $this->data."/".$b ) ): + $b = $this->data."/".$b; + elseif ( file_exists( $this->cache."/".$b ) ): + $b = $this->cache."/".$b; + else: + $b = $this->data."/".$b; + endif; + + if ( is_array( $a ) ): + $a = json_encode( $a ); + file_put_contents( $b, $a ); + return true; + elseif ( is_string( $a ) ): + file_put_contents( $b, $a ); + return true; + else: + return false; + endif; + } + + /** + * Description: + * Returns data from a local cache file + * + * @param file - filename to read the cache data from + * @return false if the file cannot be found, the file data if found. If the file + * format is json encoded, then a json object is returned. + */ + public function read( $a ) + { + if ( file_exists( $a ) ): + if ( file_exists( $this->path.'/'.$a ) ): + $a = $this->path.'/'.$a; + endif; + elseif ( file_exists( $this->data."/".$a ) ): + $a = $this->data."/".$a; + elseif ( file_exists( $this->cache."/".$a ) ): + $a = $this->cache."/".$a; + else: + return false; + endif; + + $out = file_get_contents( $a ); + if ( !is_null( json_decode( $out ) ) ): + $out = json_decode( $out ); + endif; + + return $out; + } + + public function filetime( $a ) + { + if ( file_exists( $a ) ): + if ( file_exists( $this->path.'/'.$a ) ): + return filemtime($this->path.'/'.$a); + endif; + elseif ( file_exists( $this->data."/".$a ) ): + return filemtime($this->data.'/'.$a); + elseif ( file_exists( $this->cache."/".$a ) ): + return filemtime($this->cache.'/'.$a); + endif; + + return false; + } + + /** + * Description: + * Helper function that just makes it easier to pass values into a function + * and create an array result to be passed back to Alfred + * + * @param $uid - the uid of the result, should be unique + * @param $arg - the argument that will be passed on + * @param $title - The title of the result item + * @param $sub - The subtitle text for the result item + * @param $icon - the icon to use for the result item + * @param $valid - sets whether the result item can be actioned + * @param $auto - the autocomplete value for the result item + * @return array - array item to be passed back to Alfred + */ + public function result( $uid, $arg, $title, $sub, $icon, $valid='yes', $auto=null, $type=null ) + { + $temp = array( + 'uid' => $uid, + 'arg' => $arg, + 'title' => $title, + 'subtitle' => $sub, + 'icon' => $icon, + 'valid' => $valid, + 'autocomplete' => $auto, + 'type' => $type + ); + + if ( is_null( $type ) ): + unset( $temp['type'] ); + endif; + + array_push( $this->results, $temp ); + + return $temp; + } + +} \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/debian.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/debian.png new file mode 100644 index 0000000..252017a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/debian.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/fedora.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/fedora.png new file mode 100644 index 0000000..13e33d6 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/fedora.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/freebsd.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/freebsd.png new file mode 100644 index 0000000..17cfe53 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/freebsd.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/icon.png new file mode 100644 index 0000000..d287082 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/info.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/info.plist new file mode 100644 index 0000000..a36c867 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/info.plist @@ -0,0 +1,119 @@ + + + + + bundleid + dk.aiyo.VirtualBoxControl + connections + + 86FD7F90-FA0B-4C1C-B13B-346309B0E5D3 + + + destinationuid + 301581C1-995D-4A74-90CD-8B3D929EBF23 + modifiers + 0 + modifiersubtext + + + + + createdby + Jonas Eriksen + description + Control Your VirtualBox VMs From Alfred.app + disabled + + name + VirtualBox v2.0.1 + objects + + + config + + concurrently + + escaping + 62 + script + if [[ ":$PATH:" != *"usr/local/bin"* ]]; then + PATH=$PATH:/usr/local/bin +fi + +VBoxManage {query} + type + 0 + + type + alfred.workflow.action.script + uid + 301581C1-995D-4A74-90CD-8B3D929EBF23 + version + 0 + + + config + + argumenttype + 1 + escaping + 62 + keyword + vm + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + Searching for Virtual Machines... + script + sh virtualbox_control.sh "{query}" + subtext + Start, Stop, Pause, Resume, Reset and more + title + VirtualBox Control + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 86FD7F90-FA0B-4C1C-B13B-346309B0E5D3 + version + 0 + + + readme + Control your VirualBox VMs from Alfred. + +Surported commands are: + - Start + - Power Off + - ACPI Shutdown + - Reset + - Pause / Resume + - Save State + - Take a Screen Shot + uidata + + 301581C1-995D-4A74-90CD-8B3D929EBF23 + + ypos + 10 + + 86FD7F90-FA0B-4C1C-B13B-346309B0E5D3 + + ypos + 10 + + + webaddress + www.aiyo.dk/alfredapp/v2 + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/linux.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/linux.png new file mode 100644 index 0000000..92abc24 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/linux.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/netbsd.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/netbsd.png new file mode 100644 index 0000000..2bac44a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/netbsd.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/openbsd.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/openbsd.png new file mode 100644 index 0000000..f02876a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/openbsd.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/osx.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/osx.png new file mode 100644 index 0000000..e01f904 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/osx.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/redhat.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/redhat.png new file mode 100644 index 0000000..6eb5458 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/redhat.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/suse.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/suse.png new file mode 100644 index 0000000..4ed979c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/suse.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/ubuntu.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/ubuntu.png new file mode 100644 index 0000000..cf7c136 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/ubuntu.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/virtualbox_control.sh b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/virtualbox_control.sh new file mode 100644 index 0000000..9a1bbc5 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/virtualbox_control.sh @@ -0,0 +1,264 @@ +#!/bin/bash + +if [[ ":$PATH:" != *"usr/local/bin"* ]]; then + PATH=$PATH:/usr/local/bin +fi + +function VMicon { + # Choose Icon based on OS type + case "$1" in + Windows*) + echo windows + ;; + "Mac OS X"*) + echo osx + ;; + OpenBSD*) + echo openbsd + ;; + FreeBSD*) + echo freebsd + ;; + NetBSD*) + echo netbsd + ;; + Ubuntu*) + echo ubuntu + ;; + Fedora*) + echo fedora + ;; + "Red Hat"*) + echo redhat + ;; + openSUSE*) + echo suse + ;; + Debian*) + echo debian + ;; + Gentoo*|Mandriva*|Turbulinux*|Xandos*|Oracle*|Linux*) + echo linux + ;; + *) + echo icon + ;; + esac +} + +# Case insensitive compare +shopt -s nocasematch + + +# cache list of vms +let "TIME=$(date +%s)-10" # keep VMs cache in 10 seconds +if [ -z "$1" ] || [ $(stat -f "%m" ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl/vms) -ge $TIME ] + then + # cache the VMs + if [ ! -d ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl/ ] + then + mkdir ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl + fi + VBoxManage list vms -l | sed -n -e '/^Name/N' -e '/\nGroups/P' -e '/\nGuest OS/p' -e '/^Guest OS/P' -e '/^UUID/P' -e '/^State/P' > ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl/vms +fi + +#------------ + +# check if a VM is selected +if [[ $(echo "$1" | grep -c " >" ) -gt 0 ]] + then + # Try to extract VM name from query + NAME=${1%%" >"*} + # try to find VM in cache (only match the full name) + VMINFO=$(grep -A 3 "$NAME$" ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl/vms) + if [[ ! -z "$VMINFO" ]] + then + # get UUID for reference + UUID=$(echo $VMINFO | egrep -o '[0-9abcdef]{8}-[0-9abcdef]{4}-[0-9abcdef]{4}-[0-9abcdef]{4}-[0-9abcdef]{12}') + ICON=$(VMicon "$(echo ${VMINFO#*'Guest OS: '})") + # make sure name is xml valid + NAME=$(printf "$NAME" | sed -e 's/&/&/g') + fi +fi + +# prepare query for fuzzy match +QUERY=$(echo "$1" | sed -e 's/^ *//' -e 's/ *$//' -e 's/ /*\\ /g') + +echo '' +echo '' + +# if $UUID is set then a VM is selected - check if status is 'running' if so then show options for VM +if [ ! -z "$UUID" ] && [ $(echo $VMINFO | egrep -c " running ") -gt 0 ] + then + # the VM is Running + + # remove vm name from query + QUERY="${QUERY#*' >'}" + + # list options available for the VM with fuzzymatch search + if [[ " power off" == $QUERY* ]] + then + # Power Off + echo " Power Off\">" + echo "Power Off" + echo "$ICON.png" + echo "" + fi + if [[ " acpi shutdown" == $QUERY* ]] + then + # ACPI Shutdown + echo " ACPI Shutdown\">" + echo "ACPI Shutdown" + echo "$ICON.png" + echo "" + fi + if [[ " pause" == $QUERY* ]] + then + # Pause + echo " Pause\">" + echo "Pause" + echo "$ICON.png" + echo "" + fi + if [[ " save state" == $QUERY* ]] + then + # Save Machine State + echo " Save State\">" + echo "Save State" + echo "$ICON.png" + echo "" + fi + if [[ " reset" == $QUERY* ]] + then + # Reset + echo " Reset\">" + echo "Reset" + echo "$ICON.png" + echo "" + fi + if [[ " take a screenshot" == $QUERY* ]] + then + # Screen Shot + FILENAME=$(echo "~/Desktop/$NAME - Screen Shot $(date +"%Y-%m-%d at %H.%M.%S").png" | sed -e 's/ /\\ /g' -e 's/&/\\&/g') + echo " Reset\">" + echo "Take a Screenshot" + echo "$ICON.png" + echo "" + fi + # make a Back item. this links back to VM options or list of VMs + if [[ "> " == $QUERY* ]] + then + BACK="" + else + BACK="$NAME > " + fi + echo "" + echo "Back..." + echo "icon.png" + echo "" + +elif [ ! -z "$UUID" ] && [ $(echo $VMINFO | egrep -c " saved ") -gt 0 ] + then + # the VM is in Saved State mode + + # remove vm name from query + QUERY="${QUERY#*' >'}" + + # list options available for the VM with fuzzymatch search + if [[ " Start VM" == $QUERY* ]] + then + # ACPI Shutdown + echo " Start VM\">" + echo "Start VM" + echo "$ICON.png" + echo "" + fi + if [[ " Discard Saved State" == $QUERY* ]] + then + # Pause + echo " Discard Saved State\">" + echo "Discard Saved State" + echo "$ICON.png" + echo "" + fi + # make a Back item. this links back to VM options or list of VMs + if [[ "> " == $QUERY* ]] + then + BACK="" + else + BACK="$NAME > " + fi + echo "" + echo "Back..." + echo "icon.png" + echo "" + +else + # no VM was selected, get VMs and list them + + while read LINE + do + + case "$LINE" in + "Name:"*) + NAME=$(echo $LINE | sed -e 's/^Name: *//' -e 's/&/&/g' -e 's//\>/g') + ;; + "UUID:"*) + UUID=$(echo $LINE | sed -e 's/UUID: *//') + ;; + "Guest OS:"*) + ICON=$(VMicon "$(echo $LINE | sed -e 's/Guest OS: *//')") + ;; + "State:"*) + if [ ! -z "$NAME" ] && [ ! -z "$UUID" ] && [ ! -z "$ICON" ] + then + # fuzzy match query + if [[ " $NAME" == *\ $QUERY* ]] + then + if [[ $(echo $LINE | grep -c "powered off") -gt 0 ]] + then + # VM is not running make a start link + echo "" + echo "$NAME" + echo "Start Virtual Machine" + + elif [[ $(echo $LINE | grep -c "aborted") -gt 0 ]] + then + # VM is aborted make a start link + echo "" + echo "$NAME (Aborted)" + echo "Start Virtual Machine" + + elif [[ $(echo $LINE | grep -c "paused") -gt 0 ]] + then + # VM is paused, make a resume link + echo "" + echo "$NAME (Paused)" + echo "Resume Virtual Machine" + + elif [[ $(echo $LINE | grep -c "saved") -gt 0 ]] + then + # VM is in a saved state, link to list of options + echo " \" valid=\"no\">" + echo "$NAME (Saved State)" + echo "Start or Discard Saved State of Virtual Machine" + + else + # VM is running, link to list of options + echo " \" valid=\"no\">" + echo "$NAME (Running)" + echo "Pause, Save State, Power Off or Reset Virtual Machine" + fi + + echo "$ICON.png" + echo "" + fi + fi + ;; + esac + + done < ~/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\ Data/dk.aiyo.VirtualBoxControl/vms +fi + +echo '' +shopt -u nocasematch diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/windows.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/windows.png new file mode 100644 index 0000000..26a54be Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.1A99AD16-525C-4794-9A30-62FE498BF5EB/windows.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/05F86AA1-D3EE-4409-9A58-898B36FFE503.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/05F86AA1-D3EE-4409-9A58-898B36FFE503.png new file mode 100644 index 0000000..d6f8523 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/05F86AA1-D3EE-4409-9A58-898B36FFE503.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C.png new file mode 100644 index 0000000..63eed98 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0B75CF43-8B04-405F-86C3-2FFC59AC4A70.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0B75CF43-8B04-405F-86C3-2FFC59AC4A70.png new file mode 100644 index 0000000..0d78bbb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0B75CF43-8B04-405F-86C3-2FFC59AC4A70.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0EBF4C61-5630-4629-8B4F-AD91D3470760.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0EBF4C61-5630-4629-8B4F-AD91D3470760.png new file mode 100644 index 0000000..7d17eda Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/0EBF4C61-5630-4629-8B4F-AD91D3470760.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/11E4CA98-E51E-45E4-91ED-72B4A1A34283.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/11E4CA98-E51E-45E4-91ED-72B4A1A34283.png new file mode 100644 index 0000000..aea89fe Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/11E4CA98-E51E-45E4-91ED-72B4A1A34283.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15209065-AB33-44E4-ADFC-BAFC5033762E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15209065-AB33-44E4-ADFC-BAFC5033762E.png new file mode 100644 index 0000000..6861793 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15209065-AB33-44E4-ADFC-BAFC5033762E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2.png new file mode 100644 index 0000000..63a0b93 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/16F5C3BF-01EE-493C-9E7B-CC54D482B7A6.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/16F5C3BF-01EE-493C-9E7B-CC54D482B7A6.png new file mode 100644 index 0000000..3e4de88 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/16F5C3BF-01EE-493C-9E7B-CC54D482B7A6.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1BA522F3-B2D0-4F36-B86C-738FB3AC55DD.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1BA522F3-B2D0-4F36-B86C-738FB3AC55DD.png new file mode 100644 index 0000000..d0d0f29 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1BA522F3-B2D0-4F36-B86C-738FB3AC55DD.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0.png new file mode 100644 index 0000000..d08e6ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C6211-1DD0-4CE6-8082-37957F15CC1D.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C6211-1DD0-4CE6-8082-37957F15CC1D.png new file mode 100644 index 0000000..8687dc7 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C6211-1DD0-4CE6-8082-37957F15CC1D.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C8466-4AED-4272-9C10-50F3BCE88043.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C8466-4AED-4272-9C10-50F3BCE88043.png new file mode 100644 index 0000000..e49f202 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2B0C8466-4AED-4272-9C10-50F3BCE88043.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2F1F6369-46C0-483B-816F-3796168AE060.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2F1F6369-46C0-483B-816F-3796168AE060.png new file mode 100644 index 0000000..74d84ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2F1F6369-46C0-483B-816F-3796168AE060.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2FC567E2-E6C5-4A91-B42E-1996532B78C9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2FC567E2-E6C5-4A91-B42E-1996532B78C9.png new file mode 100644 index 0000000..675a438 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/2FC567E2-E6C5-4A91-B42E-1996532B78C9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/303A65BF-8E81-48E8-AA28-E1CA408FDD53.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/303A65BF-8E81-48E8-AA28-E1CA408FDD53.png new file mode 100644 index 0000000..80e21d2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/303A65BF-8E81-48E8-AA28-E1CA408FDD53.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3040749D-6B5C-4CCD-AF95-AEC0F83B48D9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3040749D-6B5C-4CCD-AF95-AEC0F83B48D9.png new file mode 100644 index 0000000..ea61178 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3040749D-6B5C-4CCD-AF95-AEC0F83B48D9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3617F927-558D-4F30-B8D1-B7789F863AB0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3617F927-558D-4F30-B8D1-B7789F863AB0.png new file mode 100644 index 0000000..603c807 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3617F927-558D-4F30-B8D1-B7789F863AB0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/39A1935A-37F5-49FA-A860-BCF7765A8C65.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/39A1935A-37F5-49FA-A860-BCF7765A8C65.png new file mode 100644 index 0000000..bba88bc Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/39A1935A-37F5-49FA-A860-BCF7765A8C65.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3F85747B-FC44-4B07-AA6E-3645F0CC0DF7.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3F85747B-FC44-4B07-AA6E-3645F0CC0DF7.png new file mode 100644 index 0000000..1e4086b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/3F85747B-FC44-4B07-AA6E-3645F0CC0DF7.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/450AEF8B-BDAA-409C-A0D4-68769545FBCF.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/450AEF8B-BDAA-409C-A0D4-68769545FBCF.png new file mode 100644 index 0000000..91da880 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/450AEF8B-BDAA-409C-A0D4-68769545FBCF.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/455BDE70-BCF4-447F-ABFF-C25D8E5B08B6.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/455BDE70-BCF4-447F-ABFF-C25D8E5B08B6.png new file mode 100644 index 0000000..605f0b4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/455BDE70-BCF4-447F-ABFF-C25D8E5B08B6.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4BE9FB30-9B4F-4E44-861D-D178507A7568.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4BE9FB30-9B4F-4E44-861D-D178507A7568.png new file mode 100644 index 0000000..2b5911a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4BE9FB30-9B4F-4E44-861D-D178507A7568.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4EB5FB5E-6472-4757-A479-B206B6080036.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4EB5FB5E-6472-4757-A479-B206B6080036.png new file mode 100644 index 0000000..434f34e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/4EB5FB5E-6472-4757-A479-B206B6080036.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/552D77E3-1550-4035-AB49-8B708B081EC9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/552D77E3-1550-4035-AB49-8B708B081EC9.png new file mode 100644 index 0000000..c0db352 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/552D77E3-1550-4035-AB49-8B708B081EC9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5AF7EEEC-2E55-482C-8750-4CE6AD752683.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5AF7EEEC-2E55-482C-8750-4CE6AD752683.png new file mode 100644 index 0000000..2d3711b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5AF7EEEC-2E55-482C-8750-4CE6AD752683.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2.png new file mode 100644 index 0000000..2d3711b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5EB4A672-01BC-4DBB-AD39-60EBB0F79A67.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5EB4A672-01BC-4DBB-AD39-60EBB0F79A67.png new file mode 100644 index 0000000..1e4086b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/5EB4A672-01BC-4DBB-AD39-60EBB0F79A67.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/62AA861E-C910-4354-84C9-58A5660365D8.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/62AA861E-C910-4354-84C9-58A5660365D8.png new file mode 100644 index 0000000..2b5911a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/62AA861E-C910-4354-84C9-58A5660365D8.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/66F8A022-163E-42CB-A9E9-B32E8158ACA7.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/66F8A022-163E-42CB-A9E9-B32E8158ACA7.png new file mode 100644 index 0000000..2695cec Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/66F8A022-163E-42CB-A9E9-B32E8158ACA7.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/6E9B4F21-F907-4A22-8689-9A146F909454.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/6E9B4F21-F907-4A22-8689-9A146F909454.png new file mode 100644 index 0000000..63eed98 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/6E9B4F21-F907-4A22-8689-9A146F909454.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A.png new file mode 100644 index 0000000..3820728 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/794A76A7-BB98-4A83-92BE-386A56875120.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/794A76A7-BB98-4A83-92BE-386A56875120.png new file mode 100644 index 0000000..9bfd1db Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/794A76A7-BB98-4A83-92BE-386A56875120.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/79F70A28-E2D9-4705-81A9-86F3EA8EB47F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/79F70A28-E2D9-4705-81A9-86F3EA8EB47F.png new file mode 100644 index 0000000..3689e62 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/79F70A28-E2D9-4705-81A9-86F3EA8EB47F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FE5D993-C14D-4B94-9479-B361680F1C40.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FE5D993-C14D-4B94-9479-B361680F1C40.png new file mode 100644 index 0000000..c669028 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FE5D993-C14D-4B94-9479-B361680F1C40.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FF09231-F068-4EA0-8537-6C1EB608CA5A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FF09231-F068-4EA0-8537-6C1EB608CA5A.png new file mode 100644 index 0000000..66a24a4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/7FF09231-F068-4EA0-8537-6C1EB608CA5A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/804D8959-D2AE-453E-BBC1-3C11B275597B.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/804D8959-D2AE-453E-BBC1-3C11B275597B.png new file mode 100644 index 0000000..06fe87a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/804D8959-D2AE-453E-BBC1-3C11B275597B.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/81BA0BC2-F1CB-46DC-A715-C38A1A0E055E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/81BA0BC2-F1CB-46DC-A715-C38A1A0E055E.png new file mode 100644 index 0000000..9db7327 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/81BA0BC2-F1CB-46DC-A715-C38A1A0E055E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8339BE15-274E-4A77-A6A0-CEDF30EFD0E5.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8339BE15-274E-4A77-A6A0-CEDF30EFD0E5.png new file mode 100644 index 0000000..434f34e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8339BE15-274E-4A77-A6A0-CEDF30EFD0E5.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8598A5C9-72B6-4CEF-A498-D6C2ED06DC88.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8598A5C9-72B6-4CEF-A498-D6C2ED06DC88.png new file mode 100644 index 0000000..605f0b4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8598A5C9-72B6-4CEF-A498-D6C2ED06DC88.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/873EF61A-BD03-4946-87B0-C7AE5DFC5E5B.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/873EF61A-BD03-4946-87B0-C7AE5DFC5E5B.png new file mode 100644 index 0000000..f661507 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/873EF61A-BD03-4946-87B0-C7AE5DFC5E5B.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/89BC46B4-E178-4855-8863-393730814F6E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/89BC46B4-E178-4855-8863-393730814F6E.png new file mode 100644 index 0000000..9db7327 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/89BC46B4-E178-4855-8863-393730814F6E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8C78472B-13EB-4512-B94D-4BF92867CD92.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8C78472B-13EB-4512-B94D-4BF92867CD92.png new file mode 100644 index 0000000..29559d4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8C78472B-13EB-4512-B94D-4BF92867CD92.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5.png new file mode 100644 index 0000000..66a24a4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F478980-199B-45B5-AD41-EBA185446705.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F478980-199B-45B5-AD41-EBA185446705.png new file mode 100644 index 0000000..9bfd1db Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F478980-199B-45B5-AD41-EBA185446705.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4.png new file mode 100644 index 0000000..3e4de88 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9661EF24-91C3-44A1-9066-8E9B9817841D.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9661EF24-91C3-44A1-9066-8E9B9817841D.png new file mode 100644 index 0000000..0d78bbb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9661EF24-91C3-44A1-9066-8E9B9817841D.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9B2621F0-0190-4ABD-A09F-3DBF85548580.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9B2621F0-0190-4ABD-A09F-3DBF85548580.png new file mode 100644 index 0000000..27ae603 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9B2621F0-0190-4ABD-A09F-3DBF85548580.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9E3FE06C-F5F8-41F3-A70F-B92E187EED75.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9E3FE06C-F5F8-41F3-A70F-B92E187EED75.png new file mode 100644 index 0000000..2be4de3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/9E3FE06C-F5F8-41F3-A70F-B92E187EED75.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0EAB8B1-F034-490F-9534-44ADF572AF4E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0EAB8B1-F034-490F-9534-44ADF572AF4E.png new file mode 100644 index 0000000..a98f19a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0EAB8B1-F034-490F-9534-44ADF572AF4E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90.png new file mode 100644 index 0000000..3689e62 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A38DD404-DE03-42C2-B0CB-A37891B6F24D.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A38DD404-DE03-42C2-B0CB-A37891B6F24D.png new file mode 100644 index 0000000..71a0d5c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A38DD404-DE03-42C2-B0CB-A37891B6F24D.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A41190FA-4B23-4908-A4B7-16A14F338C11.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A41190FA-4B23-4908-A4B7-16A14F338C11.png new file mode 100644 index 0000000..74d84ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A41190FA-4B23-4908-A4B7-16A14F338C11.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A76C26BD-BA48-4797-839B-BE439FF40846.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A76C26BD-BA48-4797-839B-BE439FF40846.png new file mode 100644 index 0000000..1f5b4f2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A76C26BD-BA48-4797-839B-BE439FF40846.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A8BE6109-BCC0-4A41-9375-C1D2E3A755BD.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A8BE6109-BCC0-4A41-9375-C1D2E3A755BD.png new file mode 100644 index 0000000..63a0b93 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/A8BE6109-BCC0-4A41-9375-C1D2E3A755BD.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/AC236315-8CDE-41E3-A9BA-BB59D292FE14.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/AC236315-8CDE-41E3-A9BA-BB59D292FE14.png new file mode 100644 index 0000000..88ab394 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/AC236315-8CDE-41E3-A9BA-BB59D292FE14.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Info.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Info.plist new file mode 100644 index 0000000..8b7fecc --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Info.plist @@ -0,0 +1,41 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Spotify Mini Player + CFBundleIconFile + appIcon.icns + CFBundleIdentifier + com.spotify.miniplayer.green + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Spotify Mini Player + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSMinimumSystemVersion + 10.7.0 + LSUIElement + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSHumanReadableCopyright + © 2017 vdesabou + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/MacOS/Spotify Mini Player b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/MacOS/Spotify Mini Player new file mode 100755 index 0000000..c2247cf Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/MacOS/Spotify Mini Player differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/AppSettings.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/AppSettings.plist new file mode 100644 index 0000000..e19e1c1 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/AppSettings.plist @@ -0,0 +1,47 @@ + + + + + AcceptsFiles + + AcceptsText + + Authentication + + Creator + Platypus-5.1 + Droppable + + Interpreter + /bin/sh + InterpreterArgs + + Output + None + PromptForFileOnLaunch + + RemainRunning + + ScriptArgs + + Secure + + Suffixes + + TextBackground + #ffffff + TextEncoding + 4 + TextFont + Monaco + TextForeground + #000000 + TextSize + 13 + UniformTypes + + public.item + public.folder + + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/MainMenu.nib/keyedobjects.nib b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000..661250b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/MainMenu.nib/keyedobjects.nib differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/appIcon.icns b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/appIcon.icns new file mode 100644 index 0000000..7a8041a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/appIcon.icns differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/script b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/script new file mode 100755 index 0000000..7efb52d --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/App/green/Spotify Mini Player.app/Contents/Resources/script @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "" \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B23712E3-4564-4668-BD6D-4D535839CC8C.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B23712E3-4564-4668-BD6D-4D535839CC8C.png new file mode 100644 index 0000000..a98f19a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B23712E3-4564-4668-BD6D-4D535839CC8C.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B77F5F98-C065-49A4-BBB1-68ADADDD8E7D.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B77F5F98-C065-49A4-BBB1-68ADADDD8E7D.png new file mode 100644 index 0000000..675a438 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B77F5F98-C065-49A4-BBB1-68ADADDD8E7D.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F.png new file mode 100644 index 0000000..a9c7d11 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BA289B3E-779E-482F-AFEA-8E1395513365.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BA289B3E-779E-482F-AFEA-8E1395513365.png new file mode 100644 index 0000000..69acd90 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BA289B3E-779E-482F-AFEA-8E1395513365.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BC488027-E76B-43A7-B414-C7FAA9CF9995.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BC488027-E76B-43A7-B414-C7FAA9CF9995.png new file mode 100644 index 0000000..29559d4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BC488027-E76B-43A7-B414-C7FAA9CF9995.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BD255BDB-07A5-4EE9-858F-A58C6207D191.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BD255BDB-07A5-4EE9-858F-A58C6207D191.png new file mode 100644 index 0000000..cb2fe21 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/BD255BDB-07A5-4EE9-858F-A58C6207D191.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C10A975C-0DAE-4A45-AEAB-4E07CF125703.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C10A975C-0DAE-4A45-AEAB-4E07CF125703.png new file mode 100644 index 0000000..71701c0 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C10A975C-0DAE-4A45-AEAB-4E07CF125703.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C323BECC-0183-4562-B817-65624E13B3F3.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C323BECC-0183-4562-B817-65624E13B3F3.png new file mode 100644 index 0000000..7d17eda Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C323BECC-0183-4562-B817-65624E13B3F3.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C588A188-D8D3-450F-9020-5EBB563F6B8A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C588A188-D8D3-450F-9020-5EBB563F6B8A.png new file mode 100644 index 0000000..e49f202 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C588A188-D8D3-450F-9020-5EBB563F6B8A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C7CFF014-DBC8-4663-A0AB-219C57A427EE.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C7CFF014-DBC8-4663-A0AB-219C57A427EE.png new file mode 100644 index 0000000..8687dc7 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C7CFF014-DBC8-4663-A0AB-219C57A427EE.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C93B7A2B-9105-4456-997A-1BCC4EDA5A27.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C93B7A2B-9105-4456-997A-1BCC4EDA5A27.png new file mode 100644 index 0000000..71701c0 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/C93B7A2B-9105-4456-997A-1BCC4EDA5A27.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CD9D3654-8137-49B2-80DC-095E97A58E67.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CD9D3654-8137-49B2-80DC-095E97A58E67.png new file mode 100644 index 0000000..2695cec Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CD9D3654-8137-49B2-80DC-095E97A58E67.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CE28CBC8-93FD-4B21-8488-28CBC5A3E63B.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CE28CBC8-93FD-4B21-8488-28CBC5A3E63B.png new file mode 100644 index 0000000..45413e1 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CE28CBC8-93FD-4B21-8488-28CBC5A3E63B.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CEF36AB9-7CC2-4765-BF84-751E88B69023.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CEF36AB9-7CC2-4765-BF84-751E88B69023.png new file mode 100644 index 0000000..f661507 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/CEF36AB9-7CC2-4765-BF84-751E88B69023.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D31A5001-4590-418E-9AB0-6183E75E59DE.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D31A5001-4590-418E-9AB0-6183E75E59DE.png new file mode 100644 index 0000000..27ae603 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D31A5001-4590-418E-9AB0-6183E75E59DE.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D4442911-E17B-49CC-8F7F-EAC1830B11CD.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D4442911-E17B-49CC-8F7F-EAC1830B11CD.png new file mode 100644 index 0000000..d0d0f29 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D4442911-E17B-49CC-8F7F-EAC1830B11CD.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D8C53798-B7E2-4A51-AC12-37FEBDB624E0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D8C53798-B7E2-4A51-AC12-37FEBDB624E0.png new file mode 100644 index 0000000..c0db352 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D8C53798-B7E2-4A51-AC12-37FEBDB624E0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D931B685-B5F8-4BBC-9FCB-D78F9FA0AB66.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D931B685-B5F8-4BBC-9FCB-D78F9FA0AB66.png new file mode 100644 index 0000000..d0d0f29 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/D931B685-B5F8-4BBC-9FCB-D78F9FA0AB66.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DA2F787C-11F7-4C7A-B275-A4CFFE171012.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DA2F787C-11F7-4C7A-B275-A4CFFE171012.png new file mode 100644 index 0000000..06fe87a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DA2F787C-11F7-4C7A-B275-A4CFFE171012.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC403223-17FA-466B-9488-7292DA9D8223.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC403223-17FA-466B-9488-7292DA9D8223.png new file mode 100644 index 0000000..71a0d5c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC403223-17FA-466B-9488-7292DA9D8223.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC678CF5-D8B2-4508-A2FA-CB0F0E253108.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC678CF5-D8B2-4508-A2FA-CB0F0E253108.png new file mode 100644 index 0000000..836e471 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DC678CF5-D8B2-4508-A2FA-CB0F0E253108.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DD0755A4-3C70-467C-A005-11F10E23CEF0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DD0755A4-3C70-467C-A005-11F10E23CEF0.png new file mode 100644 index 0000000..5ed26f5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/DD0755A4-3C70-467C-A005-11F10E23CEF0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E45DF42A-58A9-4069-A410-EC2BBC8A0575.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E45DF42A-58A9-4069-A410-EC2BBC8A0575.png new file mode 100644 index 0000000..3c8e44a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E45DF42A-58A9-4069-A410-EC2BBC8A0575.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A.png new file mode 100644 index 0000000..7d17eda Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E6CEF7D4-CFA9-4608-A188-65B33A602BAF.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E6CEF7D4-CFA9-4608-A188-65B33A602BAF.png new file mode 100644 index 0000000..aea89fe Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/E6CEF7D4-CFA9-4608-A188-65B33A602BAF.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EA03C1F5-912A-4422-B766-2BBC94DC0344.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EA03C1F5-912A-4422-B766-2BBC94DC0344.png new file mode 100644 index 0000000..2be4de3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EA03C1F5-912A-4422-B766-2BBC94DC0344.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E.png new file mode 100644 index 0000000..3689e62 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EF574432-0896-4A92-9944-7DA5DD7295DA.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EF574432-0896-4A92-9944-7DA5DD7295DA.png new file mode 100644 index 0000000..63e68c6 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/EF574432-0896-4A92-9944-7DA5DD7295DA.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F0ED23FA-8524-4769-B610-828611958D6A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F0ED23FA-8524-4769-B610-828611958D6A.png new file mode 100644 index 0000000..d3f8cb5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F0ED23FA-8524-4769-B610-828611958D6A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F250A59C-0B2D-4A08-9085-9CA0A2FB2DCC.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F250A59C-0B2D-4A08-9085-9CA0A2FB2DCC.png new file mode 100644 index 0000000..d0d0f29 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F250A59C-0B2D-4A08-9085-9CA0A2FB2DCC.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4382654-9318-4849-82E4-550AC235148C.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4382654-9318-4849-82E4-550AC235148C.png new file mode 100644 index 0000000..1f5b4f2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4382654-9318-4849-82E4-550AC235148C.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4F5AC18-3C04-4673-9CC3-E563094C9446.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4F5AC18-3C04-4673-9CC3-E563094C9446.png new file mode 100644 index 0000000..c669028 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/F4F5AC18-3C04-4673-9CC3-E563094C9446.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/FAA5FC99-7909-45B6-9BF0-7601DBAADC4F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/FAA5FC99-7909-45B6-9BF0-7601DBAADC4F.png new file mode 100644 index 0000000..e9156c6 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/FAA5FC99-7909-45B6-9BF0-7601DBAADC4F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_ALERTER.md b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_ALERTER.md new file mode 100644 index 0000000..c7b57a4 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_ALERTER.md @@ -0,0 +1,9 @@ +All the works are available under the MIT license. + +Copyright (C) 2012-2015 Valère Jeantet valere.jeantet@gmail.com, Eloy Durán eloy.de.enige@gmail.com, Julien Blanchard julien@sideburns.eu + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_TERMINAL_SHARE.md b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_TERMINAL_SHARE.md new file mode 100644 index 0000000..2aa361f --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/LICENSE_TERMINAL_SHARE.md @@ -0,0 +1,19 @@ +Copyright (c) 2012 Mattt Thompson (http://mattt.me/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/078886c96323cf8fa4dc08c047f730f210d436c3.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/078886c96323cf8fa4dc08c047f730f210d436c3.png new file mode 100644 index 0000000..b853a0b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/078886c96323cf8fa4dc08c047f730f210d436c3.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/0ff3394be61c7c822d06e3228c89add5b462084f.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/0ff3394be61c7c822d06e3228c89add5b462084f.png new file mode 100644 index 0000000..eddbcd1 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/0ff3394be61c7c822d06e3228c89add5b462084f.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/17ebacf9fa9a2526eed6e79be7619d1a296f5c07.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/17ebacf9fa9a2526eed6e79be7619d1a296f5c07.png new file mode 100644 index 0000000..5d3ac68 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/17ebacf9fa9a2526eed6e79be7619d1a296f5c07.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/23dbf40eac5c981b0171d90427f6ba54b71239e0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/23dbf40eac5c981b0171d90427f6ba54b71239e0.png new file mode 100644 index 0000000..e8cc844 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/23dbf40eac5c981b0171d90427f6ba54b71239e0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/33a76cda76a24b29c08fa6a30b306f8d18842a69.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/33a76cda76a24b29c08fa6a30b306f8d18842a69.png new file mode 100644 index 0000000..68475f8 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/33a76cda76a24b29c08fa6a30b306f8d18842a69.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/416366eee910711e509f9c7381a14729a4fec214.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/416366eee910711e509f9c7381a14729a4fec214.png new file mode 100644 index 0000000..5481158 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/416366eee910711e509f9c7381a14729a4fec214.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/5438218af54404741e979e30029dffc8cfa027e0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/5438218af54404741e979e30029dffc8cfa027e0.png new file mode 100644 index 0000000..4b9762a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/5438218af54404741e979e30029dffc8cfa027e0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/616d2b26fc250b4bcbabb45fab72267d90b86d5b.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/616d2b26fc250b4bcbabb45fab72267d90b86d5b.png new file mode 100644 index 0000000..e157152 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/616d2b26fc250b4bcbabb45fab72267d90b86d5b.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/7f73299e44208b1bf3ea24353e08897cc883f3fb.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/7f73299e44208b1bf3ea24353e08897cc883f3fb.png new file mode 100644 index 0000000..3673706 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/7f73299e44208b1bf3ea24353e08897cc883f3fb.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/82859060e592ee7da3bc7067150201773fdcfdda.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/82859060e592ee7da3bc7067150201773fdcfdda.png new file mode 100644 index 0000000..56cc4dc Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/82859060e592ee7da3bc7067150201773fdcfdda.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/89d65b3654007d57567c65b8369feec3a867ab18.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/89d65b3654007d57567c65b8369feec3a867ab18.png new file mode 100644 index 0000000..612f58e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/89d65b3654007d57567c65b8369feec3a867ab18.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/afb9b5f72d45346d3a11ab99023d14d3dde3eea0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/afb9b5f72d45346d3a11ab99023d14d3dde3eea0.png new file mode 100644 index 0000000..b5073f3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/afb9b5f72d45346d3a11ab99023d14d3dde3eea0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/d1502fd6b51fa78e31bd5061b9f0c368b504c617.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/d1502fd6b51fa78e31bd5061b9f0c368b504c617.png new file mode 100644 index 0000000..12af672 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/List Filter Images/d1502fd6b51fa78e31bd5061b9f0c368b504c617.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/15D6EBE2-6D82-4F2C-A4B3-5949424B4EF9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/15D6EBE2-6D82-4F2C-A4B3-5949424B4EF9.png new file mode 100644 index 0000000..e9156c6 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/15D6EBE2-6D82-4F2C-A4B3-5949424B4EF9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/163265DD-5CAB-4D11-B984-F86871709AEE.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/163265DD-5CAB-4D11-B984-F86871709AEE.png new file mode 100644 index 0000000..bba88bc Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/163265DD-5CAB-4D11-B984-F86871709AEE.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/19E641F3-FE15-4058-9597-255FDDAA4F48.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/19E641F3-FE15-4058-9597-255FDDAA4F48.png new file mode 100644 index 0000000..5ed26f5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/19E641F3-FE15-4058-9597-255FDDAA4F48.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2375184C-CC97-4763-A846-D2FAB1259FD1.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2375184C-CC97-4763-A846-D2FAB1259FD1.png new file mode 100644 index 0000000..27ae603 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2375184C-CC97-4763-A846-D2FAB1259FD1.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/26215986-3B9E-4491-A93B-67878CE04EB5.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/26215986-3B9E-4491-A93B-67878CE04EB5.png new file mode 100644 index 0000000..aea89fe Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/26215986-3B9E-4491-A93B-67878CE04EB5.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2737969D-A8B4-4550-8568-3C926D36DD81.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2737969D-A8B4-4550-8568-3C926D36DD81.png new file mode 100644 index 0000000..1e4086b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/2737969D-A8B4-4550-8568-3C926D36DD81.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/27BDEB50-2E71-474D-B329-30EBFB7BC663.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/27BDEB50-2E71-474D-B329-30EBFB7BC663.png new file mode 100644 index 0000000..0d78bbb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/27BDEB50-2E71-474D-B329-30EBFB7BC663.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/28180F27-0728-414D-88F3-76E99A58FA7D.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/28180F27-0728-414D-88F3-76E99A58FA7D.png new file mode 100644 index 0000000..a9c7d11 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/28180F27-0728-414D-88F3-76E99A58FA7D.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/3690378D-02F4-4BF9-BC91-975F3739542B.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/3690378D-02F4-4BF9-BC91-975F3739542B.png new file mode 100644 index 0000000..29559d4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/3690378D-02F4-4BF9-BC91-975F3739542B.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/41AECA11-8410-4CFF-8BAB-51FE6DE283F4.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/41AECA11-8410-4CFF-8BAB-51FE6DE283F4.png new file mode 100644 index 0000000..2be4de3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/41AECA11-8410-4CFF-8BAB-51FE6DE283F4.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4368A343-21A8-44C7-96F9-4870FA1C2EFB.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4368A343-21A8-44C7-96F9-4870FA1C2EFB.png new file mode 100644 index 0000000..2695cec Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4368A343-21A8-44C7-96F9-4870FA1C2EFB.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4FE5620A-FB79-440E-8633-B8148EE1191E.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4FE5620A-FB79-440E-8633-B8148EE1191E.png new file mode 100644 index 0000000..c669028 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/4FE5620A-FB79-440E-8633-B8148EE1191E.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5365AF85-EDB1-4789-9ABD-B272A8C96AA0.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5365AF85-EDB1-4789-9ABD-B272A8C96AA0.png new file mode 100644 index 0000000..66a24a4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5365AF85-EDB1-4789-9ABD-B272A8C96AA0.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/569B0F42-A04A-40B7-9E86-EA1C61EF0AE5.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/569B0F42-A04A-40B7-9E86-EA1C61EF0AE5.png new file mode 100644 index 0000000..603c807 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/569B0F42-A04A-40B7-9E86-EA1C61EF0AE5.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/577A4640-8D94-4813-9223-B355BE7FE1BD.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/577A4640-8D94-4813-9223-B355BE7FE1BD.png new file mode 100644 index 0000000..9db7327 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/577A4640-8D94-4813-9223-B355BE7FE1BD.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/58AF0E83-EC70-42B2-AED5-DB7DF65C043C.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/58AF0E83-EC70-42B2-AED5-DB7DF65C043C.png new file mode 100644 index 0000000..71a0d5c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/58AF0E83-EC70-42B2-AED5-DB7DF65C043C.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5C18A3F0-C5CC-4B8D-B71E-B00B420CA2DC.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5C18A3F0-C5CC-4B8D-B71E-B00B420CA2DC.png new file mode 100644 index 0000000..d08e6ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/5C18A3F0-C5CC-4B8D-B71E-B00B420CA2DC.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/6D35BFAD-C96C-4BF8-B76B-5C4BB4313DF9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/6D35BFAD-C96C-4BF8-B76B-5C4BB4313DF9.png new file mode 100644 index 0000000..80e21d2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/6D35BFAD-C96C-4BF8-B76B-5C4BB4313DF9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/707403B7-FF4A-4995-99F3-AB2B5F39B34F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/707403B7-FF4A-4995-99F3-AB2B5F39B34F.png new file mode 100644 index 0000000..f661507 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/707403B7-FF4A-4995-99F3-AB2B5F39B34F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/749D3ABB-38FB-4EFB-9E3D-881C5AF5CAC9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/749D3ABB-38FB-4EFB-9E3D-881C5AF5CAC9.png new file mode 100644 index 0000000..434f34e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/749D3ABB-38FB-4EFB-9E3D-881C5AF5CAC9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83D8A06D-1B1C-4B90-A00A-5B5E575DF7E8.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83D8A06D-1B1C-4B90-A00A-5B5E575DF7E8.png new file mode 100644 index 0000000..605f0b4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83D8A06D-1B1C-4B90-A00A-5B5E575DF7E8.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83F461DC-A47F-4407-92C3-BF269BB49953.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83F461DC-A47F-4407-92C3-BF269BB49953.png new file mode 100644 index 0000000..a98f19a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/83F461DC-A47F-4407-92C3-BF269BB49953.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/89CD46BC-7C18-4D85-A23B-CF5F93273B1A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/89CD46BC-7C18-4D85-A23B-CF5F93273B1A.png new file mode 100644 index 0000000..91da880 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/89CD46BC-7C18-4D85-A23B-CF5F93273B1A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/8B60A0B6-910F-4B63-A0B1-953D9A99990F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/8B60A0B6-910F-4B63-A0B1-953D9A99990F.png new file mode 100644 index 0000000..88ab394 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/8B60A0B6-910F-4B63-A0B1-953D9A99990F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9045D879-6632-4113-9915-85534EBECBB1.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9045D879-6632-4113-9915-85534EBECBB1.png new file mode 100644 index 0000000..836e471 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9045D879-6632-4113-9915-85534EBECBB1.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/924A7250-A8D3-4944-BDEF-74B3DD32DC75.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/924A7250-A8D3-4944-BDEF-74B3DD32DC75.png new file mode 100644 index 0000000..d0d0f29 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/924A7250-A8D3-4944-BDEF-74B3DD32DC75.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9B2EBB97-E54C-420E-BB2E-20AC87764C68.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9B2EBB97-E54C-420E-BB2E-20AC87764C68.png new file mode 100644 index 0000000..74d84ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/9B2EBB97-E54C-420E-BB2E-20AC87764C68.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/A6374417-A3FC-4360-9913-504F7A21F4F1.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/A6374417-A3FC-4360-9913-504F7A21F4F1.png new file mode 100644 index 0000000..71701c0 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/A6374417-A3FC-4360-9913-504F7A21F4F1.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AE944AAF-0B18-436F-AB21-1B22AA446063.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AE944AAF-0B18-436F-AB21-1B22AA446063.png new file mode 100644 index 0000000..69acd90 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AE944AAF-0B18-436F-AB21-1B22AA446063.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AEC59638-4779-4470-9A6A-E32992498ED2.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AEC59638-4779-4470-9A6A-E32992498ED2.png new file mode 100644 index 0000000..1f5b4f2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AEC59638-4779-4470-9A6A-E32992498ED2.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AF86DFA1-E6C7-4C2B-BD00-66614B6CFE81.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AF86DFA1-E6C7-4C2B-BD00-66614B6CFE81.png new file mode 100644 index 0000000..e49f202 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/AF86DFA1-E6C7-4C2B-BD00-66614B6CFE81.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/C5B9A789-80F3-41BA-9A46-C34DD4CDE050.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/C5B9A789-80F3-41BA-9A46-C34DD4CDE050.png new file mode 100644 index 0000000..7d17eda Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/C5B9A789-80F3-41BA-9A46-C34DD4CDE050.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CC39269A-4977-48A1-8427-F9CFC2AE8EED.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CC39269A-4977-48A1-8427-F9CFC2AE8EED.png new file mode 100644 index 0000000..2d3711b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CC39269A-4977-48A1-8427-F9CFC2AE8EED.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CED135C7-B958-4C68-8C47-956FBAA9086A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CED135C7-B958-4C68-8C47-956FBAA9086A.png new file mode 100644 index 0000000..2b5911a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/CED135C7-B958-4C68-8C47-956FBAA9086A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D191C6F2-CF3A-4F3A-AEDB-9D8B03EA7EC9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D191C6F2-CF3A-4F3A-AEDB-9D8B03EA7EC9.png new file mode 100644 index 0000000..675a438 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D191C6F2-CF3A-4F3A-AEDB-9D8B03EA7EC9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D427D63A-3C3A-420D-87D5-46185FE361E3.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D427D63A-3C3A-420D-87D5-46185FE361E3.png new file mode 100644 index 0000000..c0db352 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D427D63A-3C3A-420D-87D5-46185FE361E3.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D51D9C70-68AF-4D63-ABD0-09906D9B1EC9.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D51D9C70-68AF-4D63-ABD0-09906D9B1EC9.png new file mode 100644 index 0000000..3e4de88 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/D51D9C70-68AF-4D63-ABD0-09906D9B1EC9.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/DF3FC215-4E94-472D-91B2-9D94A3B8632F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/DF3FC215-4E94-472D-91B2-9D94A3B8632F.png new file mode 100644 index 0000000..3820728 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/DF3FC215-4E94-472D-91B2-9D94A3B8632F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E7ECAC10-DDC2-4860-A342-A876756D8812.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E7ECAC10-DDC2-4860-A342-A876756D8812.png new file mode 100644 index 0000000..63eed98 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E7ECAC10-DDC2-4860-A342-A876756D8812.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E8BE74B6-2928-4513-A0BC-B88EBF839ABD.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E8BE74B6-2928-4513-A0BC-B88EBF839ABD.png new file mode 100644 index 0000000..8687dc7 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E8BE74B6-2928-4513-A0BC-B88EBF839ABD.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E9C9194B-AF5F-4BAD-88AB-DB7AFED380BF.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E9C9194B-AF5F-4BAD-88AB-DB7AFED380BF.png new file mode 100644 index 0000000..d3f8cb5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/E9C9194B-AF5F-4BAD-88AB-DB7AFED380BF.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EA114C5E-A6A7-479E-BDB8-17E9C3163B53.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EA114C5E-A6A7-479E-BDB8-17E9C3163B53.png new file mode 100644 index 0000000..ea61178 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EA114C5E-A6A7-479E-BDB8-17E9C3163B53.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EE84BB33-1412-4F21-8B4D-D09362ECFE7A.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EE84BB33-1412-4F21-8B4D-D09362ECFE7A.png new file mode 100644 index 0000000..63a0b93 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/EE84BB33-1412-4F21-8B4D-D09362ECFE7A.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/F14D664A-48D5-4232-A6CD-772F3361630B.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/F14D664A-48D5-4232-A6CD-772F3361630B.png new file mode 100644 index 0000000..3c8e44a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/F14D664A-48D5-4232-A6CD-772F3361630B.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/FDAEECD4-DE40-443C-89F9-B46D5592D8C4.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/FDAEECD4-DE40-443C-89F9-B46D5592D8C4.png new file mode 100644 index 0000000..9bfd1db Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/items/FDAEECD4-DE40-443C-89F9-B46D5592D8C4.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/31BE3663-05A1-4380-9955-ECBD4E1AD618.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/31BE3663-05A1-4380-9955-ECBD4E1AD618.png new file mode 100644 index 0000000..434f34e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/31BE3663-05A1-4380-9955-ECBD4E1AD618.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/657FE771-8978-4E40-9AA9-201603AC8B5F.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/657FE771-8978-4E40-9AA9-201603AC8B5F.png new file mode 100644 index 0000000..e49f202 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/657FE771-8978-4E40-9AA9-201603AC8B5F.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/8F6D8768-149A-492E-B88F-DECA4DB283B5.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/8F6D8768-149A-492E-B88F-DECA4DB283B5.png new file mode 100644 index 0000000..3820728 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/images/pages/8F6D8768-149A-492E-B88F-DECA4DB283B5.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/454E2ABB-7327-4C15-A46D-ABE05E765CA4.data b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/454E2ABB-7327-4C15-A46D-ABE05E765CA4.data new file mode 100644 index 0000000..ff4c790 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/454E2ABB-7327-4C15-A46D-ABE05E765CA4.data @@ -0,0 +1,295 @@ + + + + + backgroundcolor + + 0.22745098173618317 + 0.22745098173618317 + 0.22745098173618317 + + iconid + 31BE3663-05A1-4380-9955-ECBD4E1AD618 + iconisuserspecified + + items + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.playartist + + actionuid + remote.alfred.runworkflow + buttoniconid + 27BDEB50-2E71-474D-B329-30EBFB7BC663 + buttonlabel + Play Artist + itemuid + BC451E4F-7D30-4E8A-9B9D-0E84C0AF228C + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.playalbum + + actionuid + remote.alfred.runworkflow + buttoniconid + D191C6F2-CF3A-4F3A-AEDB-9D8B03EA7EC9 + buttonlabel + Play Album + itemuid + CD9F8022-CCED-4C58-A65C-BFBF46B47865 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.repeating + + actionuid + remote.alfred.runworkflow + buttoniconid + 9B2EBB97-E54C-420E-BB2E-20AC87764C68 + buttonlabel + Activate Repeating + itemuid + 3AB82BD4-8431-450E-BFEF-F445506BA22C + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.shuffle + + actionuid + remote.alfred.runworkflow + buttoniconid + 577A4640-8D94-4813-9223-B355BE7FE1BD + buttonlabel + Activate Shuffle + itemuid + 609138A1-0456-4EC6-B728-DEBC191BE29F + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.random + + actionuid + remote.alfred.runworkflow + buttoniconid + 3690378D-02F4-4BF9-BC91-975F3739542B + buttonlabel + Random Track + itemuid + 27015EAB-A58E-4DCB-B3A0-54B8E2A1A8AD + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.randomalbum + + actionuid + remote.alfred.runworkflow + buttoniconid + 2375184C-CC97-4763-A846-D2FAB1259FD1 + buttonlabel + Random Album + itemuid + C7B51235-8FAF-4607-BF3B-493E3E1ACEC6 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.mute + + actionuid + remote.alfred.runworkflow + buttoniconid + E8BE74B6-2928-4513-A0BC-B88EBF839ABD + buttonlabel + Mute/Unmute + itemuid + FE5DC9FF-211E-4EE9-9881-52A92FFF8055 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.volmax + + actionuid + remote.alfred.runworkflow + buttoniconid + EE84BB33-1412-4F21-8B4D-D09362ECFE7A + buttonlabel + Volume Max + itemuid + 489EE95B-58D0-4FCC-B76C-F8FFF476941A + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.playpause + + actionuid + remote.alfred.runworkflow + buttoniconid + E7ECAC10-DDC2-4860-A342-A876756D8812 + buttonlabel + Play/Pause + itemuid + 37F02763-E4E9-41B2-A984-1FC85272D748 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.volumedown + + actionuid + remote.alfred.runworkflow + buttoniconid + 5365AF85-EDB1-4789-9ABD-B272A8C96AA0 + buttonlabel + Volume Down + itemuid + DC813FB1-B979-4A3F-9146-3BF499C902C5 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.volumeup + + actionuid + remote.alfred.runworkflow + buttoniconid + 924A7250-A8D3-4944-BDEF-74B3DD32DC75 + buttonlabel + Volume Up + itemuid + F3931E5D-9D07-410F-BF96-7B7501DEE354 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.volmid + + actionuid + remote.alfred.runworkflow + buttoniconid + 41AECA11-8410-4CFF-8BAB-51FE6DE283F4 + buttonlabel + Volume 50% + itemuid + 87F8CB97-6174-4517-B52A-3481C03EDEAC + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.previous + + actionuid + remote.alfred.runworkflow + buttoniconid + 4368A343-21A8-44C7-96F9-4870FA1C2EFB + buttonlabel + Previous Track + itemuid + 95AC7068-4EE3-4451-8088-E48C0A2CD9BF + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.play + + actionuid + remote.alfred.runworkflow + buttoniconid + CC39269A-4977-48A1-8427-F9CFC2AE8EED + buttonlabel + Play + itemuid + 627C824B-9492-4B92-B94F-85D3102D0AC7 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.pause + + actionuid + remote.alfred.runworkflow + buttoniconid + AEC59638-4779-4470-9A6A-E32992498ED2 + buttonlabel + Pause + itemuid + 54AF3815-20C7-4C58-875F-0725C1200A69 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.next + + actionuid + remote.alfred.runworkflow + buttoniconid + 749D3ABB-38FB-4EFB-9E3D-881C5AF5CAC9 + buttonlabel + Next Track + itemuid + 193C3A2A-443C-4B0E-B224-6AC4AADC8170 + + + subtitle + Commands to control Spotify + title + Playing commands + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/5F27FB6D-93ED-45A2-BE11-F71030019345.data b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/5F27FB6D-93ED-45A2-BE11-F71030019345.data new file mode 100644 index 0000000..87e3742 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/5F27FB6D-93ED-45A2-BE11-F71030019345.data @@ -0,0 +1,263 @@ + + + + + backgroundcolor + + 0.22745098173618317 + 0.22745098173618317 + 0.22745098173618317 + + iconid + 657FE771-8978-4E40-9AA9-201603AC8B5F + iconisuserspecified + + items + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.artistradio + + actionuid + remote.alfred.runworkflow + buttoniconid + A6374417-A3FC-4360-9913-504F7A21F4F1 + buttonlabel + Create Artist Radio + itemuid + A6C0F100-3776-4A4B-965B-960E68FB18D9 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.songadio + + actionuid + remote.alfred.runworkflow + buttoniconid + 83D8A06D-1B1C-4B90-A00A-5B5E575DF7E8 + buttonlabel + Create Song Radio + itemuid + 9385F35A-6D2F-413A-A3F6-F0E54DD1F8D6 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.lyrics + + actionuid + remote.alfred.runworkflow + buttoniconid + 8B60A0B6-910F-4B63-A0B1-953D9A99990F + buttonlabel + Lyrics + itemuid + AA7FA832-013B-46FB-AD02-CDE9BBE67F3D + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.share + + actionuid + remote.alfred.runworkflow + buttoniconid + C5B9A789-80F3-41BA-9A46-C34DD4CDE050 + buttonlabel + Share + itemuid + 503CC6A0-1B8A-4A5C-9AF0-37ECC7BBE0A2 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.current + + actionuid + remote.alfred.runworkflow + buttoniconid + 58AF0E83-EC70-42B2-AED5-DB7DF65C043C + buttonlabel + Current Track Info + itemuid + 34113641-481E-45C2-A314-51E3E0B4F0CB + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.refreshlibrary + + actionuid + remote.alfred.runworkflow + buttoniconid + AF86DFA1-E6C7-4C2B-BD00-66614B6CFE81 + buttonlabel + Refresh Library + itemuid + 9A63CF58-8C3C-4AAA-9C3D-B5F679C4AA0F + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.issue + + actionuid + remote.alfred.runworkflow + buttoniconid + FDAEECD4-DE40-443C-89F9-B46D5592D8C4 + buttonlabel + Report Issue + itemuid + 8F6811B3-DAC8-40D0-B596-15C1C41690AE + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.debug + + actionuid + remote.alfred.runworkflow + buttoniconid + 707403B7-FF4A-4995-99F3-AB2B5F39B34F + buttonlabel + Debug + itemuid + 67E6BD1B-5E89-4144-B286-24FE7C8339C3 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.addcurrenttrack + + actionuid + remote.alfred.runworkflow + buttoniconid + 2737969D-A8B4-4550-8568-3C926D36DD81 + buttonlabel + Add track to AP or Your Music + itemuid + F47AE1BE-2C3E-48F5-8E4E-2754906D01E2 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.addcurrenttrackto + + actionuid + remote.alfred.runworkflow + buttoniconid + 4FE5620A-FB79-440E-8633-B8148EE1191E + buttonlabel + Add track to... + itemuid + 2989097C-DDCC-4318-A651-AC1DB34B3134 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.removecurrenttrackfrom + + actionuid + remote.alfred.runworkflow + buttoniconid + CED135C7-B958-4C68-8C47-956FBAA9086A + buttonlabel + Remove track from... + itemuid + 4A8EE485-C503-4850-970F-614E3510BD70 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.lookupcurrentartist + + actionuid + remote.alfred.runworkflow + buttoniconid + D427D63A-3C3A-420D-87D5-46185FE361E3 + buttonlabel + Lookup Artist Online + itemuid + 4234DEFF-0583-4298-8A6F-057067C76B29 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.youtube + + actionuid + remote.alfred.runworkflow + buttoniconid + 15D6EBE2-6D82-4F2C-A4B3-5949424B4EF9 + buttonlabel + Youtube + itemuid + 58A82CED-55BB-4687-B44E-847F0EC8E860 + + + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.reset + + actionuid + remote.alfred.runworkflow + buttoniconid + 83F461DC-A47F-4407-92C3-BF269BB49953 + buttonlabel + Reset Settings + itemuid + 8D7FDC8C-BBB0-437E-92F6-48F1FFA5070B + + + subtitle + All other workflow commands + title + Other commands + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/9DE7ED8E-0E79-4BF5-B950-8B6B7D173E5E.data b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/9DE7ED8E-0E79-4BF5-B950-8B6B7D173E5E.data new file mode 100644 index 0000000..cac8226 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/9DE7ED8E-0E79-4BF5-B950-8B6B7D173E5E.data @@ -0,0 +1,279 @@ + + + + + backgroundcolor + + 0.22745098173618317 + 0.22745098173618317 + 0.22745098173618317 + + iconid + 8F6D8768-149A-492E-B88F-DECA4DB283B5 + iconisuserspecified + + items + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.show + + actionuid + remote.alfred.runworkflow + buttoniconid + 163265DD-5CAB-4D11-B984-F86871709AEE + buttonlabel + Show Workflow + itemuid + 65FC6C78-C023-4003-A536-08760E5562FE + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.showalfredplaylist + + actionuid + remote.alfred.runworkflow + buttoniconid + 26215986-3B9E-4491-A93B-67878CE04EB5 + buttonlabel + Show Alfred Playlist + itemuid + 94A2F569-92F3-4296-B96C-C74282909B32 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.playlists + + actionuid + remote.alfred.runworkflow + buttoniconid + D51D9C70-68AF-4D63-ABD0-09906D9B1EC9 + buttonlabel + Show Playlists + itemuid + 2A7377E2-ACA5-414C-BF5E-DA65DA501666 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.settings + + actionuid + remote.alfred.runworkflow + buttoniconid + 19E641F3-FE15-4058-9597-255FDDAA4F48 + buttonlabel + Show Settings + itemuid + 9091F837-9889-4FAC-9599-7F33D0041138 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.recenttrack + + actionuid + remote.alfred.runworkflow + buttoniconid + E9C9194B-AF5F-4BAD-88AB-DB7AFED380BF + buttonlabel + Show Recent Tracks + itemuid + 71DB6D1E-06F1-4796-9D75-380826512CD1 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.currenttrack + + actionuid + remote.alfred.runworkflow + buttoniconid + EA114C5E-A6A7-479E-BDB8-17E9C3163B53 + buttonlabel + Show Current Track + itemuid + 70E29B81-95AB-45F3-AA49-37E0A6417F8C + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.connect + + actionuid + remote.alfred.runworkflow + buttoniconid + 28180F27-0728-414D-88F3-76E99A58FA7D + buttonlabel + Show Connect + itemuid + DE668106-4F4A-4805-BFE3-7A61ABA752C2 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.shownewreleases + + actionuid + remote.alfred.runworkflow + buttoniconid + F14D664A-48D5-4232-A6CD-772F3361630B + buttonlabel + Show New Releases + itemuid + 4873C62B-B61C-4141-B3DE-FE6F6830495C + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.keyup + + actionuid + remote.alfred.runworkflow + buttoniconid + 5C18A3F0-C5CC-4B8D-B71E-B00B420CA2DC + buttonlabel + Key Up + itemuid + 75FD4FCA-38F9-4D86-BA4C-DA12D43C8D45 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.keyenter + + actionuid + remote.alfred.runworkflow + buttoniconid + DF3FC215-4E94-472D-91B2-9D94A3B8632F + buttonlabel + Key Enter + itemuid + 1C8D1F9A-5448-4523-A440-EB92A5C72748 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.showbrowse + + actionuid + remote.alfred.runworkflow + buttoniconid + AE944AAF-0B18-436F-AB21-1B22AA446063 + buttonlabel + Show Browse + itemuid + A96A74C4-5B19-4889-9752-35DA0978B1A6 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.showplayqueue + + actionuid + remote.alfred.runworkflow + buttoniconid + 569B0F42-A04A-40B7-9E86-EA1C61EF0AE5 + buttonlabel + Show Play Queue + itemuid + B579AA6E-08DF-4219-B130-779A079CD245 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.keydown + + actionuid + remote.alfred.runworkflow + buttoniconid + 6D35BFAD-C96C-4BF8-B76B-5C4BB4313DF9 + buttonlabel + Key Down + itemuid + C799ED72-F1C4-4915-81B9-BCAEAD11F863 + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.keyescape + + actionuid + remote.alfred.runworkflow + buttoniconid + 89CD46BC-7C18-4D85-A23B-CF5F93273B1A + buttonlabel + Key Escape + itemuid + BE4EB8B2-D511-4664-BFC1-5D0A609D9B6C + + + + actionconfig + + autoworkflowuid + + triggerid + com.vdesabou.miniplayer.showsearchonline + + actionuid + remote.alfred.runworkflow + buttoniconid + 9045D879-6632-4113-9915-85534EBECBB1 + buttonlabel + Show Search Online + itemuid + 6960F909-AFC6-4E7F-A6F8-58E3E3DD7A9B + + + subtitle + Display workflow and navigate + title + Show commands + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/pages.data b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/pages.data new file mode 100644 index 0000000..411353c --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/_remote/pages/pages.data @@ -0,0 +1,12 @@ + + + + + pages + + 454E2ABB-7327-4C15-A46D-ABE05E765CA4 + 5F27FB6D-93ED-45A2-BE11-F71030019345 + 9DE7ED8E-0E79-4BF5-B950-8B6B7D173E5E + + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/a.txt b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/a.txt new file mode 100644 index 0000000..e69de29 diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/alerter b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/alerter new file mode 100755 index 0000000..410cf21 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/alerter differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/callback.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/callback.php new file mode 100644 index 0000000..e81385e --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/callback.php @@ -0,0 +1,89 @@ +oauth_client_id; +$oauth_client_secret = $settings->oauth_client_secret; +$oauth_redirect_uri = $settings->oauth_redirect_uri; + +try { + $session = new SpotifyWebAPI\Session($oauth_client_id, $oauth_client_secret, $oauth_redirect_uri); + + if (!empty($_GET['code'])) { + + // Request a access token using the code from Spotify + $ret = $session->requestAccessToken($_GET['code']); + + if ($ret == true) { + $api = new SpotifyWebAPI\SpotifyWebAPI(); + // Set the code on the API wrapper + $api->setAccessToken($session->getAccessToken()); + $user = $api->me(); + + $ret = updateSetting($w,'oauth_access_token',$session->getAccessToken()); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + $ret = updateSetting($w,'oauth_expires',time()); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + $ret = updateSetting($w,'oauth_refresh_token',$session->getRefreshToken()); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + $ret = updateSetting($w,'country_code',$user->country); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + $ret = updateSetting($w,'display_name',$user->display_name); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + $ret = updateSetting($w,'userid',$user->id); + if($ret == false) { + echo "There was an error when updating settings"; + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + return; + } + + echo "Hello $user->display_name ! You are now successfully logged and you can close this window."; + + } else { + echo "There was an error during the authentication (could not get token)"; + } + } else { + echo "There was an error during the authentication (could not get code)"; + } + +} +catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + echo "There was an error during the authentication (exception " . jTraceEx($e) . ")"; +} + +exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); +?> diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/icon.png new file mode 100644 index 0000000..bba88bc Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add.png new file mode 100644 index 0000000..0dff5e2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to.png new file mode 100644 index 0000000..69e12e3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to_ap_yourmusic.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to_ap_yourmusic.png new file mode 100644 index 0000000..07795f8 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/add_to_ap_yourmusic.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/albums.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/albums.png new file mode 100644 index 0000000..3eb0791 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/albums.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred-workflow-icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred-workflow-icon.png new file mode 100644 index 0000000..d886bd8 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred-workflow-icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred_playlist.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred_playlist.png new file mode 100644 index 0000000..1c99b3b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/alfred_playlist.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artists.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artists.png new file mode 100644 index 0000000..c32a45e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artists.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artworks.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artworks.png new file mode 100644 index 0000000..c685395 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/artworks.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/back.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/back.png new file mode 100644 index 0000000..c9fa990 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/back.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/biography.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/biography.png new file mode 100644 index 0000000..3de3419 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/biography.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/browse.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/browse.png new file mode 100644 index 0000000..c7e371a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/browse.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/change_theme_color.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/change_theme_color.png new file mode 100644 index 0000000..1d4e44e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/change_theme_color.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check.png new file mode 100644 index 0000000..4736d8f Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check_update.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check_update.png new file mode 100644 index 0000000..9193278 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/check_update.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/complete_collection.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/complete_collection.png new file mode 100644 index 0000000..e6b0969 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/complete_collection.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/computer.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/computer.png new file mode 100644 index 0000000..4dd51b3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/computer.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/connect.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/connect.png new file mode 100644 index 0000000..38fa826 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/connect.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/create_playlist.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/create_playlist.png new file mode 100644 index 0000000..7c1a223 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/create_playlist.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/current_track.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/current_track.png new file mode 100644 index 0000000..2c16268 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/current_track.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/debug.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/debug.png new file mode 100644 index 0000000..548458b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/debug.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_artworks.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_artworks.png new file mode 100644 index 0000000..773b1f5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_artworks.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_autoplay.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_autoplay.png new file mode 100644 index 0000000..24acf2e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_autoplay.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_display_rating.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_display_rating.png new file mode 100644 index 0000000..9e4e078 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_display_rating.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_lookup_local_tracks_online.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_lookup_local_tracks_online.png new file mode 100644 index 0000000..0751f0f Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_lookup_local_tracks_online.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_mopidy.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_mopidy.png new file mode 100644 index 0000000..e9f5401 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_mopidy.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_now_playing.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_now_playing.png new file mode 100644 index 0000000..1b65b33 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_now_playing.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_public_playlists.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_public_playlists.png new file mode 100644 index 0000000..75bd2d2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_public_playlists.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_quick_mode.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_quick_mode.png new file mode 100644 index 0000000..b68e0de Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_quick_mode.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_use_growl.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_use_growl.png new file mode 100644 index 0000000..37b3d37 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/disable_use_growl.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_artworks.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_artworks.png new file mode 100644 index 0000000..b8d8104 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_artworks.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_autoplay.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_autoplay.png new file mode 100644 index 0000000..de1856a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_autoplay.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_display_rating.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_display_rating.png new file mode 100644 index 0000000..1a4cf96 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_display_rating.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_lookup_local_tracks_online.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_lookup_local_tracks_online.png new file mode 100644 index 0000000..370ee5b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_lookup_local_tracks_online.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_mopidy.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_mopidy.png new file mode 100644 index 0000000..6cfe01a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_mopidy.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_now_playing.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_now_playing.png new file mode 100644 index 0000000..3654e01 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_now_playing.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_public_playlists.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_public_playlists.png new file mode 100644 index 0000000..30905ec Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_public_playlists.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_quick_mode.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_quick_mode.png new file mode 100644 index 0000000..e3fc0c3 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_quick_mode.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_use_growl.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_use_growl.png new file mode 100644 index 0000000..1fb9b5d Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/enable_use_growl.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/facebook.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/facebook.png new file mode 100644 index 0000000..f0db355 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/facebook.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/follow.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/follow.png new file mode 100644 index 0000000..24f8314 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/follow.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/icon.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/icon.png new file mode 100644 index 0000000..1d4e44e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/icon.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/info.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/info.png new file mode 100644 index 0000000..47db5fc Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/info.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/issue.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/issue.png new file mode 100644 index 0000000..6513702 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/issue.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/kill.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/kill.png new file mode 100644 index 0000000..bf17037 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/kill.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lastfm.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lastfm.png new file mode 100644 index 0000000..30a22b2 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lastfm.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lyrics.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lyrics.png new file mode 100644 index 0000000..52dd584 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/lyrics.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mail.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mail.png new file mode 100644 index 0000000..8cd63eb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mail.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_port.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_port.png new file mode 100644 index 0000000..5eb2939 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_port.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_server.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_server.png new file mode 100644 index 0000000..7f3df8d Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mopidy_server.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mute.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mute.png new file mode 100644 index 0000000..644027c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/mute.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/new_releases.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/new_releases.png new file mode 100644 index 0000000..53b2638 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/new_releases.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/next.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/next.png new file mode 100644 index 0000000..bb432ad Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/next.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/numbers.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/numbers.png new file mode 100644 index 0000000..b14b4fb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/numbers.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online.png new file mode 100644 index 0000000..5a87708 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_album.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_album.png new file mode 100644 index 0000000..e7e974e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_album.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_artist.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_artist.png new file mode 100644 index 0000000..39982ca Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/online_artist.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/packal.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/packal.png new file mode 100644 index 0000000..1477b22 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/packal.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/pause.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/pause.png new file mode 100644 index 0000000..abaa3ca Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/pause.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play.png new file mode 100644 index 0000000..13211d8 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play_queue.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play_queue.png new file mode 100644 index 0000000..d4b455a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/play_queue.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playlists.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playlists.png new file mode 100644 index 0000000..ac77103 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playlists.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playpause.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playpause.png new file mode 100644 index 0000000..470be0c Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/playpause.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/previous.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/previous.png new file mode 100644 index 0000000..87cc609 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/previous.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_artist.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_artist.png new file mode 100644 index 0000000..c935f1b Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_artist.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_numbers.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_numbers.png new file mode 100644 index 0000000..78e3934 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_numbers.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_song.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_song.png new file mode 100644 index 0000000..a675136 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/radio_song.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random.png new file mode 100644 index 0000000..c5589ab Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random_album.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random_album.png new file mode 100644 index 0000000..72a0fff Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/random_album.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recent.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recent.png new file mode 100644 index 0000000..88e9682 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recent.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recreate.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recreate.png new file mode 100644 index 0000000..5b53b21 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/recreate.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/related.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/related.png new file mode 100644 index 0000000..d8cd38a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/related.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove.png new file mode 100644 index 0000000..d733600 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove_from.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove_from.png new file mode 100644 index 0000000..677decb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/remove_from.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/repeating.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/repeating.png new file mode 100644 index 0000000..569a32a Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/repeating.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/results_numbers.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/results_numbers.png new file mode 100644 index 0000000..6ca49c5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/results_numbers.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search.png new file mode 100644 index 0000000..565a101 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search_scope_yourmusic_only.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search_scope_yourmusic_only.png new file mode 100644 index 0000000..f0fd262 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/search_scope_yourmusic_only.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/settings.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/settings.png new file mode 100644 index 0000000..af0d85f Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/settings.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/share.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/share.png new file mode 100644 index 0000000..b84b141 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/share.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/shuffle.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/shuffle.png new file mode 100644 index 0000000..7548b60 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/shuffle.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/smartphone.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/smartphone.png new file mode 100644 index 0000000..23f8649 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/smartphone.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/speaker.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/speaker.png new file mode 100644 index 0000000..e8df26d Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/speaker.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/spotify.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/spotify.png new file mode 100644 index 0000000..b1b7cdb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/spotify.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/star.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/star.png new file mode 100644 index 0000000..019958e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/star.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/tracks.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/tracks.png new file mode 100644 index 0000000..82159cb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/tracks.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/twitter.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/twitter.png new file mode 100644 index 0000000..5022deb Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/twitter.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/uncheck.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/uncheck.png new file mode 100644 index 0000000..d7d3ee8 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/uncheck.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update.png new file mode 100644 index 0000000..94bf2fd Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update_in_progress.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update_in_progress.png new file mode 100644 index 0000000..24160d5 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/update_in_progress.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmax.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmax.png new file mode 100644 index 0000000..1bfb167 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmax.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmid.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmid.png new file mode 100644 index 0000000..9f199df Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volmid.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_down.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_down.png new file mode 100644 index 0000000..3050620 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_down.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_up.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_up.png new file mode 100644 index 0000000..1c29cee Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/volume_up.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/warning.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/warning.png new file mode 100644 index 0000000..99e3679 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/warning.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/website.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/website.png new file mode 100644 index 0000000..5fb9b5f Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/website.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/wikipedia.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/wikipedia.png new file mode 100644 index 0000000..5fd8a5e Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/wikipedia.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_artists.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_artists.png new file mode 100644 index 0000000..068f61f Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_artists.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_tracks.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_tracks.png new file mode 100644 index 0000000..7f6c8f4 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/your_tops_tracks.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/yourmusic.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/yourmusic.png new file mode 100644 index 0000000..93eeb01 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/yourmusic.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/youtube.png b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/youtube.png new file mode 100644 index 0000000..5228f92 Binary files /dev/null and b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/images/youtube.png differ diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/index.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/index.php new file mode 100644 index 0000000..a89fd5a --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/index.php @@ -0,0 +1,44 @@ +oauth_client_id; +$oauth_client_secret = $settings->oauth_client_secret; +$oauth_redirect_uri = $settings->oauth_redirect_uri; + +try { + $session = new SpotifyWebAPI\Session($oauth_client_id, $oauth_client_secret, $oauth_redirect_uri); + + // Get the authorization URL and send the user there + header('Location: '.$session->getAuthorizeUrl(array( + 'scope' => array( + 'user-library-read', + 'user-read-email', + 'user-read-private', + 'user-library-modify', + 'user-follow-modify', + 'user-follow-read', + 'playlist-read-private', + 'playlist-modify-public', + 'playlist-modify-private', + 'playlist-read-collaborative', + 'user-top-read', + 'user-read-recently-played', + 'user-read-playback-state', + 'user-modify-playback-state', + 'user-read-currently-playing'), + 'show_dialog' => true, ))); +} catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + echo 'There was an error during the authentication flow (exception '.jTraceEx($e).')'; + displayNotificationWithArtwork($w, 'Web server killed', './images/warning.png', 'Error!'); + exec("kill -9 $(ps -efx | grep \"php -S localhost:15298\" | grep -v grep | awk '{print $2}')"); + + return; +} diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/info.plist b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/info.plist new file mode 100644 index 0000000..eed1002 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/info.plist @@ -0,0 +1,10616 @@ + + + + + bundleid + com.vdesabou.spotify.mini.player + connections + + 024D6172-912E-4EAE-92AA-776626D52FFB + + + destinationuid + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 05F86AA1-D3EE-4409-9A58-898B36FFE503 + + + destinationuid + 19215BE5-986E-4AC9-9166-C80872C51DBE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 062BBC6A-8B21-4777-8580-5CAE8506A859 + + + destinationuid + B2B50FA2-E3B9-43C3-AC33-754811E3CAC3 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 090D4A5C-85C3-4083-B936-3E61ED83B1A3 + + + destinationuid + B91D4F9A-DEA5-426E-B984-372482E03125 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C + + + destinationuid + A2C8ACBA-F98F-457A-90E8-11BA2112342C + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0B75CF43-8B04-405F-86C3-2FFC59AC4A70 + + + destinationuid + 1A29820A-69D9-458F-9285-76901C21D7F4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0C74516A-D95D-4379-94B6-CD984A31A003 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0CAE95A9-03D6-4305-A30B-153796564AD1 + + + destinationuid + 0749257A-D830-483B-9EF5-580E33C10BB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0E45EEB7-EA6D-4E6F-8655-98731989AEE0 + + + destinationuid + B5D85A55-8E85-4B14-81EF-0656DC5E7594 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 0EBF4C61-5630-4629-8B4F-AD91D3470760 + + + destinationuid + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1059D963-473F-44F8-8D60-94CFCE56BFF2 + + + destinationuid + 8B88B440-38F7-4EBA-9A2E-46779141C889 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 11E4CA98-E51E-45E4-91ED-72B4A1A34283 + + + destinationuid + E049B90B-F4AC-475E-A20A-82083E709F11 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2 + + + destinationuid + 383F2E0F-8A62-41E5-8575-415A9225572E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 16F5C3BF-01EE-493C-9E7B-CC54D482B7A6 + + + destinationuid + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + modifiers + 0 + modifiersubtext + + vitoclose + + + + 175EB434-B9E1-4C6F-85B0-B0A3436E7E40 + + + destinationuid + 2609AC90-5B4D-4043-8F13-D5187B14833F + modifiers + 0 + modifiersubtext + + vitoclose + + + + 18496AC4-EA42-444C-A906-642E38259C96 + + + destinationuid + 5F3AF2C8-064F-4C10-8D99-22E212825BFE + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + 8DF18F9A-B3A5-4B14-8360-AD850CF5C143 + modifiers + 524288 + modifiersubtext + Play album with Spotify + vitoclose + + + + destinationuid + 9845C770-A2CC-4752-A542-D71BE1081691 + modifiers + 1048576 + modifiersubtext + Play artist in Spotify + vitoclose + + + + destinationuid + 1A88766E-BF4A-48F5-9BD4-D3538634422F + modifiers + 131072 + modifiersubtext + Add album or playlist to your Alfred Playlist + vitoclose + + + + destinationuid + 7918E8F7-20AE-445E-9AEA-E2E54CDE967D + modifiers + 8388608 + modifiersubtext + Add track to Alfred playlist + vitoclose + + + + destinationuid + 5F5E8A6D-8707-41FC-B5D1-660CD11685F0 + modifiers + 262144 + modifiersubtext + Search artist online + vitoclose + + + + 19215BE5-986E-4AC9-9166-C80872C51DBE + + 1A88766E-BF4A-48F5-9BD4-D3538634422F + + 1A88C8F9-C6E3-42C9-98A5-E277B97690B0 + + + destinationuid + 6008947F-A428-45E7-8B9C-1F3402278D3A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1B716436-7DCE-45DA-8567-FA157808962F + + + destinationuid + 6FEAFE02-DF77-4F58-9305-651E6D627144 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1B841176-1A95-46BD-8123-583075FAB8E4 + + + destinationuid + 83FDAFA8-0D15-43B2-9CA9-E9B3459ACE5E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1BA522F3-B2D0-4F36-B86C-738FB3AC55DD + + + destinationuid + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1BA8D519-4B49-4BD9-B329-D004A22AE84C + + + destinationuid + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + modifiers + 0 + modifiersubtext + + vitoclose + + + + 1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0 + + + destinationuid + 51401C92-A6F8-4E2A-AA02-D140984EE916 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2B0C6211-1DD0-4CE6-8082-37957F15CC1D + + + destinationuid + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2B0C8466-4AED-4272-9C10-50F3BCE88043 + + + destinationuid + CF46537F-6F59-40DB-A643-72A7BB952840 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2B1BF20E-C892-4340-ABFE-AFA4AF7F8C52 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2E15D453-FA20-483A-AAA3-59FF33614829 + + + destinationuid + F2B24FB4-386C-4562-99D2-E4162D26AB4A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2EC684F9-F50A-4300-9421-FF3B95CF2CC1 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2F1F6369-46C0-483B-816F-3796168AE060 + + + destinationuid + 0749257A-D830-483B-9EF5-580E33C10BB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2FC567E2-E6C5-4A91-B42E-1996532B78C9 + + + destinationuid + 23412027-872A-4639-A9D9-DCFD8D8FF36D + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3016205A-8693-421C-B3B6-3CE742806FCC + + + destinationuid + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 303A65BF-8E81-48E8-AA28-E1CA408FDD53 + + + destinationuid + 13367FE5-35F7-4B94-8728-CF6F3D9F4C2B + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3040749D-6B5C-4CCD-AF95-AEC0F83B48D9 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 30833563-364F-4EC4-B467-F63A7F66EB06 + + + destinationuid + C40074F8-D8EC-4270-AE0C-05A98F3E2DCD + modifiers + 0 + modifiersubtext + + vitoclose + + + + 30F45FDA-252D-4C22-894C-444F7E3E8E78 + + + destinationuid + 39C34247-AE29-43A1-879B-3965F3AAF475 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 318D20CD-D753-4CCC-B931-BB3CFC6A1D0A + + + destinationuid + C7A836E4-009F-4028-A233-561002F90337 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 327849A3-A34A-46BA-AC04-1F5115824DC3 + + + destinationuid + CEF36AB9-7CC2-4765-BF84-751E88B69023 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3280F15E-8C80-4A0D-8439-07A113AA1094 + + + destinationuid + E049B90B-F4AC-475E-A20A-82083E709F11 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3435F565-E791-4FE9-A7B9-85B4A2EA353C + + + destinationuid + 0749257A-D830-483B-9EF5-580E33C10BB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3617F927-558D-4F30-B8D1-B7789F863AB0 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 36FF7DE6-29DF-4E25-8E15-58411CE75638 + + + destinationuid + 2B1BF20E-C892-4340-ABFE-AFA4AF7F8C52 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3837382F-63B4-4B0D-A880-A1CF7079D584 + + + destinationuid + ECC53637-75AD-4FD2-9605-8E038D04C4BF + modifiers + 0 + modifiersubtext + + vitoclose + + + + 39A1935A-37F5-49FA-A860-BCF7765A8C65 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 39C34247-AE29-43A1-879B-3965F3AAF475 + + + destinationuid + C91B7486-D357-4C1C-8661-83290128E78E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3AA52DF5-6A73-4739-A088-0F78F446B447 + + + destinationuid + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 3F85747B-FC44-4B07-AA6E-3645F0CC0DF7 + + + destinationuid + ECC53637-75AD-4FD2-9605-8E038D04C4BF + modifiers + 0 + modifiersubtext + + vitoclose + + + + 401D4FC7-21EC-47C3-9896-FCD97C8563F4 + + + destinationuid + FD282800-1267-4ACF-BF0D-C42758D49623 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 450AEF8B-BDAA-409C-A0D4-68769545FBCF + + + destinationuid + 25E3EBDF-2CFA-4599-A13B-8C63B3E5329A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 450CD09C-F6EB-4270-8FEE-C1E33586165F + + + destinationuid + 80AD9430-0A5B-4196-8A02-B3B1CEEE678D + modifiers + 0 + modifiersubtext + + vitoclose + + + + 455BDE70-BCF4-447F-ABFF-C25D8E5B08B6 + + + destinationuid + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 479B0769-F60E-4F2B-A2A6-BA361F3B0BF2 + + + destinationuid + C3F966D4-D292-4B70-9024-B8788BA5488F + modifiers + 0 + modifiersubtext + + vitoclose + + + + 4BE9FB30-9B4F-4E44-861D-D178507A7568 + + + destinationuid + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 4EB5FB5E-6472-4757-A479-B206B6080036 + + + destinationuid + 64953E09-D9D0-485B-B92B-79E7FEC15927 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 4FB4D3A4-9DA1-4369-99D1-664AE2685C27 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 528C59BE-0DAD-4C1D-876E-09EEE2B889FA + + + destinationuid + C3F966D4-D292-4B70-9024-B8788BA5488F + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5372B0DF-11F6-41D9-8E6C-ED8C2A7EBE70 + + + destinationuid + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 55288BC7-DEF9-4B85-BB03-274A7322F31A + + + destinationuid + 7351C6F1-1AB2-42D0-9003-5FFECFDEB441 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 552D77E3-1550-4035-AB49-8B708B081EC9 + + + destinationuid + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + modifiers + 0 + modifiersubtext + + vitoclose + + + + 57B3B398-989F-42FF-B449-281E41BB0851 + + + destinationuid + 2EC684F9-F50A-4300-9421-FF3B95CF2CC1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 57BD5D83-BC36-41AF-B6F7-B3289DD427CE + + + destinationuid + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5AF7EEEC-2E55-482C-8750-4CE6AD752683 + + + destinationuid + 98123379-ADC9-4377-9F28-DF79E01715D1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5BB099A1-224D-4702-BBBC-52919BDCCF62 + + + destinationuid + E3BCC85B-A326-41C9-BAC9-623BE1865375 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2 + + + destinationuid + 98123379-ADC9-4377-9F28-DF79E01715D1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5EB4A672-01BC-4DBB-AD39-60EBB0F79A67 + + + destinationuid + ECC53637-75AD-4FD2-9605-8E038D04C4BF + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5F3AF2C8-064F-4C10-8D99-22E212825BFE + + 5F3F806B-0B88-4C17-92E7-72A944CEB1A6 + + + destinationuid + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 5F5E8A6D-8707-41FC-B5D1-660CD11685F0 + + 6008947F-A428-45E7-8B9C-1F3402278D3A + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 60F15971-216E-4921-8A56-C6B992D25B08 + + + destinationuid + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 620CF52F-BCFD-4957-BC4F-1E9853125AF5 + + + destinationuid + A2C8ACBA-F98F-457A-90E8-11BA2112342C + modifiers + 0 + modifiersubtext + + vitoclose + + + + 62AA861E-C910-4354-84C9-58A5660365D8 + + + destinationuid + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 63010287-34D8-4CB5-9AE8-7D868883A5E0 + + + destinationuid + 6FF2EF90-205D-4423-B818-11BCC11D34BE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 66723864-4D1C-439D-A1DE-5F90BCB03CCC + + + destinationuid + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 66A0F734-983C-420D-B6E4-F21922513E4B + + + destinationuid + 1A29820A-69D9-458F-9285-76901C21D7F4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 66AE01C5-E034-40D2-9CEE-69A063016B4A + + + destinationuid + 23412027-872A-4639-A9D9-DCFD8D8FF36D + modifiers + 0 + modifiersubtext + + vitoclose + + + + 66F8A022-163E-42CB-A9E9-B32E8158ACA7 + + + destinationuid + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 68A6C7CD-CB82-4A31-A935-E38F8E414772 + + + destinationuid + AA5EC8E7-EFB2-4194-9412-B562C202A977 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6965EC4E-AE6C-40BD-A3B5-CD316812BF30 + + + destinationuid + 64953E09-D9D0-485B-B92B-79E7FEC15927 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 69E43FC9-457E-4082-8930-A1B00B6A5514 + + + destinationuid + 98123379-ADC9-4377-9F28-DF79E01715D1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6AB2756A-CF82-447B-BB7F-AC42AC2A04ED + + + destinationuid + FE00C128-31CE-4143-A647-1F1623539743 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6BC60709-1E24-4297-A9CB-3B99581AF0C6 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6E7EAD8C-4207-4393-8091-D7EC5ED9A654 + + + destinationuid + 6EC5159F-1577-4384-9869-4777146F362E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6E9B4F21-F907-4A22-8689-9A146F909454 + + + destinationuid + A2C8ACBA-F98F-457A-90E8-11BA2112342C + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6EA904F5-F25E-4B1E-A6DD-5E94263ADBC8 + + + destinationuid + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6EC5159F-1577-4384-9869-4777146F362E + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6FDBF98C-ACD5-49F8-B1FD-04B79FA04E29 + + + destinationuid + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + modifiers + 0 + modifiersubtext + + vitoclose + + + + 6FEAFE02-DF77-4F58-9305-651E6D627144 + + 6FF2EF90-205D-4423-B818-11BCC11D34BE + + + destinationuid + 5C5EA309-F6AD-440F-B4CE-6638CD188EB4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 70C9B5C9-72DA-409A-B3EC-8C2DC0EE9627 + + + destinationuid + 1A29820A-69D9-458F-9285-76901C21D7F4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7224DEC2-8842-4EF7-9D41-8996267F4231 + + + destinationuid + C91B7486-D357-4C1C-8661-83290128E78E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7351C6F1-1AB2-42D0-9003-5FFECFDEB441 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 73FB3971-4382-45F5-ADED-F1E481A95E2E + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 75E489FD-ADF2-4A30-A432-61E53BF36A00 + + + destinationuid + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + modifiers + 0 + modifiersubtext + + vitoclose + + + + 78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A + + + destinationuid + E59E23E2-837A-4B48-949A-A9EE059186C1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 78DD84AE-70E9-4DB5-BF2B-44BC774B4383 + + + destinationuid + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7918E8F7-20AE-445E-9AEA-E2E54CDE967D + + 7934F80C-2281-449C-9A89-7BC422D659D7 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 794A76A7-BB98-4A83-92BE-386A56875120 + + + destinationuid + 899AC4D2-88FA-474F-A075-AFA12F361E2B + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7CD59703-7376-4695-8BC8-DBBD01EC19A6 + + + destinationuid + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7E4C3B84-D930-490A-BF7E-FA5C57328897 + + + destinationuid + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7F15B183-963C-4EE1-9B19-10705529BF0B + + + destinationuid + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7FE5D993-C14D-4B94-9479-B361680F1C40 + + + destinationuid + E3BCC85B-A326-41C9-BAC9-623BE1865375 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 7FF09231-F068-4EA0-8537-6C1EB608CA5A + + + destinationuid + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 804D8959-D2AE-453E-BBC1-3C11B275597B + + + destinationuid + 9D647271-3601-4788-9E1F-F299FA7A39BD + modifiers + 0 + modifiersubtext + + vitoclose + + + + 80AD9430-0A5B-4196-8A02-B3B1CEEE678D + + + destinationuid + FA976637-B683-4672-837E-85462CC82B69 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 80B80179-E286-4D4A-9FEC-FCBE63AD8AEE + + + destinationuid + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 81536C26-DB7C-42CE-95C0-B78FA1C7934E + + + destinationuid + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 817080F0-4CE8-4336-A972-550D43D063B1 + + + destinationuid + 383F2E0F-8A62-41E5-8575-415A9225572E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 827D9590-7BA6-4E87-B288-0AF6C04C9B01 + + + destinationuid + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8339BE15-274E-4A77-A6A0-CEDF30EFD0E5 + + + destinationuid + 64953E09-D9D0-485B-B92B-79E7FEC15927 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8347A3BC-6F50-447F-84B3-3497D4BF720D + + + destinationuid + 7224DEC2-8842-4EF7-9D41-8996267F4231 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 83FDAFA8-0D15-43B2-9CA9-E9B3459ACE5E + + + destinationuid + 71AACE30-7E8D-4D3C-8BD1-F98FEE578AEC + modifiers + 0 + modifiersubtext + + vitoclose + + + + 85966031-0B63-4629-BF2A-CAE7C92FCDD6 + + + destinationuid + ECC53637-75AD-4FD2-9605-8E038D04C4BF + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8598A5C9-72B6-4CEF-A498-D6C2ED06DC88 + + + destinationuid + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 85A5063C-1E10-4219-BB9D-333185702D4F + + + destinationuid + 9D647271-3601-4788-9E1F-F299FA7A39BD + modifiers + 0 + modifiersubtext + + vitoclose + + + + 873EF61A-BD03-4946-87B0-C7AE5DFC5E5B + + + destinationuid + CEF36AB9-7CC2-4765-BF84-751E88B69023 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 89BC46B4-E178-4855-8863-393730814F6E + + + destinationuid + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 89D8799A-D22A-4A6D-B43D-50B9EADB879D + + + destinationuid + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8A63B1A6-0F0E-481A-9312-C75557A9DA71 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8B3222AF-02D9-4F13-9F79-6C4A935FD76F + + + destinationuid + 1A2C6EE5-E029-45EE-89D0-4C6182C7E5E0 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8C78472B-13EB-4512-B94D-4BF92867CD92 + + + destinationuid + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8D9D70BD-782D-421A-926F-7EBC18085CE9 + + + destinationuid + 4FB4D3A4-9DA1-4369-99D1-664AE2685C27 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8DF18F9A-B3A5-4B14-8360-AD850CF5C143 + + 8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5 + + + destinationuid + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8F478980-199B-45B5-AD41-EBA185446705 + + + destinationuid + 899AC4D2-88FA-474F-A075-AFA12F361E2B + modifiers + 0 + modifiersubtext + + vitoclose + + + + 8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 900B374F-3B5D-48A1-9213-99DEC1975B89 + + + destinationuid + 63010287-34D8-4CB5-9AE8-7D868883A5E0 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 901D4A54-195C-4D82-90C8-E3A6F6F48FC8 + + + destinationuid + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 93DE48B5-E0D6-4B64-B972-D01EB36E71C7 + + + destinationuid + 528C59BE-0DAD-4C1D-876E-09EEE2B889FA + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9653C27F-400A-4C3F-BB97-FC0C803DFEC7 + + + destinationuid + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9661EF24-91C3-44A1-9066-8E9B9817841D + + + destinationuid + 1A29820A-69D9-458F-9285-76901C21D7F4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 96995CA4-6C03-4DB7-9E8E-95AEECA4CEB5 + + + destinationuid + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9845C770-A2CC-4752-A542-D71BE1081691 + + 99E823C3-8271-4C60-B4F9-8F5F9C48F1CE + + + destinationuid + 1A2C6EE5-E029-45EE-89D0-4C6182C7E5E0 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9B1431EC-8D2F-4149-9EC0-7DBFD487D93E + + + destinationuid + 8B88B440-38F7-4EBA-9A2E-46779141C889 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9B240AE9-8584-42FE-95A9-FF0561F0508C + + + destinationuid + 383F2E0F-8A62-41E5-8575-415A9225572E + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9B2621F0-0190-4ABD-A09F-3DBF85548580 + + + destinationuid + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9E3FE06C-F5F8-41F3-A70F-B92E187EED75 + + + destinationuid + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + modifiers + 0 + modifiersubtext + + vitoclose + + + + 9F9919C7-33FD-472E-B18D-212D95BF1470 + + + destinationuid + 99E823C3-8271-4C60-B4F9-8F5F9C48F1CE + modifiers + 0 + modifiersubtext + + vitoclose + + + + A0EAB8B1-F034-490F-9534-44ADF572AF4E + + + destinationuid + F2B24FB4-386C-4562-99D2-E4162D26AB4A + modifiers + 0 + modifiersubtext + + vitoclose + + + + A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90 + + + destinationuid + 8B88B440-38F7-4EBA-9A2E-46779141C889 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A38DD404-DE03-42C2-B0CB-A37891B6F24D + + + destinationuid + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A41190FA-4B23-4908-A4B7-16A14F338C11 + + + destinationuid + 0749257A-D830-483B-9EF5-580E33C10BB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A4437594-2A54-42A1-836E-129E46F5DB47 + + + destinationuid + CF46537F-6F59-40DB-A643-72A7BB952840 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A4EEDB0D-EEB3-45CE-B8A8-1397DD905470 + + + destinationuid + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A5C6FE27-E7CE-45C4-ADB0-8B2D0CC39E99 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A5E65336-52B1-42E9-93F1-9AF3040048AC + + + destinationuid + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + modifiers + 0 + modifiersubtext + + vitoclose + + + + A6F352C0-689E-484F-8782-AC74F9EDDB75 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A76C26BD-BA48-4797-839B-BE439FF40846 + + + destinationuid + 24B8C827-75F2-4421-A412-D48782DA1DB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + A8BE6109-BCC0-4A41-9375-C1D2E3A755BD + + + destinationuid + 383F2E0F-8A62-41E5-8575-415A9225572E + modifiers + 0 + modifiersubtext + + vitoclose + + + + A8CB9AD8-402D-4DBA-B2A7-921B4F7ABE51 + + + destinationuid + 23412027-872A-4639-A9D9-DCFD8D8FF36D + modifiers + 0 + modifiersubtext + + vitoclose + + + + A9C4AD0B-3E66-42A8-B891-B57CC59396FE + + + destinationuid + 19215BE5-986E-4AC9-9166-C80872C51DBE + modifiers + 0 + modifiersubtext + + vitoclose + + + + AA5EC8E7-EFB2-4194-9412-B562C202A977 + + + destinationuid + E81FC8A2-529A-4350-9734-0AEE58EB8D95 + modifiers + 0 + modifiersubtext + + vitoclose + + + + ABCF2AB0-D1EC-48B5-8BBB-3BA51EF2F55A + + + destinationuid + 98123379-ADC9-4377-9F28-DF79E01715D1 + modifiers + 0 + modifiersubtext + + vitoclose + + + + AC236315-8CDE-41E3-A9BA-BB59D292FE14 + + + destinationuid + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + modifiers + 0 + modifiersubtext + + vitoclose + + + + AE6160D1-56EA-4416-991E-CF12B874FFD3 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B23712E3-4564-4668-BD6D-4D535839CC8C + + + destinationuid + F2B24FB4-386C-4562-99D2-E4162D26AB4A + modifiers + 0 + modifiersubtext + + vitoclose + + + + B2454113-3905-495E-B8E0-0E25AC384525 + + + destinationuid + DADFE8E3-A419-4AE9-84E0-322B797F8F98 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B2A423FC-AF28-40F1-8BAF-CC7A29B86788 + + + destinationuid + D90DC148-3BE8-4D4E-B144-C0B5A625D4C5 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B2B50FA2-E3B9-43C3-AC33-754811E3CAC3 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B77F5F98-C065-49A4-BBB1-68ADADDD8E7D + + + destinationuid + 23412027-872A-4639-A9D9-DCFD8D8FF36D + modifiers + 0 + modifiersubtext + + vitoclose + + + + B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B91D4F9A-DEA5-426E-B984-372482E03125 + + + destinationuid + E81FC8A2-529A-4350-9734-0AEE58EB8D95 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B953E1B7-2F6E-4E88-A66B-5F12999EE0E2 + + + destinationuid + E049B90B-F4AC-475E-A20A-82083E709F11 + modifiers + 0 + modifiersubtext + + vitoclose + + + + BA289B3E-779E-482F-AFEA-8E1395513365 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + BC488027-E76B-43A7-B414-C7FAA9CF9995 + + + destinationuid + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + modifiers + 0 + modifiersubtext + + vitoclose + + + + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + + BD255BDB-07A5-4EE9-858F-A58C6207D191 + + + destinationuid + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + modifiers + 0 + modifiersubtext + + vitoclose + + + + BE8BE3CE-9515-4294-9F4B-CA2F079A0A90 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C032FA5B-9A40-4D07-8D22-4951FC736C88 + + + destinationuid + 78C0F9B3-408C-43E4-BC40-86523A54AFDA + modifiers + 0 + modifiersubtext + + vitoclose + + + + C10A975C-0DAE-4A45-AEAB-4E07CF125703 + + + destinationuid + 2609AC90-5B4D-4043-8F13-D5187B14833F + modifiers + 0 + modifiersubtext + + vitoclose + + + + C208E6CD-E56A-4223-BF05-3B90DEC14483 + + + destinationuid + 68A6C7CD-CB82-4A31-A935-E38F8E414772 + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + C9ACB578-CE2A-492F-84CA-CFCA5E528458 + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + 8347A3BC-6F50-447F-84B3-3497D4BF720D + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + B2A423FC-AF28-40F1-8BAF-CC7A29B86788 + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + 1B841176-1A95-46BD-8123-583075FAB8E4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + destinationuid + F23EB343-6D1D-4D17-9CCC-465756A5F513 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C2B88645-70FA-454D-8237-1AC8812CB059 + + + destinationuid + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + modifiers + 0 + modifiersubtext + + vitoclose + + + + C2D3F56B-0B41-4305-8D17-5B95EFDB8F06 + + + destinationuid + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + modifiers + 0 + modifiersubtext + + vitoclose + + + + C323BECC-0183-4562-B817-65624E13B3F3 + + + destinationuid + 6FEAFE02-DF77-4F58-9305-651E6D627144 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C40074F8-D8EC-4270-AE0C-05A98F3E2DCD + + + destinationuid + C208E6CD-E56A-4223-BF05-3B90DEC14483 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C588A188-D8D3-450F-9020-5EBB563F6B8A + + + destinationuid + CF46537F-6F59-40DB-A643-72A7BB952840 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C7A836E4-009F-4028-A233-561002F90337 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C7CFF014-DBC8-4663-A0AB-219C57A427EE + + + destinationuid + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C8B5A68F-5328-48B7-84C1-E73601716B7E + + + destinationuid + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + modifiers + 0 + modifiersubtext + + vitoclose + + + + C93B7A2B-9105-4456-997A-1BCC4EDA5A27 + + + destinationuid + 2609AC90-5B4D-4043-8F13-D5187B14833F + modifiers + 0 + modifiersubtext + + vitoclose + + + + C9ACB578-CE2A-492F-84CA-CFCA5E528458 + + + destinationuid + 479B0769-F60E-4F2B-A2A6-BA361F3B0BF2 + modifiers + 0 + modifiersubtext + + vitoclose + + + + CD9D3654-8137-49B2-80DC-095E97A58E67 + + + destinationuid + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + modifiers + 0 + modifiersubtext + + vitoclose + + + + CEA89051-EDDB-4FBB-9BE7-F7FF7B6B8B27 + + + destinationuid + E3BCC85B-A326-41C9-BAC9-623BE1865375 + modifiers + 0 + modifiersubtext + + vitoclose + + + + CEF36AB9-7CC2-4765-BF84-751E88B69023 + + + destinationuid + 5F3AF2C8-064F-4C10-8D99-22E212825BFE + modifiers + 0 + modifiersubtext + + vitoclose + + + + D165D8EC-3FB4-4758-8760-AEDA9BEBC727 + + + destinationuid + 2609AC90-5B4D-4043-8F13-D5187B14833F + modifiers + 0 + modifiersubtext + + vitoclose + + + + D31A5001-4590-418E-9AB0-6183E75E59DE + + + destinationuid + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + modifiers + 0 + modifiersubtext + + vitoclose + + + + D433D376-C21C-4A96-9CDF-1FA402D74249 + + + destinationuid + 899AC4D2-88FA-474F-A075-AFA12F361E2B + modifiers + 0 + modifiersubtext + + vitoclose + + + + D4442911-E17B-49CC-8F7F-EAC1830B11CD + + + destinationuid + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + modifiers + 0 + modifiersubtext + + vitoclose + + + + D54F6237-A9E0-4E1D-912B-5970380FD2C7 + + + destinationuid + 24B8C827-75F2-4421-A412-D48782DA1DB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + D781BC43-654A-4261-A7E4-648287517182 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + D8C53798-B7E2-4A51-AC12-37FEBDB624E0 + + + destinationuid + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + modifiers + 0 + modifiersubtext + + vitoclose + + + + D90DC148-3BE8-4D4E-B144-C0B5A625D4C5 + + + destinationuid + B5D85A55-8E85-4B14-81EF-0656DC5E7594 + modifiers + 0 + modifiersubtext + + vitoclose + + + + D9BCA226-6F66-4A41-A8BE-19E9D6343941 + + + destinationuid + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + modifiers + 0 + modifiersubtext + + vitoclose + + + + DA2F787C-11F7-4C7A-B275-A4CFFE171012 + + + destinationuid + 9D647271-3601-4788-9E1F-F299FA7A39BD + modifiers + 0 + modifiersubtext + + vitoclose + + + + DADFE8E3-A419-4AE9-84E0-322B797F8F98 + + + destinationuid + 71AACE30-7E8D-4D3C-8BD1-F98FEE578AEC + modifiers + 0 + modifiersubtext + + vitoclose + + + + DAE270E5-CA94-4F36-99FE-D8EC996608C0 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + DC403223-17FA-466B-9488-7292DA9D8223 + + + destinationuid + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + DC678CF5-D8B2-4508-A2FA-CB0F0E253108 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + DD0755A4-3C70-467C-A005-11F10E23CEF0 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + DD89687E-99D0-4A06-9965-86C62CB2AC5C + + + destinationuid + 6FEAFE02-DF77-4F58-9305-651E6D627144 + modifiers + 0 + modifiersubtext + + vitoclose + + + + E241B5C1-14A9-4D50-AD12-22033C647C44 + + + destinationuid + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + modifiers + 0 + modifiersubtext + + vitoclose + + + + E45DF42A-58A9-4069-A410-EC2BBC8A0575 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A + + + destinationuid + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + modifiers + 0 + modifiersubtext + + vitoclose + + + + E63EB492-FCE2-42A1-BD38-7EFE4EA77473 + + + destinationuid + 64953E09-D9D0-485B-B92B-79E7FEC15927 + modifiers + 0 + modifiersubtext + + vitoclose + + + + E6CEF7D4-CFA9-4608-A188-65B33A602BAF + + + destinationuid + E049B90B-F4AC-475E-A20A-82083E709F11 + modifiers + 0 + modifiersubtext + + vitoclose + + + + EA03C1F5-912A-4422-B766-2BBC94DC0344 + + + destinationuid + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + modifiers + 0 + modifiersubtext + + vitoclose + + + + EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E + + + destinationuid + 8B88B440-38F7-4EBA-9A2E-46779141C889 + modifiers + 0 + modifiersubtext + + vitoclose + + + + EBE3B702-B0E0-4AAC-AB87-623064F9D06D + + + destinationuid + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + EBF5CCE5-EB7F-485A-AC1D-A6A558B6A318 + + + destinationuid + 9D647271-3601-4788-9E1F-F299FA7A39BD + modifiers + 0 + modifiersubtext + + vitoclose + + + + EC1183BF-4D79-4AA1-9B58-E69CBC467069 + + + destinationuid + 24B8C827-75F2-4421-A412-D48782DA1DB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + ECC53637-75AD-4FD2-9605-8E038D04C4BF + + F0ED23FA-8524-4769-B610-828611958D6A + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + F1A83FA9-AEB1-4136-BA2C-6BA9615A1E6B + + + destinationuid + 0E45EEB7-EA6D-4E6F-8655-98731989AEE0 + modifiers + 0 + modifiersubtext + + vitoclose + + + + F23EB343-6D1D-4D17-9CCC-465756A5F513 + + + destinationuid + 8B3222AF-02D9-4F13-9F79-6C4A935FD76F + modifiers + 0 + modifiersubtext + + vitoclose + + + + F2E78D71-0765-466D-9143-176361994982 + + + destinationuid + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + modifiers + 0 + modifiersubtext + + vitoclose + + + + F4382654-9318-4849-82E4-550AC235148C + + + destinationuid + 24B8C827-75F2-4421-A412-D48782DA1DB8 + modifiers + 0 + modifiersubtext + + vitoclose + + + + F4F5AC18-3C04-4673-9CC3-E563094C9446 + + + destinationuid + E3BCC85B-A326-41C9-BAC9-623BE1865375 + modifiers + 0 + modifiersubtext + + vitoclose + + + + F71F1D16-0DF9-4590-9FE9-22D439FE12BB + + + destinationuid + A2C8ACBA-F98F-457A-90E8-11BA2112342C + modifiers + 0 + modifiersubtext + + vitoclose + + + + F89879E2-9D98-43EC-802B-76AA64EF0050 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + FAA5FC99-7909-45B6-9BF0-7601DBAADC4F + + + destinationuid + 6FEAFE02-DF77-4F58-9305-651E6D627144 + modifiers + 0 + modifiersubtext + + vitoclose + + + + FD282800-1267-4ACF-BF0D-C42758D49623 + + + destinationuid + 18496AC4-EA42-444C-A906-642E38259C96 + modifiers + 0 + modifiersubtext + + vitoclose + + + + FE00C128-31CE-4143-A647-1F1623539743 + + + destinationuid + 450CD09C-F6EB-4270-8FEE-C1E33586165F + modifiers + 0 + modifiersubtext + + vitoclose + + + + + createdby + vdesabou + description + Control your Spotify library at your fingertips + disabled + + name + Spotify Mini Player + objects + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.show + triggername + Show Workflow + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 39A1935A-37F5-49FA-A860-BCF7765A8C65 + version + 1 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 5F3AF2C8-064F-4C10-8D99-22E212825BFE + version + 2 + + + config + + triggerid + spot_mini + + type + alfred.workflow.trigger.external + uid + F89879E2-9D98-43EC-802B-76AA64EF0050 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + AE6160D1-56EA-4416-991E-CF12B874FFD3 + version + 2 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Settings▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedApps + + com.sublimetext.3 + + relatedAppsMode + 2 + + type + alfred.workflow.trigger.hotkey + uid + A5C6FE27-E7CE-45C4-ADB0-8B2D0CC39E99 + version + 2 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "ALBUM" "" >> "$alfred_workflow_cache/action.log" 2>&1 + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 8DF18F9A-B3A5-4B14-8360-AD850CF5C143 + version + 2 + + + config + + argument + ✧Settings▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.settings + triggername + Show Settings + workflowonly + + + type + alfred.workflow.trigger.remote + uid + DD0755A4-3C70-467C-A005-11F10E23CEF0 + version + 1 + + + config + + alfredfiltersresults + + alfredfiltersresultsmatchmode + 0 + argumenttrimmode + 0 + argumenttype + 1 + escaping + 38 + keyword + {var:c_spot_mini} + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 2 + runningsubtext + Wait for it... + script + php -n -f ./src/main.php -- "{query}" + scriptargtype + 0 + scriptfile + + subtext + Search in your playlists for tracks, artists, and albums + title + Spotify Mini Player + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 18496AC4-EA42-444C-A906-642E38259C96 + version + 2 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "ARTIST_OR_PLAYLIST_PRIVACY" "" >> "$alfred_workflow_cache/action.log" 2>&1 + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 9845C770-A2CC-4752-A542-D71BE1081691 + version + 2 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Playlist▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedApps + + com.sublimetext.3 + + relatedAppsMode + 2 + + type + alfred.workflow.trigger.hotkey + uid + DAE270E5-CA94-4F36-99FE-D8EC996608C0 + version + 2 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "ALBUM_OR_PLAYLIST" "ADDTOPLAYLIST" >> "$alfred_workflow_cache/action.log" 2>&1 + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 1A88766E-BF4A-48F5-9BD4-D3538634422F + version + 2 + + + config + + argument + ✧Playlist▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.playlists + triggername + Show Playlists + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4 + version + 1 + + + config + + triggerid + show_settings + + type + alfred.workflow.trigger.external + uid + 401D4FC7-21EC-47C3-9896-FCD97C8563F4 + version + 1 + + + config + + argument + ✧Settings▹ + variables + + + type + alfred.workflow.utility.argument + uid + FD282800-1267-4ACF-BF0D-C42758D49623 + version + 1 + + + config + + argument + ✧Spotify Connect▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.connect + triggername + Show Connect + workflowonly + + + type + alfred.workflow.trigger.remote + uid + B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F + version + 1 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "TRACK" "ADDTOPLAYLIST" >> "$alfred_workflow_cache/action.log" 2>&1 + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 7918E8F7-20AE-445E-9AEA-E2E54CDE967D + version + 2 + + + config + + triggerid + show_playlists + + type + alfred.workflow.trigger.external + uid + 1A88C8F9-C6E3-42C9-98A5-E277B97690B0 + version + 1 + + + config + + argument + ✧Playlist▹ + variables + + + type + alfred.workflow.utility.argument + uid + 6008947F-A428-45E7-8B9C-1F3402278D3A + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Spotify Connect▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + BE8BE3CE-9515-4294-9F4B-CA2F079A0A90 + version + 2 + + + config + + triggerid + show_current_track + + type + alfred.workflow.trigger.external + uid + 8D9D70BD-782D-421A-926F-7EBC18085CE9 + version + 1 + + + config + + concurrently + + escaping + 38 + script + php -f ./src/action.php -- "{query}" "ONLINE" "" >> "$alfred_workflow_cache/action.log" 2>&1 + + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 5F5E8A6D-8707-41FC-B5D1-660CD11685F0 + version + 2 + + + config + + argument + ✧Current Track▹ + variables + + + type + alfred.workflow.utility.argument + uid + 4FB4D3A4-9DA1-4369-99D1-664AE2685C27 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Current Track▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedApps + + com.sublimetext.3 + + relatedAppsMode + 2 + + type + alfred.workflow.trigger.hotkey + uid + 0C74516A-D95D-4379-94B6-CD984A31A003 + version + 2 + + + config + + triggerid + show_recent_tracks + + type + alfred.workflow.trigger.external + uid + 062BBC6A-8B21-4777-8580-5CAE8506A859 + version + 1 + + + config + + argument + Recent Tracks▹ + variables + + + type + alfred.workflow.utility.argument + uid + B2B50FA2-E3B9-43C3-AC33-754811E3CAC3 + version + 1 + + + config + + argument + ✧Current Track▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.currenttrack + triggername + Show Current Track + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 3040749D-6B5C-4CCD-AF95-AEC0F83B48D9 + version + 1 + + + config + + triggerid + show_new_releases + + type + alfred.workflow.trigger.external + uid + 55288BC7-DEF9-4B85-BB03-274A7322F31A + version + 1 + + + config + + argument + ✧New Releases▹ + variables + + + type + alfred.workflow.utility.argument + uid + 7351C6F1-1AB2-42D0-9003-5FFECFDEB441 + version + 1 + + + config + + argument + Recent Tracks▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.recenttrack + triggername + Show Recent Tracks + workflowonly + + + type + alfred.workflow.trigger.remote + uid + F0ED23FA-8524-4769-B610-828611958D6A + version + 1 + + + config + + triggerid + show_search_online + + type + alfred.workflow.trigger.external + uid + 36FF7DE6-29DF-4E25-8E15-58411CE75638 + version + 1 + + + config + + argument + ✧Search Online▹ + variables + + + type + alfred.workflow.utility.argument + uid + 2B1BF20E-C892-4340-ABFE-AFA4AF7F8C52 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + Recent Tracks▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 8A63B1A6-0F0E-481A-9312-C75557A9DA71 + version + 2 + + + config + + triggerid + show_play_queue + + type + alfred.workflow.trigger.external + uid + 57B3B398-989F-42FF-B449-281E41BB0851 + version + 1 + + + config + + argument + ✧New Releases▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.shownewreleases + triggername + Show New Releases + workflowonly + + + type + alfred.workflow.trigger.remote + uid + E45DF42A-58A9-4069-A410-EC2BBC8A0575 + version + 1 + + + config + + argument + ✧Play Queue▹ + variables + + + type + alfred.workflow.utility.argument + uid + 2EC684F9-F50A-4300-9421-FF3B95CF2CC1 + version + 1 + + + config + + triggerid + show_browse + + type + alfred.workflow.trigger.external + uid + 6E7EAD8C-4207-4393-8091-D7EC5ED9A654 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧New Releases▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 7934F80C-2281-449C-9A89-7BC422D659D7 + version + 2 + + + config + + argument + ✧Browse▹ + variables + + + type + alfred.workflow.utility.argument + uid + 6EC5159F-1577-4384-9869-4777146F362E + version + 1 + + + config + + triggerid + show_connect + + type + alfred.workflow.trigger.external + uid + 318D20CD-D753-4CCC-B931-BB3CFC6A1D0A + version + 1 + + + config + + argument + ✧Search Online▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.showsearchonline + triggername + Show Search Online + workflowonly + + + type + alfred.workflow.trigger.remote + uid + DC678CF5-D8B2-4508-A2FA-CB0F0E253108 + version + 1 + + + config + + argument + ✧Spotify Connect▹ + variables + + + type + alfred.workflow.utility.argument + uid + C7A836E4-009F-4028-A233-561002F90337 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Search Online▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedApps + + com.sublimetext.3 + + relatedAppsMode + 2 + + type + alfred.workflow.trigger.hotkey + uid + 73FB3971-4382-45F5-ADED-F1E481A95E2E + version + 2 + + + config + + argument + ✧Play Queue▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.showplayqueue + triggername + Show Play Queue + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 3617F927-558D-4F30-B8D1-B7789F863AB0 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Play Queue▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedApps + + com.sublimetext.3 + + relatedAppsMode + 1 + + type + alfred.workflow.trigger.hotkey + uid + A6F352C0-689E-484F-8782-AC74F9EDDB75 + version + 2 + + + config + + alfredfiltersresults + + alfredfiltersresultsmatchmode + 0 + argumenttrimmode + 0 + argumenttype + 1 + escaping + 38 + keyword + {var:c_spot_mini_debug} + queuedelaycustom + 1 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + Wait for it... + script + php -f ./src/debug.php -- "{query}" + scriptargtype + 0 + scriptfile + + subtext + Please send the generated zip file to the workflow author + title + Debug tools for Spotify Mini Player + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + CEF36AB9-7CC2-4765-BF84-751E88B69023 + version + 2 + + + config + + argument + ✧Browse▹ + argumenttype + 3 + triggerid + com.vdesabou.miniplayer.showbrowse + triggername + Show Browse + workflowonly + + + type + alfred.workflow.trigger.remote + uid + BA289B3E-779E-482F-AFEA-8E1395513365 + version + 1 + + + config + + triggerid + spot_mini_debug + + type + alfred.workflow.trigger.external + uid + 327849A3-A34A-46BA-AC04-1F5115824DC3 + version + 1 + + + config + + text + Search Spotify Mini Player for '{query}' + + type + alfred.workflow.trigger.fallback + uid + D781BC43-654A-4261-A7E4-648287517182 + version + 1 + + + config + + action + 0 + argument + 3 + argumenttext + ✧Browse▹ + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 2 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 6BC60709-1E24-4297-A9CB-3B99581AF0C6 + version + 2 + + + config + + triggerid + volume_up + + type + alfred.workflow.trigger.external + uid + C2B88645-70FA-454D-8237-1AC8812CB059 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.debug + triggername + Debug + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 873EF61A-BD03-4946-87B0-C7AE5DFC5E5B + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.volumeup + triggername + Volume Up + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 1BA522F3-B2D0-4F36-B86C-738FB3AC55DD + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + C8B5A68F-5328-48B7-84C1-E73601716B7E + version + 2 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "volume_up" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_volume_up} + subtext + Increase Spotify Volume + text + Volume Up + withspace + + + type + alfred.workflow.input.keyword + uid + D4442911-E17B-49CC-8F7F-EAC1830B11CD + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 3AA52DF5-6A73-4739-A088-0F78F446B447 + version + 2 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "volume_down" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_volume_down} + subtext + Decrease Spotify Volume + text + Volume Down + withspace + + + type + alfred.workflow.input.keyword + uid + 7FF09231-F068-4EA0-8537-6C1EB608CA5A + version + 1 + + + config + + triggerid + volume_down + + type + alfred.workflow.trigger.external + uid + F2E78D71-0765-466D-9143-176361994982 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.volumedown + triggername + Volume Down + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5 + version + 1 + + + config + + argumenttype + 2 + keyword + random + subtext + Play random track + text + Random Track + withspace + + + type + alfred.workflow.input.keyword + uid + 8C78472B-13EB-4512-B94D-4BF92867CD92 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "random" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.random + triggername + Random Track + workflowonly + + + type + alfred.workflow.trigger.remote + uid + BC488027-E76B-43A7-B414-C7FAA9CF9995 + version + 1 + + + config + + triggerid + random_track + + type + alfred.workflow.trigger.external + uid + 7F15B183-963C-4EE1-9B19-10705529BF0B + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 80B80179-E286-4D4A-9FEC-FCBE63AD8AEE + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_add_current_track_to_alfred_playlist_or_your_music} + subtext + Current track will be added to Alfred Playlist or Your Music + text + Add current track to Alfred Playlist or Your Music + withspace + + + type + alfred.workflow.input.keyword + uid + 3F85747B-FC44-4B07-AA6E-3645F0CC0DF7 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "add_current_track" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + ECC53637-75AD-4FD2-9605-8E038D04C4BF + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.addcurrenttrack + triggername + Add track to AP or Your Music + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 5EB4A672-01BC-4DBB-AD39-60EBB0F79A67 + version + 1 + + + config + + triggerid + add_current_track_to_alfred_playlist_or_your_music + + type + alfred.workflow.trigger.external + uid + 85966031-0B63-4629-BF2A-CAE7C92FCDD6 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 3837382F-63B4-4B0D-A880-A1CF7079D584 + version + 2 + + + config + + triggerid + pause + + type + alfred.workflow.trigger.external + uid + EC1183BF-4D79-4AA1-9B58-E69CBC467069 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + D54F6237-A9E0-4E1D-912B-5970380FD2C7 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_pause} + subtext + Pause the current Spotify track + text + Pause + withspace + + + type + alfred.workflow.input.keyword + uid + F4382654-9318-4849-82E4-550AC235148C + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "pause" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 24B8C827-75F2-4421-A412-D48782DA1DB8 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.pause + triggername + Pause + workflowonly + + + type + alfred.workflow.trigger.remote + uid + A76C26BD-BA48-4797-839B-BE439FF40846 + version + 1 + + + config + + triggerid + play + + type + alfred.workflow.trigger.external + uid + ABCF2AB0-D1EC-48B5-8BBB-3BA51EF2F55A + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.play + triggername + Play + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "play" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "{query}" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 98123379-ADC9-4377-9F28-DF79E01715D1 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_play} + subtext + Play the current Spotify track + text + Play + withspace + + + type + alfred.workflow.input.keyword + uid + 5AF7EEEC-2E55-482C-8750-4CE6AD752683 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 69E43FC9-457E-4082-8930-A1B00B6A5514 + version + 2 + + + config + + alfredfiltersresults + + alfredfiltersresultsmatchmode + 0 + argumenttrimmode + 0 + argumenttype + 2 + escaping + 68 + keyword + {var:c_shuffle} + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + + script + result=$(php -r "require './src/functions.php'; isShuffleActive(true);") + + +if [ $result == "true" ] + then cat << EOB +{ + + + +"items": [ + { + "title": "Shuffle is activated", + "subtitle": "Type enter to deactivate shuffle", + "icon": { + "path": "images/shuffle.png" + } + } + +]} +EOB +fi +if [ $result == "false" ] + then cat << EOB +{ + + + +"items": [ + { + "title": "Shuffle is deactivated", + "subtitle": "Type enter to activate shuffle", + "icon": { + "path": "images/shuffle.png" + } + } + +]} +EOB +fi + +echo -n $query + scriptargtype + 1 + scriptfile + + subtext + Activate/Deactivate shuffling in Spotify + title + Shuffle + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + BD255BDB-07A5-4EE9-858F-A58C6207D191 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.shuffle + triggername + Activate Shuffle + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 89BC46B4-E178-4855-8863-393730814F6E + version + 1 + + + config + + triggerid + shuffle + + type + alfred.workflow.trigger.external + uid + 5372B0DF-11F6-41D9-8E6C-ED8C2A7EBE70 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "shuffle" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + A4EEDB0D-EEB3-45CE-B8A8-1397DD905470 + version + 2 + + + config + + triggerid + previous + + type + alfred.workflow.trigger.external + uid + 60F15971-216E-4921-8A56-C6B992D25B08 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + E241B5C1-14A9-4D50-AD12-22033C647C44 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_previous} + subtext + Play the previous track in Spotify + text + Previous Track + withspace + + + type + alfred.workflow.input.keyword + uid + CD9D3654-8137-49B2-80DC-095E97A58E67 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "previous" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.previous + triggername + Previous Track + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 66F8A022-163E-42CB-A9E9-B32E8158ACA7 + version + 1 + + + config + + triggerid + next + + type + alfred.workflow.trigger.external + uid + 6965EC4E-AE6C-40BD-A3B5-CD316812BF30 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + E63EB492-FCE2-42A1-BD38-7EFE4EA77473 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_next} + subtext + Play the next track in Spotify + text + Next Track + withspace + + + type + alfred.workflow.input.keyword + uid + 4EB5FB5E-6472-4757-A479-B206B6080036 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "next" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 64953E09-D9D0-485B-B92B-79E7FEC15927 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.next + triggername + Next Track + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 8339BE15-274E-4A77-A6A0-CEDF30EFD0E5 + version + 1 + + + config + + triggerid + display_current_track_notification + + type + alfred.workflow.trigger.external + uid + 89D8799A-D22A-4A6D-B43D-50B9EADB879D + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.current + triggername + Current Track Info + workflowonly + + + type + alfred.workflow.trigger.remote + uid + DC403223-17FA-466B-9488-7292DA9D8223 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "current" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "{query}" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_current} + subtext + Get current track information + text + Get Current Track info + withspace + + + type + alfred.workflow.input.keyword + uid + A38DD404-DE03-42C2-B0CB-A37891B6F24D + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + EBE3B702-B0E0-4AAC-AB87-623064F9D06D + version + 2 + + + config + + triggerid + lyrics + + type + alfred.workflow.trigger.external + uid + A5E65336-52B1-42E9-93F1-9AF3040048AC + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.lyrics + triggername + Lyrics + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 16F5C3BF-01EE-493C-9E7B-CC54D482B7A6 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_lyrics} + subtext + Get current track lyrics + text + Get Lyrics for current track + withspace + + + type + alfred.workflow.input.keyword + uid + AC236315-8CDE-41E3-A9BA-BB59D292FE14 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "lyrics" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 6FDBF98C-ACD5-49F8-B1FD-04B79FA04E29 + version + 2 + + + config + + triggerid + artist_radio + + type + alfred.workflow.trigger.external + uid + D165D8EC-3FB4-4758-8760-AEDA9BEBC727 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.artistradio + triggername + Create Artist Radio + workflowonly + + + type + alfred.workflow.trigger.remote + uid + C10A975C-0DAE-4A45-AEAB-4E07CF125703 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_artist_radio} + subtext + Create artist radio playlist + text + Create artist radio playlist for current artist + withspace + + + type + alfred.workflow.input.keyword + uid + C93B7A2B-9105-4456-997A-1BCC4EDA5A27 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "current_artist_radio" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 2609AC90-5B4D-4043-8F13-D5187B14833F + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 175EB434-B9E1-4C6F-85B0-B0A3436E7E40 + version + 2 + + + config + + triggerid + song_radio + + type + alfred.workflow.trigger.external + uid + 024D6172-912E-4EAE-92AA-776626D52FFB + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.songadio + triggername + Create Song Radio + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 8598A5C9-72B6-4CEF-A498-D6C2ED06DC88 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_song_radio} + subtext + Create song radio playlist + text + Create song radio playlist for current track + withspace + + + type + alfred.workflow.input.keyword + uid + 455BDE70-BCF4-447F-ABFF-C25D8E5B08B6 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "current_track_radio" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 78DD84AE-70E9-4DB5-BF2B-44BC774B4383 + version + 2 + + + config + + triggerid + spot_mini_reset_settings + + type + alfred.workflow.trigger.external + uid + 2E15D453-FA20-483A-AAA3-59FF33614829 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_spot_mini_reset_settings} + subtext + The authentication will have to be done again + text + Reset settings for Spotify Mini Player + withspace + + + type + alfred.workflow.input.keyword + uid + B23712E3-4564-4668-BD6D-4D535839CC8C + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "reset_settings" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + F2B24FB4-386C-4562-99D2-E4162D26AB4A + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.reset + triggername + Reset Settings + workflowonly + + + type + alfred.workflow.trigger.remote + uid + A0EAB8B1-F034-490F-9534-44ADF572AF4E + version + 1 + + + config + + triggerid + spot_mini_kill + + type + alfred.workflow.trigger.external + uid + A9C4AD0B-3E66-42A8-B891-B57CC59396FE + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_spot_mini_kill} + subtext + use it if the library update seems stuck + text + Kill update library + withspace + + + type + alfred.workflow.input.keyword + uid + 05F86AA1-D3EE-4409-9A58-898B36FFE503 + version + 1 + + + config + + concurrently + + escaping + 127 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "kill_update" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 19215BE5-986E-4AC9-9166-C80872C51DBE + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.refreshlibrary + triggername + Refresh Library + workflowonly + + + type + alfred.workflow.trigger.remote + uid + C588A188-D8D3-450F-9020-5EBB563F6B8A + version + 1 + + + config + + triggerid + refresh_library + + type + alfred.workflow.trigger.external + uid + A4437594-2A54-42A1-836E-129E46F5DB47 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "refresh_library" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + CF46537F-6F59-40DB-A643-72A7BB952840 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_refresh_library} + subtext + This will refresh the library + text + Refresh Spotify Mini Player library + withspace + + + type + alfred.workflow.input.keyword + uid + 2B0C8466-4AED-4272-9C10-50F3BCE88043 + version + 1 + + + config + + triggerid + play_artist + + type + alfred.workflow.trigger.external + uid + 70C9B5C9-72DA-409A-B3EC-8C2DC0EE9627 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.playartist + triggername + Play Artist + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 9661EF24-91C3-44A1-9066-8E9B9817841D + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "play_current_artist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 1A29820A-69D9-458F-9285-76901C21D7F4 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_play_artist} + subtext + Play the current artist + text + Play current artist + withspace + + + type + alfred.workflow.input.keyword + uid + 0B75CF43-8B04-405F-86C3-2FFC59AC4A70 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 66A0F734-983C-420D-B6E4-F21922513E4B + version + 2 + + + config + + triggerid + play_album + + type + alfred.workflow.trigger.external + uid + A8CB9AD8-402D-4DBA-B2A7-921B4F7ABE51 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.playalbum + triggername + Play Album + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 2FC567E2-E6C5-4A91-B42E-1996532B78C9 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_play_album} + subtext + Play the current album + text + Play current album + withspace + + + type + alfred.workflow.input.keyword + uid + B77F5F98-C065-49A4-BBB1-68ADADDD8E7D + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "play_current_album" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 23412027-872A-4639-A9D9-DCFD8D8FF36D + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 66AE01C5-E034-40D2-9CEE-69A063016B4A + version + 2 + + + config + + triggerid + play_alfred_playlist + + type + alfred.workflow.trigger.external + uid + 1059D963-473F-44F8-8D60-94CFCE56BFF2 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.playalfredplaylist + triggername + Play Alfred Playlist + workflowonly + + + type + alfred.workflow.trigger.remote + uid + A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_play_alfred_playlist} + subtext + This will launch your Alfred Playlist + text + Play Alfred Playlist + withspace + + + type + alfred.workflow.input.keyword + uid + EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "play_alfred_playlist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 8B88B440-38F7-4EBA-9A2E-46779141C889 + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 9B1431EC-8D2F-4149-9EC0-7DBFD487D93E + version + 2 + + + config + + triggerid + spot_mini_issue + + type + alfred.workflow.trigger.external + uid + D433D376-C21C-4A96-9CDF-1FA402D74249 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_spot_mini_issue} + subtext + This will open the GitHub page + text + Report an issue or propose an enhancement + withspace + + + type + alfred.workflow.input.keyword + uid + 794A76A7-BB98-4A83-92BE-386A56875120 + version + 1 + + + config + + browser + + spaces + + url + https://github.com/vdesabou/alfred-spotify-mini-player/issues/new + utf8 + + + type + alfred.workflow.action.openurl + uid + 899AC4D2-88FA-474F-A075-AFA12F361E2B + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.issue + triggername + Report Issue + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 8F478980-199B-45B5-AD41-EBA185446705 + version + 1 + + + config + + triggerid + add_current_track_to + + type + alfred.workflow.trigger.external + uid + CEA89051-EDDB-4FBB-9BE7-F7FF7B6B8B27 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.addcurrenttrackto + triggername + Add track to... + workflowonly + + + type + alfred.workflow.trigger.remote + uid + F4F5AC18-3C04-4673-9CC3-E563094C9446 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "add_current_track_to" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "{query}" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + E3BCC85B-A326-41C9-BAC9-623BE1865375 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_add_current_track_to} + subtext + Current track will be added to Your Music or a chosen playlist + text + Add current track to ... + withspace + + + type + alfred.workflow.input.keyword + uid + 7FE5D993-C14D-4B94-9479-B361680F1C40 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 5BB099A1-224D-4702-BBBC-52919BDCCF62 + version + 2 + + + config + + triggerid + lookup_artist_online + + type + alfred.workflow.trigger.external + uid + 75E489FD-ADF2-4A30-A432-61E53BF36A00 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.lookupcurrentartist + triggername + Lookup Artist Online + workflowonly + + + type + alfred.workflow.trigger.remote + uid + D8C53798-B7E2-4A51-AC12-37FEBDB624E0 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "lookup_current_artist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_lookup_artist_online} + subtext + ☁︎ Query all albums/tracks from this artist online.. + text + Lookup Current Artist online + withspace + + + type + alfred.workflow.input.keyword + uid + 552D77E3-1550-4035-AB49-8B708B081EC9 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + C2D3F56B-0B41-4305-8D17-5B95EFDB8F06 + version + 2 + + + config + + concurrently + + escaping + 127 + script + tell application "System Events" + key code 74 -- escape +end tell + scriptargtype + 0 + scriptfile + + type + 6 + + type + alfred.workflow.action.script + uid + 25E3EBDF-2CFA-4599-A13B-8C63B3E5329A + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.keyescape + triggername + Key Escape + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 450AEF8B-BDAA-409C-A0D4-68769545FBCF + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.keyenter + triggername + Key Enter + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A + version + 1 + + + config + + concurrently + + escaping + 127 + script + tell application "System Events" + key code 36 -- enter +end tell + scriptargtype + 0 + scriptfile + + type + 6 + + type + alfred.workflow.action.script + uid + E59E23E2-837A-4B48-949A-A9EE059186C1 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.keydown + triggername + Key Down + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 303A65BF-8E81-48E8-AA28-E1CA408FDD53 + version + 1 + + + config + + concurrently + + escaping + 127 + script + tell application "System Events" + key code 125 -- down +end tell + scriptargtype + 0 + scriptfile + + type + 6 + + type + alfred.workflow.action.script + uid + 13367FE5-35F7-4B94-8728-CF6F3D9F4C2B + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.keyup + triggername + Key Up + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0 + version + 1 + + + config + + concurrently + + escaping + 127 + script + tell application "System Events" + key code 126 -- up +end tell + scriptargtype + 0 + scriptfile + + type + 6 + + type + alfred.workflow.action.script + uid + 51401C92-A6F8-4E2A-AA02-D140984EE916 + version + 2 + + + config + + triggerid + show_alfred_playlist + + type + alfred.workflow.trigger.external + uid + B953E1B7-2F6E-4E88-A66B-5F12999EE0E2 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.showalfredplaylist + triggername + Show Alfred Playlist + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 11E4CA98-E51E-45E4-91ED-72B4A1A34283 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "show_alfred_playlist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + E049B90B-F4AC-475E-A20A-82083E709F11 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_show_alfred_playlist} + subtext + This will show your Alfred Playlist + text + Show Alfred Playlist + withspace + + + type + alfred.workflow.input.keyword + uid + E6CEF7D4-CFA9-4608-A188-65B33A602BAF + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 3280F15E-8C80-4A0D-8439-07A113AA1094 + version + 2 + + + config + + triggerid + remove_current_track_from + + type + alfred.workflow.trigger.external + uid + 7CD59703-7376-4695-8BC8-DBBD01EC19A6 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.removecurrenttrackfrom + triggername + Remove track from... + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 4BE9FB30-9B4F-4E44-861D-D178507A7568 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_remove_current_track_from} + subtext + Current track will be removed from Your Music or a chosen playlist + text + Remove current track from ... + withspace + + + type + alfred.workflow.input.keyword + uid + 62AA861E-C910-4354-84C9-58A5660365D8 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "remove_current_track_from" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 7E4C3B84-D930-490A-BF7E-FA5C57328897 + version + 2 + + + config + + triggerid + random_album + + type + alfred.workflow.trigger.external + uid + 3016205A-8693-421C-B3B6-3CE742806FCC + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "random_album" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_random_album} + subtext + Play random album + text + Random Album + withspace + + + type + alfred.workflow.input.keyword + uid + D31A5001-4590-418E-9AB0-6183E75E59DE + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.randomalbum + triggername + Random Album + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 9B2621F0-0190-4ABD-A09F-3DBF85548580 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 827D9590-7BA6-4E87-B288-0AF6C04C9B01 + version + 2 + + + config + + triggerid + mute + + type + alfred.workflow.trigger.external + uid + 901D4A54-195C-4D82-90C8-E3A6F6F48FC8 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_mute} + subtext + Mute/Unmute Volume + text + Mute/Unmute Spotify Volume + withspace + + + type + alfred.workflow.input.keyword + uid + C7CFF014-DBC8-4663-A0AB-219C57A427EE + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "mute" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.mute + triggername + Mute/Unmute + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 2B0C6211-1DD0-4CE6-8082-37957F15CC1D + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 96995CA4-6C03-4DB7-9E8E-95AEECA4CEB5 + version + 2 + + + config + + triggerid + playpause + + type + alfred.workflow.trigger.external + uid + 620CF52F-BCFD-4957-BC4F-1E9853125AF5 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_playpause} + subtext + Play or Pause the current Spotify track + text + Play/Pause + withspace + + + type + alfred.workflow.input.keyword + uid + 6E9B4F21-F907-4A22-8689-9A146F909454 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.playpause + triggername + Play/Pause + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "playpause" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + A2C8ACBA-F98F-457A-90E8-11BA2112342C + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + F71F1D16-0DF9-4590-9FE9-22D439FE12BB + version + 2 + + + config + + triggerid + volmax + + type + alfred.workflow.trigger.external + uid + 9B240AE9-8584-42FE-95A9-FF0561F0508C + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_volmax} + subtext + Set the Spotify volume to maximum + text + Set Spotify Volume to Maximum + withspace + + + type + alfred.workflow.input.keyword + uid + 15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "volmax" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 383F2E0F-8A62-41E5-8575-415A9225572E + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.volmax + triggername + Volume Max + workflowonly + + + type + alfred.workflow.trigger.remote + uid + A8BE6109-BCC0-4A41-9375-C1D2E3A755BD + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 817080F0-4CE8-4336-A972-550D43D063B1 + version + 2 + + + config + + triggerid + volmid + + type + alfred.workflow.trigger.external + uid + 57BD5D83-BC36-41AF-B6F7-B3289DD427CE + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_volmid} + subtext + Set the Spotify volume to Middle + text + Set Spotify Volume to Middle + withspace + + + type + alfred.workflow.input.keyword + uid + EA03C1F5-912A-4422-B766-2BBC94DC0344 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.volmid + triggername + Volume Mid + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 9E3FE06C-F5F8-41F3-A70F-B92E187EED75 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "volmid" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + D9BCA226-6F66-4A41-A8BE-19E9D6343941 + version + 2 + + + config + + triggerid + repeating + + type + alfred.workflow.trigger.external + uid + 0CAE95A9-03D6-4305-A30B-153796564AD1 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.repeating + triggername + Activate Repeating + workflowonly + + + type + alfred.workflow.trigger.remote + uid + A41190FA-4B23-4908-A4B7-16A14F338C11 + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_repeating} + subtext + Activate/Deactivate repeating in Spotify + text + Repeating + withspace + + + type + alfred.workflow.input.keyword + uid + 2F1F6369-46C0-483B-816F-3796168AE060 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "repeating" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 0749257A-D830-483B-9EF5-580E33C10BB8 + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 3435F565-E791-4FE9-A7B9-85B4A2EA353C + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.repeating.current.track + triggername + Activate Repeating Track + workflowonly + + + type + alfred.workflow.trigger.remote + uid + 81536C26-DB7C-42CE-95C0-B78FA1C7934E + version + 1 + + + config + + triggerid + repeating_current_track + + type + alfred.workflow.trigger.external + uid + 66723864-4D1C-439D-A1DE-5F90BCB03CCC + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "repeating" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "ARTIST_OR_PLAYLIST_PRIVACY" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_repeating_current_track} + subtext + Activate/Deactivate repeating current track in Spotify + text + Repeating current track (only possible when using Spotify Connect) + withspace + + + type + alfred.workflow.input.keyword + uid + 5F3F806B-0B88-4C17-92E7-72A944CEB1A6 + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 6EA904F5-F25E-4B1E-A6DD-5E94263ADBC8 + version + 2 + + + config + + triggerid + share + + type + alfred.workflow.trigger.external + uid + 1BA8D519-4B49-4BD9-B329-D004A22AE84C + version + 1 + + + config + + argumenttype + 2 + keyword + {var:c_share} + subtext + Share current track using Mac OS X Sharing + text + Share current track + withspace + + + type + alfred.workflow.input.keyword + uid + 0EBF4C61-5630-4629-8B4F-AD91D3470760 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "share" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.share + triggername + Share + workflowonly + + + type + alfred.workflow.trigger.remote + uid + E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A + version + 1 + + + config + + triggerid + web_search_current_track + + type + alfred.workflow.trigger.external + uid + DD89687E-99D0-4A06-9965-86C62CB2AC5C + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 6FEAFE02-DF77-4F58-9305-651E6D627144 + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 9653C27F-400A-4C3F-BB97-FC0C803DFEC7 + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_web_search} + subtext + You will be prompted to choose the web service you want to use + text + Do a web search for current track or artist on Youtube, Facebook, etc.. + withspace + + + type + alfred.workflow.input.keyword + uid + FAA5FC99-7909-45B6-9BF0-7601DBAADC4F + version + 1 + + + config + + triggerid + reddit_search_current_track + + type + alfred.workflow.trigger.external + uid + 090D4A5C-85C3-4083-B936-3E61ED83B1A3 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist_track" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + B91D4F9A-DEA5-426E-B984-372482E03125 + version + 2 + + + config + + browser + + spaces + %20 + url + https://www.reddit.com/search?q={query} + utf8 + + + type + alfred.workflow.action.openurl + uid + E81FC8A2-529A-4350-9734-0AEE58EB8D95 + version + 1 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1] $tmp[0]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + AA5EC8E7-EFB2-4194-9412-B562C202A977 + version + 2 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.websearch + triggername + Web Search + workflowonly + + + type + alfred.workflow.trigger.remote + uid + C323BECC-0183-4562-B817-65624E13B3F3 + version + 1 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + reddit + + type + alfred.workflow.utility.filter + uid + 68A6C7CD-CB82-4A31-A935-E38F8E414772 + version + 1 + + + config + + triggerid + soundcloud_search_current_track + + type + alfred.workflow.trigger.external + uid + 93DE48B5-E0D6-4B64-B972-D01EB36E71C7 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist_track" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 528C59BE-0DAD-4C1D-876E-09EEE2B889FA + version + 2 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 1B716436-7DCE-45DA-8567-FA157808962F + version + 2 + + + config + + browser + + spaces + %20 + url + https://soundcloud.com/search?q={query} + utf8 + + + type + alfred.workflow.action.openurl + uid + C3F966D4-D292-4B70-9024-B8788BA5488F + version + 1 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1] $tmp[0]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + 479B0769-F60E-4F2B-A2A6-BA361F3B0BF2 + version + 2 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + soundcloud + + type + alfred.workflow.utility.filter + uid + C9ACB578-CE2A-492F-84CA-CFCA5E528458 + version + 1 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1] $tmp[0]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + 7224DEC2-8842-4EF7-9D41-8996267F4231 + version + 2 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist_track" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 39C34247-AE29-43A1-879B-3965F3AAF475 + version + 2 + + + config + + triggerid + youtube_search_current_track + + type + alfred.workflow.trigger.external + uid + 30F45FDA-252D-4C22-894C-444F7E3E8E78 + version + 1 + + + config + + browser + + searcher + 1635218553 + + type + alfred.workflow.action.systemwebsearch + uid + C91B7486-D357-4C1C-8661-83290128E78E + version + 1 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + youtube + + type + alfred.workflow.utility.filter + uid + 8347A3BC-6F50-447F-84B3-3497D4BF720D + version + 1 + + + config + + argumenttrimmode + 0 + argumenttype + 2 + fixedorder + + items + [{"imagefile":"7f73299e44208b1bf3ea24353e08897cc883f3fb.png","title":"Youtube","arg":"youtube","subtitle":"Select to search current track on Youtube"},{"imagefile":"23dbf40eac5c981b0171d90427f6ba54b71239e0.png","title":"Wikipedia","arg":"wikipedia","subtitle":"Select to search current artist on Wikipedia"},{"imagefile":"82859060e592ee7da3bc7067150201773fdcfdda.png","title":"Facebook","arg":"facebook","subtitle":"Select to search current artist on Facebook"},{"imagefile":"078886c96323cf8fa4dc08c047f730f210d436c3.png","title":"Twitter","arg":"twitter","subtitle":"Select to search current artist on Twitter"},{"imagefile":"5438218af54404741e979e30029dffc8cfa027e0.png","title":"Soundcloud","arg":"soundcloud","subtitle":"Select to search current track on Soundcloud"},{"imagefile":"616d2b26fc250b4bcbabb45fab72267d90b86d5b.png","title":"Reddit","arg":"reddit","subtitle":"Select to search current track on Reddit"}] + runningsubtext + + subtext + + title + + withspace + + + type + alfred.workflow.input.listfilter + uid + C208E6CD-E56A-4223-BF05-3B90DEC14483 + version + 1 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + D90DC148-3BE8-4D4E-B144-C0B5A625D4C5 + version + 2 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 0E45EEB7-EA6D-4E6F-8655-98731989AEE0 + version + 2 + + + config + + browser + + searcher + 1635219305 + + type + alfred.workflow.action.systemwebsearch + uid + B5D85A55-8E85-4B14-81EF-0656DC5E7594 + version + 1 + + + config + + triggerid + web_search + + type + alfred.workflow.trigger.external + uid + 30833563-364F-4EC4-B467-F63A7F66EB06 + version + 1 + + + config + + triggerid + wikipedia_search_current_track + + type + alfred.workflow.trigger.external + uid + F1A83FA9-AEB1-4136-BA2C-6BA9615A1E6B + version + 1 + + + config + + argument + + variables + + web_search + {query} + + + type + alfred.workflow.utility.argument + uid + C40074F8-D8EC-4270-AE0C-05A98F3E2DCD + version + 1 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + wikipedia + + type + alfred.workflow.utility.filter + uid + B2A423FC-AF28-40F1-8BAF-CC7A29B86788 + version + 1 + + + config + + triggerid + facebook_search_current_track + + type + alfred.workflow.trigger.external + uid + B2454113-3905-495E-B8E0-0E25AC384525 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + DADFE8E3-A419-4AE9-84E0-322B797F8F98 + version + 2 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + 83FDAFA8-0D15-43B2-9CA9-E9B3459ACE5E + version + 2 + + + config + + browser + + searcher + 1635214946 + + type + alfred.workflow.action.systemwebsearch + uid + 71AACE30-7E8D-4D3C-8BD1-F98FEE578AEC + version + 1 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + facebook + + type + alfred.workflow.utility.filter + uid + 1B841176-1A95-46BD-8123-583075FAB8E4 + version + 1 + + + config + + triggerid + twitter_search_current_track + + type + alfred.workflow.trigger.external + uid + 9F9919C7-33FD-472E-B18D-212D95BF1470 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "web_search_artist" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 99E823C3-8271-4C60-B4F9-8F5F9C48F1CE + version + 2 + + + config + + concurrently + + escaping + 100 + script + <?php + +$web_search = getenv('web_search'); + +$tmp = explode('▹',$web_search); + +echo "$tmp[1]"; + +?> + scriptargtype + 1 + scriptfile + + type + 1 + + type + alfred.workflow.action.script + uid + 8B3222AF-02D9-4F13-9F79-6C4A935FD76F + version + 2 + + + config + + browser + + searcher + 1635218547 + + type + alfred.workflow.action.systemwebsearch + uid + 1A2C6EE5-E029-45EE-89D0-4C6182C7E5E0 + version + 1 + + + config + + inputstring + {query} + matchcasesensitive + + matchmode + 0 + matchstring + twitter + + type + alfred.workflow.utility.filter + uid + F23EB343-6D1D-4D17-9CCC-465756A5F513 + version + 1 + + + config + + argumenttrimmode + 0 + argumenttype + 2 + fixedorder + + items + [{"imagefile":"89d65b3654007d57567c65b8369feec3a867ab18.png","title":"Switch to black theme","arg":"black","subtitle":"Change theme to black"},{"imagefile":"17ebacf9fa9a2526eed6e79be7619d1a296f5c07.png","title":"Switch to orange theme","arg":"orange","subtitle":"Change theme to orange"},{"imagefile":"416366eee910711e509f9c7381a14729a4fec214.png","title":"Switch to pink theme","arg":"pink","subtitle":"Change theme to pink"},{"imagefile":"33a76cda76a24b29c08fa6a30b306f8d18842a69.png","title":"Switch to blue theme","arg":"blue","subtitle":"Change theme to blue"},{"imagefile":"d1502fd6b51fa78e31bd5061b9f0c368b504c617.png","title":"Switch to red theme","arg":"red","subtitle":"Change theme to red"},{"imagefile":"afb9b5f72d45346d3a11ab99023d14d3dde3eea0.png","title":"Switch to green theme","arg":"green","subtitle":"Change theme to green"},{"imagefile":"0ff3394be61c7c822d06e3228c89add5b462084f.png","title":"Switch to legacy theme","arg":"legacy","subtitle":"Change theme to legacy one"}] + runningsubtext + + subtext + + title + + withspace + + + type + alfred.workflow.input.listfilter + uid + 450CD09C-F6EB-4270-8FEE-C1E33586165F + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "change_theme_color_for_real" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + FA976637-B683-4672-837E-85462CC82B69 + version + 2 + + + config + + triggerid + change_theme_color + + type + alfred.workflow.trigger.external + uid + 6AB2756A-CF82-447B-BB7F-AC42AC2A04ED + version + 1 + + + config + + argument + + variables + + chosen_color + {query} + + + type + alfred.workflow.utility.argument + uid + 80AD9430-0A5B-4196-8A02-B3B1CEEE678D + version + 1 + + + config + + argument + + variables + + theme_color + {query} + + + type + alfred.workflow.utility.argument + uid + FE00C128-31CE-4143-A647-1F1623539743 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "change_search_order_for_real" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 5C5EA309-F6AD-440F-B4CE-6638CD188EB4 + version + 2 + + + config + + argumenttrimmode + 0 + argumenttype + 2 + fixedorder + + items + [{"title":"playlist ➡️ artist ➡️ track ➡️ album","arg":"playlist▹artist▹track▹album","subtitle":""},{"title":"artist ➡️ playlist ➡️ track ➡️ album","arg":"artist▹playlist▹track▹album","subtitle":""},{"title":"track ➡️ playlist ➡️ artist ➡️ album","arg":"track▹playlist▹artist▹album","subtitle":""},{"title":"playlist ➡️ track ➡️ artist ➡️ album","arg":"playlist▹track▹artist▹album","subtitle":""},{"title":"artist ➡️ track ➡️ playlist ➡️ album","arg":"artist▹track▹playlist▹album","subtitle":""},{"title":"track ➡️ artist ➡️ playlist ➡️ album","arg":"track▹artist▹playlist▹album","subtitle":""},{"title":"track ➡️ artist ➡️ album ➡️ playlist","arg":"track▹artist▹album▹playlist","subtitle":""},{"title":"artist ➡️ track ➡️ album ➡️ playlist","arg":"artist▹track▹album▹playlist","subtitle":""},{"title":"album ➡️ track ➡️ artist ➡️ playlist","arg":"album▹track▹artist▹playlist","subtitle":""},{"title":"track ➡️ album ➡️ artist ➡️ playlist","arg":"track▹album▹artist▹playlist","subtitle":""},{"title":"artist ➡️ album ➡️ track ➡️ playlist","arg":"artist▹album▹track▹playlist","subtitle":""},{"title":"album ➡️ artist ➡️ track ➡️ playlist","arg":"album▹artist▹track▹playlist","subtitle":""},{"title":"album ➡️ playlist ➡️ track ➡️ artist","arg":"album▹playlist▹track▹artist","subtitle":""},{"title":"playlist ➡️ album ➡️ track ➡️ artist","arg":"playlist▹album▹track▹artist","subtitle":""},{"title":"track ➡️ album ➡️ playlist ➡️ artist","arg":"track▹album▹playlist▹artist","subtitle":""},{"title":"album ➡️ track ➡️ playlist ➡️ artist","arg":"album▹track▹playlist▹artist","subtitle":""},{"title":"playlist ➡️ track ➡️ album ➡️ artist","arg":"playlist▹track▹album▹artist","subtitle":""},{"title":"track ➡️ playlist ➡️ album ➡️ artist","arg":"track▹playlist▹album▹artist","subtitle":""},{"title":"artist ➡️ playlist ➡️ album ➡️ track","arg":"artist▹playlist▹album▹track","subtitle":""},{"title":"playlist ➡️ artist ➡️ album ➡️ track","arg":"playlist▹artist▹album▹track","subtitle":""},{"title":"album ➡️ artist ➡️ playlist ➡️ track","arg":"album▹artist▹playlist▹track","subtitle":""},{"title":"artist ➡️ album ➡️ playlist ➡️ track","arg":"artist▹album▹playlist▹track","subtitle":""},{"title":"playlist ➡️ album ➡️ artist ➡️ track","arg":"playlist▹album▹artist▹track","subtitle":""},{"title":"album ➡️ playlist ➡️ artist ➡️ track","arg":"album▹playlist▹artist▹track","subtitle":""}] + runningsubtext + + subtext + + title + + withspace + + + type + alfred.workflow.input.listfilter + uid + 63010287-34D8-4CB5-9AE8-7D868883A5E0 + version + 1 + + + config + + triggerid + change_search_order + + type + alfred.workflow.trigger.external + uid + 900B374F-3B5D-48A1-9213-99DEC1975B89 + version + 1 + + + config + + argument + + variables + + chosen_search_order + {query} + + + type + alfred.workflow.utility.argument + uid + 6FF2EF90-205D-4423-B818-11BCC11D34BE + version + 1 + + + config + + triggerid + copy_current_track_url_to_clipboard + + type + alfred.workflow.trigger.external + uid + C032FA5B-9A40-4D07-8D22-4951FC736C88 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "copy_current_track_url_to_clipboard" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') +php -f ./src/action.php -- "$query" "{query}" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 78C0F9B3-408C-43E4-BC40-86523A54AFDA + version + 2 + + + config + + triggerid + show_in_spotify + + type + alfred.workflow.trigger.external + uid + EBF5CCE5-EB7F-485A-AC1D-A6A558B6A318 + version + 1 + + + config + + argument + + argumenttype + 0 + triggerid + com.vdesabou.miniplayer.show_in_spotify + triggername + Show in Spotify + workflowonly + + + type + alfred.workflow.trigger.remote + uid + DA2F787C-11F7-4C7A-B275-A4CFFE171012 + version + 1 + + + config + + concurrently + + escaping + 38 + script + query=$(php -r '$foo = serialize(array("", "", "", "", "", "", "", "show_in_spotify" /* other_action */, "", "", "", "", "", "", "", "" , "", "", "", "", "", ""));echo $foo;') + + +php -f ./src/action.php -- "$query" "TRACK" "" >> "$alfred_workflow_cache/action.log" 2>&1 & + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + 9D647271-3601-4788-9E1F-F299FA7A39BD + version + 2 + + + config + + argumenttype + 2 + keyword + {var:c_show_in_spotify} + subtext + This will open Spotify Desktop with current track + text + Show current track in Spotify Desktop + withspace + + + type + alfred.workflow.input.keyword + uid + 804D8959-D2AE-453E-BBC1-3C11B275597B + version + 1 + + + config + + action + 0 + argument + 0 + focusedappvariable + + focusedappvariablename + + leftcursor + + modsmode + 0 + relatedAppsMode + 0 + + type + alfred.workflow.trigger.hotkey + uid + 85A5063C-1E10-4219-BB9D-333185702D4F + version + 2 + + + readme + Web Site: + +http://alfred-spotify-mini-player.com + +Twitter Account: + +@TheMiniPlayer + +Github page: + +https://github.com/vdesabou/alfred-spotify-mini-player + +Packal Page: + +http://www.packal.org/workflow/spotify-mini-player + uidata + + 024D6172-912E-4EAE-92AA-776626D52FFB + + xpos + 650 + ypos + 5530 + + 05D01A85-8BDC-4FF6-BEBB-BAF26BB5870A + + xpos + 900 + ypos + 2580 + + 05E1E4AA-E6B1-4DAA-9CB0-36CACDE2DA5B + + xpos + 830 + ypos + 8080 + + 05F86AA1-D3EE-4409-9A58-898B36FFE503 + + xpos + 300 + ypos + 6010 + + 062BBC6A-8B21-4777-8580-5CAE8506A859 + + xpos + 330 + ypos + 800 + + 0749257A-D830-483B-9EF5-580E33C10BB8 + + xpos + 980 + ypos + 10960 + + 090D4A5C-85C3-4083-B936-3E61ED83B1A3 + + xpos + 940 + ypos + 11780 + + 0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C + + xpos + 100 + ypos + 10200 + + 0B75CF43-8B04-405F-86C3-2FFC59AC4A70 + + xpos + 200 + ypos + 6650 + + 0C74516A-D95D-4379-94B6-CD984A31A003 + + xpos + 90 + ypos + 740 + + 0CAE95A9-03D6-4305-A30B-153796564AD1 + + xpos + 750 + ypos + 10830 + + 0E45EEB7-EA6D-4E6F-8655-98731989AEE0 + + xpos + 1120 + ypos + 12270 + + 0EBF4C61-5630-4629-8B4F-AD91D3470760 + + xpos + 300 + ypos + 11330 + + 0ED2ADE7-F998-4BE2-99F5-70CE4B287555 + + xpos + 820 + ypos + 9590 + + 1059D963-473F-44F8-8D60-94CFCE56BFF2 + + xpos + 410 + ypos + 7160 + + 10D173E8-E2FD-4A00-B899-8EBEF9017B05 + + xpos + 900 + ypos + 2410 + + 11E4CA98-E51E-45E4-91ED-72B4A1A34283 + + xpos + 110 + ypos + 9020 + + 13367FE5-35F7-4B94-8728-CF6F3D9F4C2B + + xpos + 500 + ypos + 8680 + + 15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2 + + xpos + 300 + ypos + 10380 + + 16F5C3BF-01EE-493C-9E7B-CC54D482B7A6 + + xpos + 100 + ypos + 4950 + + 175EB434-B9E1-4C6F-85B0-B0A3436E7E40 + + xpos + 100 + ypos + 5430 + + 18496AC4-EA42-444C-A906-642E38259C96 + + note + main command + xpos + 370 + ypos + 250 + + 19215BE5-986E-4AC9-9166-C80872C51DBE + + xpos + 820 + ypos + 6010 + + 1A29820A-69D9-458F-9285-76901C21D7F4 + + xpos + 800 + ypos + 6520 + + 1A2C6EE5-E029-45EE-89D0-4C6182C7E5E0 + + xpos + 770 + ypos + 12600 + + 1A88766E-BF4A-48F5-9BD4-D3538634422F + + xpos + 620 + ypos + 380 + + 1A88C8F9-C6E3-42C9-98A5-E277B97690B0 + + xpos + 330 + ypos + 560 + + 1B2600AD-60B1-488D-A1B9-5B9FD2829555 + + xpos + 800 + ypos + 9940 + + 1B716436-7DCE-45DA-8567-FA157808962F + + xpos + 110 + ypos + 11930 + + 1B841176-1A95-46BD-8123-583075FAB8E4 + + xpos + 490 + ypos + 12470 + + 1BA522F3-B2D0-4F36-B86C-738FB3AC55DD + + xpos + 300 + ypos + 2160 + + 1BA8D519-4B49-4BD9-B329-D004A22AE84C + + xpos + 600 + ypos + 11290 + + 1D4F4588-B2AC-4E96-9F87-467BCC69915A + + xpos + 900 + ypos + 2280 + + 1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0 + + xpos + 100 + ypos + 8850 + + 23412027-872A-4639-A9D9-DCFD8D8FF36D + + xpos + 800 + ypos + 7010 + + 24B8C827-75F2-4421-A412-D48782DA1DB8 + + xpos + 890 + ypos + 3210 + + 25E3EBDF-2CFA-4599-A13B-8C63B3E5329A + + xpos + 500 + ypos + 8280 + + 2609AC90-5B4D-4043-8F13-D5187B14833F + + xpos + 830 + ypos + 5350 + + 2B0C6211-1DD0-4CE6-8082-37957F15CC1D + + xpos + 100 + ypos + 9940 + + 2B0C8466-4AED-4272-9C10-50F3BCE88043 + + xpos + 300 + ypos + 6250 + + 2B1BF20E-C892-4340-ABFE-AFA4AF7F8C52 + + xpos + 460 + ypos + 1080 + + 2E15D453-FA20-483A-AAA3-59FF33614829 + + xpos + 660 + ypos + 5760 + + 2EC684F9-F50A-4300-9421-FF3B95CF2CC1 + + xpos + 460 + ypos + 1200 + + 2F1F6369-46C0-483B-816F-3796168AE060 + + xpos + 490 + ypos + 10960 + + 2FC567E2-E6C5-4A91-B42E-1996532B78C9 + + xpos + 100 + ypos + 6920 + + 3016205A-8693-421C-B3B6-3CE742806FCC + + xpos + 630 + ypos + 9480 + + 303A65BF-8E81-48E8-AA28-E1CA408FDD53 + + xpos + 100 + ypos + 8680 + + 3040749D-6B5C-4CCD-AF95-AEC0F83B48D9 + + xpos + 90 + ypos + 840 + + 30833563-364F-4EC4-B467-F63A7F66EB06 + + colorindex + 1 + note + This external trigger is internal stuff, DO NOT USE ! + xpos + 10 + ypos + 12270 + + 30F45FDA-252D-4C22-894C-444F7E3E8E78 + + xpos + 940 + ypos + 12080 + + 318D20CD-D753-4CCC-B931-BB3CFC6A1D0A + + xpos + 330 + ypos + 1400 + + 327849A3-A34A-46BA-AC04-1F5115824DC3 + + xpos + 280 + ypos + 1960 + + 3280F15E-8C80-4A0D-8439-07A113AA1094 + + xpos + 110 + ypos + 9180 + + 3435F565-E791-4FE9-A7B9-85B4A2EA353C + + xpos + 290 + ypos + 11020 + + 3617F927-558D-4F30-B8D1-B7789F863AB0 + + xpos + 90 + ypos + 1660 + + 36FF7DE6-29DF-4E25-8E15-58411CE75638 + + xpos + 330 + ypos + 1050 + + 3837382F-63B4-4B0D-A880-A1CF7079D584 + + xpos + 100 + ypos + 2990 + + 383F2E0F-8A62-41E5-8575-415A9225572E + + xpos + 810 + ypos + 10420 + + 39A1935A-37F5-49FA-A860-BCF7765A8C65 + + xpos + 90 + ypos + 10 + + 39C34247-AE29-43A1-879B-3965F3AAF475 + + xpos + 1110 + ypos + 12080 + + 3AA52DF5-6A73-4739-A088-0F78F446B447 + + xpos + 100 + ypos + 2380 + + 3F85747B-FC44-4B07-AA6E-3645F0CC0DF7 + + xpos + 300 + ypos + 2780 + + 401D4FC7-21EC-47C3-9896-FCD97C8563F4 + + xpos + 330 + ypos + 440 + + 450AEF8B-BDAA-409C-A0D4-68769545FBCF + + xpos + 100 + ypos + 8280 + + 450CD09C-F6EB-4270-8FEE-C1E33586165F + + xpos + 260 + ypos + 12740 + + 455BDE70-BCF4-447F-ABFF-C25D8E5B08B6 + + xpos + 300 + ypos + 5650 + + 479B0769-F60E-4F2B-A2A6-BA361F3B0BF2 + + note + get "artist_name track_name" + xpos + 590 + ypos + 11940 + + 4BE9FB30-9B4F-4E44-861D-D178507A7568 + + xpos + 100 + ypos + 9300 + + 4EB5FB5E-6472-4757-A479-B206B6080036 + + xpos + 300 + ypos + 4260 + + 4FB4D3A4-9DA1-4369-99D1-664AE2685C27 + + xpos + 460 + ypos + 710 + + 51401C92-A6F8-4E2A-AA02-D140984EE916 + + xpos + 500 + ypos + 8850 + + 528C59BE-0DAD-4C1D-876E-09EEE2B889FA + + xpos + 1110 + ypos + 11930 + + 5372B0DF-11F6-41D9-8E6C-ED8C2A7EBE70 + + xpos + 720 + ypos + 3650 + + 55288BC7-DEF9-4B85-BB03-274A7322F31A + + xpos + 330 + ypos + 920 + + 552D77E3-1550-4035-AB49-8B708B081EC9 + + xpos + 300 + ypos + 8090 + + 57B3B398-989F-42FF-B449-281E41BB0851 + + xpos + 330 + ypos + 1170 + + 57BD5D83-BC36-41AF-B6F7-B3289DD427CE + + xpos + 600 + ypos + 10580 + + 58B9E278-8EF7-46DC-96DC-D8D127D5EEBB + + xpos + 800 + ypos + 11360 + + 5AF7EEEC-2E55-482C-8750-4CE6AD752683 + + xpos + 300 + ypos + 3420 + + 5B323D08-37EF-46D8-ACAD-9E21B74F6767 + + xpos + 800 + ypos + 11130 + + 5BB099A1-224D-4702-BBBC-52919BDCCF62 + + xpos + 100 + ypos + 7910 + + 5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2 + + xpos + 100 + ypos + 3360 + + 5C5EA309-F6AD-440F-B4CE-6638CD188EB4 + + xpos + 580 + ypos + 12910 + + 5EB4A672-01BC-4DBB-AD39-60EBB0F79A67 + + xpos + 100 + ypos + 2860 + + 5F3AF2C8-064F-4C10-8D99-22E212825BFE + + xpos + 610 + ypos + 10 + + 5F3F806B-0B88-4C17-92E7-72A944CEB1A6 + + xpos + 310 + ypos + 11130 + + 5F5E8A6D-8707-41FC-B5D1-660CD11685F0 + + xpos + 610 + ypos + 690 + + 6008947F-A428-45E7-8B9C-1F3402278D3A + + xpos + 460 + ypos + 590 + + 60F15971-216E-4921-8A56-C6B992D25B08 + + xpos + 670 + ypos + 3820 + + 620CF52F-BCFD-4957-BC4F-1E9853125AF5 + + xpos + 630 + ypos + 10120 + + 62AA861E-C910-4354-84C9-58A5660365D8 + + xpos + 300 + ypos + 9370 + + 63010287-34D8-4CB5-9AE8-7D868883A5E0 + + xpos + 220 + ypos + 12910 + + 64953E09-D9D0-485B-B92B-79E7FEC15927 + + xpos + 860 + ypos + 4280 + + 66723864-4D1C-439D-A1DE-5F90BCB03CCC + + xpos + 610 + ypos + 11040 + + 66A0F734-983C-420D-B6E4-F21922513E4B + + xpos + 100 + ypos + 6810 + + 66AE01C5-E034-40D2-9CEE-69A063016B4A + + xpos + 100 + ypos + 7070 + + 66F8A022-163E-42CB-A9E9-B32E8158ACA7 + + xpos + 100 + ypos + 4010 + + 68A6C7CD-CB82-4A31-A935-E38F8E414772 + + xpos + 500 + ypos + 11820 + + 6965EC4E-AE6C-40BD-A3B5-CD316812BF30 + + xpos + 650 + ypos + 4190 + + 69E43FC9-457E-4082-8930-A1B00B6A5514 + + xpos + 100 + ypos + 3500 + + 6AB2756A-CF82-447B-BB7F-AC42AC2A04ED + + colorindex + 1 + note + This external trigger is internal stuff, DO NOT USE ! + xpos + 20 + ypos + 12740 + + 6BC60709-1E24-4297-A9CB-3B99581AF0C6 + + xpos + 100 + ypos + 2040 + + 6E7D21ED-AC05-4EC3-974C-ECB80BB744CA + + xpos + 820 + ypos + 10690 + + 6E7EAD8C-4207-4393-8091-D7EC5ED9A654 + + xpos + 330 + ypos + 1290 + + 6E9B4F21-F907-4A22-8689-9A146F909454 + + xpos + 300 + ypos + 10140 + + 6EA904F5-F25E-4B1E-A6DD-5E94263ADBC8 + + xpos + 110 + ypos + 11190 + + 6EC5159F-1577-4384-9869-4777146F362E + + xpos + 460 + ypos + 1320 + + 6FDBF98C-ACD5-49F8-B1FD-04B79FA04E29 + + xpos + 100 + ypos + 5140 + + 6FEAFE02-DF77-4F58-9305-651E6D627144 + + xpos + 780 + ypos + 11510 + + 6FF2EF90-205D-4423-B818-11BCC11D34BE + + note + set chosen_search_order variable + xpos + 430 + ypos + 12940 + + 70C9B5C9-72DA-409A-B3EC-8C2DC0EE9627 + + xpos + 590 + ypos + 6400 + + 71AACE30-7E8D-4D3C-8BD1-F98FEE578AEC + + xpos + 770 + ypos + 12440 + + 7224DEC2-8842-4EF7-9D41-8996267F4231 + + note + get "artist_name track_name" + xpos + 590 + ypos + 12080 + + 7351C6F1-1AB2-42D0-9003-5FFECFDEB441 + + xpos + 460 + ypos + 950 + + 73FB3971-4382-45F5-ADED-F1E481A95E2E + + xpos + 80 + ypos + 1540 + + 75E489FD-ADF2-4A30-A432-61E53BF36A00 + + xpos + 660 + ypos + 7980 + + 77BC9498-F4E6-48BB-919D-D0B64DAFEF26 + + xpos + 870 + ypos + 3930 + + 78C0F9B3-408C-43E4-BC40-86523A54AFDA + + xpos + 420 + ypos + 13110 + + 78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A + + xpos + 100 + ypos + 8470 + + 78DD84AE-70E9-4DB5-BF2B-44BC774B4383 + + xpos + 100 + ypos + 5720 + + 7918E8F7-20AE-445E-9AEA-E2E54CDE967D + + xpos + 630 + ypos + 530 + + 7934F80C-2281-449C-9A89-7BC422D659D7 + + xpos + 90 + ypos + 1320 + + 794A76A7-BB98-4A83-92BE-386A56875120 + + xpos + 260 + ypos + 7470 + + 7CD59703-7376-4695-8BC8-DBBD01EC19A6 + + xpos + 650 + ypos + 9280 + + 7E4C3B84-D930-490A-BF7E-FA5C57328897 + + xpos + 100 + ypos + 9450 + + 7F15B183-963C-4EE1-9B19-10705529BF0B + + xpos + 730 + ypos + 2660 + + 7FE5D993-C14D-4B94-9479-B361680F1C40 + + xpos + 300 + ypos + 7810 + + 7FF09231-F068-4EA0-8537-6C1EB608CA5A + + xpos + 300 + ypos + 2450 + + 804D8959-D2AE-453E-BBC1-3C11B275597B + + xpos + 210 + ypos + 13390 + + 80AD9430-0A5B-4196-8A02-B3B1CEEE678D + + note + set chosen_color variable + xpos + 430 + ypos + 12770 + + 80B80179-E286-4D4A-9FEC-FCBE63AD8AEE + + xpos + 100 + ypos + 2750 + + 81536C26-DB7C-42CE-95C0-B78FA1C7934E + + xpos + 110 + ypos + 11030 + + 817080F0-4CE8-4336-A972-550D43D063B1 + + xpos + 100 + ypos + 10560 + + 827D9590-7BA6-4E87-B288-0AF6C04C9B01 + + xpos + 100 + ypos + 9790 + + 8339BE15-274E-4A77-A6A0-CEDF30EFD0E5 + + xpos + 100 + ypos + 4320 + + 8347A3BC-6F50-447F-84B3-3497D4BF720D + + xpos + 500 + ypos + 12110 + + 83FDAFA8-0D15-43B2-9CA9-E9B3459ACE5E + + note + get artist_name + xpos + 580 + ypos + 12440 + + 85966031-0B63-4629-BF2A-CAE7C92FCDD6 + + xpos + 690 + ypos + 2930 + + 8598A5C9-72B6-4CEF-A498-D6C2ED06DC88 + + xpos + 100 + ypos + 5560 + + 85A5063C-1E10-4219-BB9D-333185702D4F + + xpos + 10 + ypos + 13460 + + 873ABD54-A6BC-4C6D-A88B-8FC9DA2C3292 + + xpos + 880 + ypos + 3720 + + 873EF61A-BD03-4946-87B0-C7AE5DFC5E5B + + xpos + 100 + ypos + 2150 + + 899AC4D2-88FA-474F-A075-AFA12F361E2B + + xpos + 790 + ypos + 7520 + + 89BC46B4-E178-4855-8863-393730814F6E + + xpos + 100 + ypos + 3610 + + 89D8799A-D22A-4A6D-B43D-50B9EADB879D + + xpos + 520 + ypos + 4470 + + 8A63B1A6-0F0E-481A-9312-C75557A9DA71 + + xpos + 90 + ypos + 1080 + + 8B3222AF-02D9-4F13-9F79-6C4A935FD76F + + note + get artist_name + xpos + 580 + ypos + 12600 + + 8B88B440-38F7-4EBA-9A2E-46779141C889 + + xpos + 790 + ypos + 7290 + + 8C78472B-13EB-4512-B94D-4BF92867CD92 + + xpos + 300 + ypos + 2560 + + 8D9D70BD-782D-421A-926F-7EBC18085CE9 + + xpos + 330 + ypos + 680 + + 8DF18F9A-B3A5-4B14-8360-AD850CF5C143 + + xpos + 610 + ypos + 130 + + 8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5 + + xpos + 100 + ypos + 2510 + + 8F478980-199B-45B5-AD41-EBA185446705 + + xpos + 100 + ypos + 7620 + + 8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4 + + xpos + 90 + ypos + 420 + + 900B374F-3B5D-48A1-9213-99DEC1975B89 + + colorindex + 1 + note + This external trigger is internal stuff, DO NOT USE ! + xpos + 30 + ypos + 12910 + + 901D4A54-195C-4D82-90C8-E3A6F6F48FC8 + + xpos + 560 + ypos + 9800 + + 93DE48B5-E0D6-4B64-B972-D01EB36E71C7 + + xpos + 940 + ypos + 11930 + + 9653C27F-400A-4C3F-BB97-FC0C803DFEC7 + + xpos + 100 + ypos + 11540 + + 9661EF24-91C3-44A1-9066-8E9B9817841D + + xpos + 200 + ypos + 6490 + + 96995CA4-6C03-4DB7-9E8E-95AEECA4CEB5 + + xpos + 100 + ypos + 10080 + + 98123379-ADC9-4377-9F28-DF79E01715D1 + + xpos + 880 + ypos + 3420 + + 9845C770-A2CC-4752-A542-D71BE1081691 + + xpos + 610 + ypos + 250 + + 99E823C3-8271-4C60-B4F9-8F5F9C48F1CE + + xpos + 1120 + ypos + 12590 + + 9B1431EC-8D2F-4149-9EC0-7DBFD487D93E + + xpos + 100 + ypos + 7380 + + 9B240AE9-8584-42FE-95A9-FF0561F0508C + + xpos + 620 + ypos + 10340 + + 9B2621F0-0190-4ABD-A09F-3DBF85548580 + + xpos + 100 + ypos + 9670 + + 9D647271-3601-4788-9E1F-F299FA7A39BD + + xpos + 740 + ypos + 13380 + + 9E3FE06C-F5F8-41F3-A70F-B92E187EED75 + + xpos + 100 + ypos + 10680 + + 9F9919C7-33FD-472E-B18D-212D95BF1470 + + xpos + 950 + ypos + 12590 + + A0EAB8B1-F034-490F-9534-44ADF572AF4E + + xpos + 100 + ypos + 5920 + + A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90 + + xpos + 100 + ypos + 7220 + + A2C8ACBA-F98F-457A-90E8-11BA2112342C + + xpos + 810 + ypos + 10260 + + A38DD404-DE03-42C2-B0CB-A37891B6F24D + + xpos + 270 + ypos + 4650 + + A41190FA-4B23-4908-A4B7-16A14F338C11 + + xpos + 290 + ypos + 10860 + + A4437594-2A54-42A1-836E-129E46F5DB47 + + xpos + 610 + ypos + 6140 + + A4EEDB0D-EEB3-45CE-B8A8-1397DD905470 + + xpos + 100 + ypos + 3770 + + A5C6FE27-E7CE-45C4-ADB0-8B2D0CC39E99 + + xpos + 90 + ypos + 110 + + A5E65336-52B1-42E9-93F1-9AF3040048AC + + xpos + 610 + ypos + 4920 + + A6F352C0-689E-484F-8782-AC74F9EDDB75 + + xpos + 90 + ypos + 1790 + + A76C26BD-BA48-4797-839B-BE439FF40846 + + xpos + 100 + ypos + 3250 + + A8BE6109-BCC0-4A41-9375-C1D2E3A755BD + + xpos + 100 + ypos + 10440 + + A8CB9AD8-402D-4DBA-B2A7-921B4F7ABE51 + + xpos + 600 + ypos + 6920 + + A9C4AD0B-3E66-42A8-B891-B57CC59396FE + + xpos + 610 + ypos + 5930 + + AA5EC8E7-EFB2-4194-9412-B562C202A977 + + note + get "artist_name track_name" + xpos + 590 + ypos + 11790 + + ABCF2AB0-D1EC-48B5-8BBB-3BA51EF2F55A + + xpos + 660 + ypos + 3340 + + AC236315-8CDE-41E3-A9BA-BB59D292FE14 + + xpos + 300 + ypos + 5050 + + AE6160D1-56EA-4416-991E-CF12B874FFD3 + + xpos + 250 + ypos + 10 + + B23712E3-4564-4668-BD6D-4D535839CC8C + + xpos + 300 + ypos + 5830 + + B2454113-3905-495E-B8E0-0E25AC384525 + + xpos + 960 + ypos + 12430 + + B2A423FC-AF28-40F1-8BAF-CC7A29B86788 + + xpos + 490 + ypos + 12300 + + B2B50FA2-E3B9-43C3-AC33-754811E3CAC3 + + xpos + 460 + ypos + 830 + + B5D85A55-8E85-4B14-81EF-0656DC5E7594 + + xpos + 770 + ypos + 12270 + + B77F5F98-C065-49A4-BBB1-68ADADDD8E7D + + xpos + 250 + ypos + 7000 + + B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F + + xpos + 90 + ypos + 520 + + B91D4F9A-DEA5-426E-B984-372482E03125 + + xpos + 1110 + ypos + 11780 + + B953E1B7-2F6E-4E88-A66B-5F12999EE0E2 + + xpos + 420 + ypos + 8960 + + BA289B3E-779E-482F-AFEA-8E1395513365 + + xpos + 100 + ypos + 1930 + + BC488027-E76B-43A7-B414-C7FAA9CF9995 + + xpos + 100 + ypos + 2640 + + BC672665-5E43-4892-B8D3-BFCBA48E34C4 + + xpos + 840 + ypos + 4620 + + BD255BDB-07A5-4EE9-858F-A58C6207D191 + + xpos + 440 + ypos + 3550 + + BE8BE3CE-9515-4294-9F4B-CA2F079A0A90 + + xpos + 90 + ypos + 620 + + C032FA5B-9A40-4D07-8D22-4951FC736C88 + + note + Copy current track url to clipboard +Example: https://open.spotify.com/track/6hxgHNJjadmCHAJPXw6AYL + xpos + 170 + ypos + 13110 + + C10A975C-0DAE-4A45-AEAB-4E07CF125703 + + xpos + 100 + ypos + 5260 + + C208E6CD-E56A-4223-BF05-3B90DEC14483 + + xpos + 230 + ypos + 12270 + + C2B88645-70FA-454D-8237-1AC8812CB059 + + xpos + 460 + ypos + 2130 + + C2D3F56B-0B41-4305-8D17-5B95EFDB8F06 + + xpos + 100 + ypos + 8160 + + C323BECC-0183-4562-B817-65624E13B3F3 + + xpos + 110 + ypos + 11810 + + C3F966D4-D292-4B70-9024-B8788BA5488F + + xpos + 770 + ypos + 11940 + + C40074F8-D8EC-4270-AE0C-05A98F3E2DCD + + note + save web_search variable + xpos + 160 + ypos + 12300 + + C588A188-D8D3-450F-9020-5EBB563F6B8A + + xpos + 90 + ypos + 6120 + + C7A836E4-009F-4028-A233-561002F90337 + + xpos + 460 + ypos + 1430 + + C7CFF014-DBC8-4663-A0AB-219C57A427EE + + xpos + 300 + ypos + 9860 + + C8B5A68F-5328-48B7-84C1-E73601716B7E + + xpos + 100 + ypos + 2260 + + C91B7486-D357-4C1C-8661-83290128E78E + + xpos + 770 + ypos + 12080 + + C93B7A2B-9105-4456-997A-1BCC4EDA5A27 + + xpos + 300 + ypos + 5350 + + C9ACB578-CE2A-492F-84CA-CFCA5E528458 + + xpos + 500 + ypos + 11970 + + CB11FDA4-17C4-4684-A145-C0D8FD6F6FDE + + xpos + 820 + ypos + 9370 + + CD9D3654-8137-49B2-80DC-095E97A58E67 + + xpos + 300 + ypos + 3930 + + CEA89051-EDDB-4FBB-9BE7-F7FF7B6B8B27 + + xpos + 620 + ypos + 7680 + + CEF36AB9-7CC2-4765-BF84-751E88B69023 + + xpos + 300 + ypos + 1810 + + CF46537F-6F59-40DB-A643-72A7BB952840 + + xpos + 810 + ypos + 6250 + + D165D8EC-3FB4-4758-8760-AEDA9BEBC727 + + xpos + 610 + ypos + 5240 + + D31A5001-4590-418E-9AB0-6183E75E59DE + + xpos + 300 + ypos + 9590 + + D433D376-C21C-4A96-9CDF-1FA402D74249 + + xpos + 570 + ypos + 7400 + + D4442911-E17B-49CC-8F7F-EAC1830B11CD + + xpos + 300 + ypos + 2310 + + D54F6237-A9E0-4E1D-912B-5970380FD2C7 + + xpos + 100 + ypos + 3120 + + D781BC43-654A-4261-A7E4-648287517182 + + xpos + 440 + ypos + 1970 + + D8C53798-B7E2-4A51-AC12-37FEBDB624E0 + + xpos + 100 + ypos + 8020 + + D90DC148-3BE8-4D4E-B144-C0B5A625D4C5 + + note + get artist_name + xpos + 580 + ypos + 12270 + + D9BCA226-6F66-4A41-A8BE-19E9D6343941 + + xpos + 100 + ypos + 10800 + + DA2F787C-11F7-4C7A-B275-A4CFFE171012 + + xpos + 10 + ypos + 13320 + + DADFE8E3-A419-4AE9-84E0-322B797F8F98 + + xpos + 1130 + ypos + 12430 + + DAE270E5-CA94-4F36-99FE-D8EC996608C0 + + xpos + 90 + ypos + 310 + + DC403223-17FA-466B-9488-7292DA9D8223 + + xpos + 100 + ypos + 4550 + + DC678CF5-D8B2-4508-A2FA-CB0F0E253108 + + xpos + 90 + ypos + 1430 + + DD0755A4-3C70-467C-A005-11F10E23CEF0 + + xpos + 90 + ypos + 210 + + DD89687E-99D0-4A06-9965-86C62CB2AC5C + + xpos + 570 + ypos + 11510 + + E049B90B-F4AC-475E-A20A-82083E709F11 + + xpos + 800 + ypos + 9090 + + E241B5C1-14A9-4D50-AD12-22033C647C44 + + xpos + 100 + ypos + 3870 + + E2DF757E-A0B1-43E1-9B5B-9AFF73349323 + + xpos + 830 + ypos + 5650 + + E3BCC85B-A326-41C9-BAC9-623BE1865375 + + xpos + 830 + ypos + 7800 + + E45DF42A-58A9-4069-A410-EC2BBC8A0575 + + xpos + 90 + ypos + 1200 + + E59E23E2-837A-4B48-949A-A9EE059186C1 + + xpos + 500 + ypos + 8470 + + E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A + + xpos + 100 + ypos + 11420 + + E63EB492-FCE2-42A1-BD38-7EFE4EA77473 + + xpos + 100 + ypos + 4200 + + E6CEF7D4-CFA9-4608-A188-65B33A602BAF + + xpos + 310 + ypos + 9090 + + E81FC8A2-529A-4350-9734-0AEE58EB8D95 + + xpos + 770 + ypos + 11790 + + EA03C1F5-912A-4422-B766-2BBC94DC0344 + + xpos + 300 + ypos + 10620 + + EB1ED46F-71D7-49D1-B7BB-DA1ECF2F665F + + xpos + 840 + ypos + 5060 + + EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E + + xpos + 300 + ypos + 7290 + + EBE3B702-B0E0-4AAC-AB87-623064F9D06D + + xpos + 100 + ypos + 4770 + + EBF5CCE5-EB7F-485A-AC1D-A6A558B6A318 + + xpos + 570 + ypos + 13280 + + EC1183BF-4D79-4AA1-9B58-E69CBC467069 + + xpos + 610 + ypos + 3110 + + ECC53637-75AD-4FD2-9605-8E038D04C4BF + + xpos + 880 + ypos + 2820 + + F0ED23FA-8524-4769-B610-828611958D6A + + xpos + 90 + ypos + 960 + + F1A83FA9-AEB1-4136-BA2C-6BA9615A1E6B + + xpos + 950 + ypos + 12270 + + F23EB343-6D1D-4D17-9CCC-465756A5F513 + + xpos + 490 + ypos + 12630 + + F2B24FB4-386C-4562-99D2-E4162D26AB4A + + xpos + 830 + ypos + 5840 + + F2E78D71-0765-466D-9143-176361994982 + + xpos + 680 + ypos + 2490 + + F4382654-9318-4849-82E4-550AC235148C + + xpos + 300 + ypos + 3210 + + F4F5AC18-3C04-4673-9CC3-E563094C9446 + + xpos + 100 + ypos + 7750 + + F71F1D16-0DF9-4590-9FE9-22D439FE12BB + + xpos + 100 + ypos + 10320 + + F89879E2-9D98-43EC-802B-76AA64EF0050 + + xpos + 400 + ypos + 10 + + FA976637-B683-4672-837E-85462CC82B69 + + xpos + 580 + ypos + 12740 + + FAA5FC99-7909-45B6-9BF0-7601DBAADC4F + + xpos + 260 + ypos + 11640 + + FD282800-1267-4ACF-BF0D-C42758D49623 + + xpos + 460 + ypos + 470 + + FE00C128-31CE-4143-A647-1F1623539743 + + note + save theme_color variable + xpos + 170 + ypos + 12770 + + + variables + + add_created_radio_playlist_to_library + 0 + append_to_playlist_when_adding_tracks + 0 + automatically_open_spotify_app + 1 + c_add_current_track_to + add_current_track_to + c_add_current_track_to_alfred_playlist_or_your_music + add_current_track_to_alfred_playlist_or_your_music + c_artist_radio + artist_radio + c_current + current + c_lookup_artist_online + lookup_artist_online + c_lyrics + lyrics + c_mute + mute + c_next + next + c_pause + pause + c_play + play + c_play_album + play_album + c_play_alfred_playlist + play_alfred_playlist + c_play_artist + play_artist + c_playpause + playpause + c_previous + previous + c_random + random + c_random_album + random_album + c_refresh_library + refresh_library + c_remove_current_track_from + remove_current_track_from + c_repeating + repeating + c_repeating_current_track + repeating_current_track + c_share + share + c_show_alfred_playlist + show_alfred_playlist + c_show_in_spotify + show_in_spotify + c_shuffle + shuffle + c_song_radio + song_radio + c_spot_mini + spot_mini + c_spot_mini_debug + spot_mini_debug + c_spot_mini_issue + spot_mini_issue + c_spot_mini_kill + spot_mini_kill + c_spot_mini_reset_settings + spot_mini_reset_settings + c_volmax + volmax + c_volmid + volmid + c_volume_down + volume_down + c_volume_up + volume_up + c_web_search + web_search + menu_display_alfred_playlist + 1 + menu_display_browse_by_album + 1 + menu_display_browse_by_artist + 1 + menu_display_browse_by_playlist + 1 + menu_display_browse_categories + 1 + menu_display_browse_your_music + 1 + menu_display_current_track + 1 + menu_display_lookup_current_artist_online + 1 + menu_display_play_queue + 1 + menu_display_search_online + 1 + menu_display_spotify_connect + 1 + menu_display_your_recent_tracks + 1 + menu_display_your_tops + 1 + previous_track_for_real + 1 + reduce_notifications + 1 + settings_volume_max + 100 + settings_volume_mid + 50 + settings_volume_min + 0 + sharing_hashtag1 + #NowPlaying + sharing_hashtag2 + #AlfredSpotifyMiniPlayer + sharing_text1 + + sharing_text2 + + + version + 8.4 + webaddress + http://alfred-spotify-mini-player.com + + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/com.vdesabou.spotify.mini.player.pub b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/com.vdesabou.spotify.mini.player.pub new file mode 100644 index 0000000..9c875cd --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/com.vdesabou.spotify.mini.player.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0yytRhaab41QRuidvwKS +BfDHcYwFUeJBgOVT2F50n1tdvuG9hRIaZhYQajhmnXIBLt64XmHgwvKTMSkcsH5g +T3o5Um0ovMN3bSax/z3KfEfU3+Rk4cgHdH9TTJWpKQgJK9c4/8OJo1kRni8vE79u +z59We0P/4MZ4ebhM+ve4OhY/y0up3FbrFMEoiLTRtWUgDQKGrU9oLCk47t1gSQsZ +tTGwYuPs61vrjNTmnBhWScBuJs0v/nDtPwU/Mqi1LoDKIXSlknRfhauJBUbIzb34 +3ymirEyiHvBwlw1KoPX3Nkgw4NOvLPut425vuPLhNGUfZpEwypqnrD7i2pTQZ8Cv +RwIDAQAB +-----END PUBLIC KEY----- diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/package.xml b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/package.xml new file mode 100644 index 0000000..f2b698d --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/packal/package.xml @@ -0,0 +1,8 @@ + + + Spotify Mini Player + 8.4 + com.vdesabou.spotify.mini.player + 1575108879 + spotifyminiplayer.alfredworkflow + diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/action.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/action.php new file mode 100644 index 0000000..e84eb84 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/action.php @@ -0,0 +1,1852 @@ +is_alfred_playlist_active; +$now_playing_notifications = $settings->now_playing_notifications; +$alfred_playlist_uri = $settings->alfred_playlist_uri; +$alfred_playlist_name = $settings->alfred_playlist_name; +$country_code = $settings->country_code; +$userid = $settings->userid; +$oauth_client_id = $settings->oauth_client_id; +$oauth_client_secret = $settings->oauth_client_secret; +$oauth_redirect_uri = $settings->oauth_redirect_uri; +$oauth_access_token = $settings->oauth_access_token; +$volume_percent = $settings->volume_percent; +$use_artworks = $settings->use_artworks; +$use_facebook = $settings->use_facebook; +$always_display_lyrics_in_browser = $settings->always_display_lyrics_in_browser; +$output_application = $settings->output_application; +$theme_color = $settings->theme_color; + +if ($other_action != 'reset_settings' && $other_action != 'spot_mini_debug' && !startswith($other_settings,'SWITCH_USER▹')) { + if ($oauth_client_id == '' || $oauth_client_secret == '' || $oauth_access_token == '') { + if ($other_settings != '' && (startsWith($other_settings, 'Oauth_Client') === false && startsWith($other_settings, 'Open') === false)) { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini')." \"'"); + + return; + } + + if ($other_action != '' && $other_action != 'Oauth_Login' && + !startsWith($other_action, 'current')) { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini')." \"'"); + + return; + } + } +} + +if (!startsWith($other_action, 'current')) { + stathat_ez_count('AlfredSpotifyMiniPlayer', 'workflow used', 1); +} + +if ($add_to_option != '') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } +} + +// start now playing if needed +if($oauth_access_token != '' && $now_playing_notifications == true) { + $app_arg = ''; + if ($output_application == 'MOPIDY') { + $app_arg = 'MOPIDY'; + } else if($output_application == 'APPLESCRIPT') { + $app_arg = 'SPOTIFY'; + } else { + $app_arg = 'CONNECT'; + } + exec('./src/spotify_mini_player_notifications.ksh -d "'.$w->data().'" -a start -m "'.$app_arg.'" -v "'.getAlfredName().'" >> "'.$w->cache().'/action.log" 2>&1 & '); +} + +// make sure spotify is running +if ($output_application == 'APPLESCRIPT') { + if($oauth_access_token != '' && $other_action != 'update_library' && $other_action != 'refresh_library' && $type != 'DOWNLOAD_ARTWORKS') { + exec('./src/is_spotify_running.ksh 2>&1', $retArr, $retVal); + if ($retArr[0] != 0) { + exec('open -a "Spotify"'); + // wait for Spotify to start + sleep(6); + } + } +} + +if ($spotify_command != '' && $type == 'TRACK' && $add_to_option == '') { + $spotify_command = str_replace('\\', '', $spotify_command); + if (!startsWith($spotify_command, 'activate')) { + exec("osascript -e 'tell application \"Spotify\" to activate'"); + $tmp = 'spotify:search:' . urlencode($spotify_command); + exec("osascript -e 'set uri to \"$tmp\"' -e 'tell application \"Spotify\" to open location uri'"); + } else { + exec("osascript -e 'tell application \"Spotify\" to $spotify_command'"); + + } + return; +} + +if ($type == 'TRACK' && $other_settings == '' && + (startsWith($other_action, 'set_playlist_privacy_to_') || $other_action == 'play_track_from_play_queue' || $other_action == '' + || ($other_action == 'play_track_in_album_context' && $add_to_option != '') + || ($other_action == 'play' && $add_to_option != '') + || ($other_action == 'playpause' && $add_to_option != '') + || ($other_action == 'pause' && $add_to_option != ''))) { + if ($track_uri != '') { + if ($add_to_option != '') { + $tmp = explode(':', $track_uri); + if ($tmp[1] == 'local') { + // local track, look it up online + $query = 'track:'.$track_name.' artist:'.$artist_name; + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $artists = $track->artists; + $artist = $artists[0]; + logMsg("Error(action): Unknown track $track_uri / $track_name / $artist_name replaced by track: $track->uri / $track->name / $artist->name"); + $track_uri = $track->uri; + $tmp = explode(':', $track_uri); + } else { + logMsg("Error(action): Could not find track: $track_uri / $track_name / $artist_name"); + displayNotificationWithArtwork($w, 'Local track '.$track_name.' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Add▹'.$track_uri.'∙'.escapeQuery($track_name).'▹'."\"'"); + + return; + } elseif ($playlist_uri != '') { + if ($output_application == 'MOPIDY') { + playTrackInContextWithMopidy($w, $track_uri, $playlist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$track_uri\" in context \"$playlist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, $track_uri, $playlist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + if ($now_playing_notifications == false) { + displayNotificationWithArtwork($w, '🔈 '.$track_name.' by '.$artist_name, $track_artwork_path); + } + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addPlaylistToPlayQueue($w, $playlist_uri, $playlist_name); + + return; + } else { + if ($other_action == '' || $other_action == 'play_track_from_play_queue') { + if ($output_application == 'MOPIDY') { + playUriWithMopidyWithoutClearing($w, $track_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$track_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, $track_uri, ''); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + } + } + if ($now_playing_notifications == false) { + displayNotificationWithArtwork($w, '🔈 '.$track_name.' by '.$artist_name, $track_artwork_path); + } + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + if ($other_action == '') { + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + addTrackToPlayQueue($w, $track_uri, escapeQuery($results[0]), escapeQuery($results[1]), escapeQuery($results[2]), $results[5], $country_code); + } + } + + return; + } + } + } elseif ($playlist_uri != '') { + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $playlist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$playlist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $playlist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + if ($playlist_artwork_path == '') { + $playlist_artwork_path = getPlaylistArtwork($w, $playlist_uri, true, false, $use_artworks); + } + displayNotificationWithArtwork($w, '🔈 Playlist '.$playlist_name, $playlist_artwork_path, 'Launch Playlist'); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addPlaylistToPlayQueue($w, $playlist_uri, $playlist_name); + updatePlaylistNumberTimesPlayed($w, $playlist_uri); + + return; + } +} elseif ($type == 'ALBUM') { + if ($album_uri == '') { + if ($track_uri == '') { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + // case of current song with alt + $album_uri = getAlbumUriFromTrack($w, $track_uri); + if ($album_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + } + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $album_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$album_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $album_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, '🔈 Album '.$album_name.' by '.$artist_name, $album_artwork_path, 'Play Album'); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addAlbumToPlayQueue($w, $album_uri, $album_name); + + return; +} elseif ($type == 'ONLINE') { + if ($artist_uri == '') { + // case of current song with cmd + $artist_uri = getArtistUriFromTrack($w, $track_uri); + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Online▹'.$artist_uri.'@'.escapeQuery($artist_name).'▹'."\"'"); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'lookup online', 1); + + return; +} elseif ($type == 'ALBUM_OR_PLAYLIST') { + if ($add_to_option != '') { + if ($album_name != '') { + if ($album_uri == '') { + if ($track_uri == '') { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + // case of current song with shift + $album_uri = getAlbumUriFromTrack($w, $track_uri); + if ($album_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Add▹'.$album_uri.'∙'.escapeQuery($album_name).'▹'."\"'"); + + return; + } elseif ($playlist_uri != '') { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Add▹'.$playlist_uri.'∙'.escapeQuery($playlist_name).'▹'."\"'"); + + return; + } + } +} elseif ($type == 'DOWNLOAD_ARTWORKS') { + if ($use_artworks) { + if (downloadArtworks($w) == false) { + displayNotificationWithArtwork($w, 'Error when downloading artworks', './images/warning.png', 'Error!'); + + return; + } + } + + return; +} elseif ($type == 'ARTIST_OR_PLAYLIST_PRIVACY') { + + if ($artist_name != '') { + if ($artist_uri == '') { + // case of current song with cmd + $artist_uri = getArtistUriFromTrack($w, $track_uri); + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + $artist_artwork_path = getArtistArtwork($w, $artist_uri, $artist_name, true, false, false, $use_artworks); + } + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $artist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$artist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $artist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + displayNotificationWithArtwork($w, '🔈 Artist '.$artist_name, $artist_artwork_path, 'Play Artist'); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addArtistToPlayQueue($w, $artist_uri, $artist_name, $country_code); + + return; + } elseif ($playlist_uri != '') { + // case cmd on playlist: change privacy + // in other_action, the privacy is set + if ($other_action == 'set_playlist_privacy_to_public') { + $public = true; + $msgPublic = 'public'; + } elseif ($other_action == 'set_playlist_privacy_to_private') { + $public = false; + $msgPublic = 'private'; + } else { + displayNotificationWithArtwork($w, 'Error when changing playlist privacy', './images/warning.png', 'Error!'); + + return; + } + setThePlaylistPrivacy($w, $playlist_uri, $playlist_name, $public); + displayNotificationWithArtwork($w, 'Playlist is now '.$msgPublic, './images/disable_public_playlists.png', 'Change playlist privacy'); + + return; + } + + if ($other_action == 'repeating' && $output_application == 'CONNECT') { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + if (isRepeatStateSpotifyConnectActive($w)) { + setRepeatStateSpotifyConnect($w, $device_id, 'off'); + $command_output = 'Repeating is now disabled.'; + } else { + // called with COMMAND + setRepeatStateSpotifyConnect($w, $device_id, 'track'); + $command_output = 'Repeating is now enabled for current track.'; + } + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + displayNotificationWithArtwork($w, $command_output, './images/repeating.png', 'Repeating'); + + return; + } + +} elseif ($other_settings != '') { + $setting = explode('▹', $other_settings); + if ($setting[0] == 'MAX_RESULTS') { + $ret = updateSetting($w, 'max_results', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Max results set to '.$setting[1], './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'RADIO_TRACKS') { + $ret = updateSetting($w, 'radio_number_tracks', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Radio track number set to '.$setting[1], './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'VOLUME_PERCENT') { + $ret = updateSetting($w, 'volume_percent', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Volume Percentage set to '.$setting[1], './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'MOPIDY_SERVER') { + $ret = updateSetting($w, 'mopidy_server', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Mopidy server set to '.$setting[1], './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'MOPIDY_PORT') { + $ret = updateSetting($w, 'mopidy_port', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Mopidy TCP port set to '.$setting[1], './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'Oauth_Client_ID') { + $ret = updateSetting($w, 'oauth_client_id', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, "Client ID set to $setting[1]", './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'Oauth_Client_SECRET') { + $ret = updateSetting($w, 'oauth_client_secret', $setting[1]); + if ($ret == true) { + displayNotificationWithArtwork($w, "Client Secret set to $setting[1]", './images/settings.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'ALFRED_PLAYLIST') { + $ret = updateSetting($w, 'alfred_playlist_uri', $setting[1]); + if ($ret == true) { + $ret = updateSetting($w, 'alfred_playlist_name', $setting[2]); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Alfred Playlist set to '.$setting[2], getPlaylistArtwork($w, $setting[1], true, false, $use_artworks), 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($setting[0] == 'ADD_TO_PLAYLIST') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + // if playlist_uri is notset, then create it + if ($setting[1] == 'notset') { + $new_playlist_uri = createTheUserPlaylist($w, $setting[2]); + if ($new_playlist_uri != false) { + $setting[1] = $new_playlist_uri; + } else { + return; + } + } + // add track to playlist + if ($track_uri != '') { + $track_artwork_path = getTrackOrAlbumArtwork($w, $track_uri, true, false, false, $use_artworks); + $tmp = explode(':', $track_uri); + if ($tmp[1] == 'local') { + // local track, look it up online + $query = 'track:'.$track_name.' artist:'.$artist_name; + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $artists = $track->artists; + $artist = $artists[0]; + logMsg("Error(action): Unknown track $track_uri / $track_name / $artist_name replaced by track: $track->uri / $track->name / $artist->name"); + $track_uri = $track->uri; + $tmp = explode(':', $track_uri); + } else { + logMsg("Error(action): Could not find track: $track_uri / $track_name / $artist_name"); + displayNotificationWithArtwork($w, 'Local track '.$track_name.' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + $ret = addTracksToPlaylist($w, $tmp[2], $setting[1], $setting[2], false); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, ''.$track_name.' added to '.$setting[2].' playlist', $track_artwork_path, 'Add Track to Playlist'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, ''.$track_name.' is already in '.$setting[2].' playlist', './images/warning.png', 'Error!'); + + return; + } + } // add playlist to playlist + elseif ($playlist_uri != '') { + $playlist_artwork_path = getPlaylistArtwork($w, $playlist_uri, true, true, $use_artworks); + $ret = addTracksToPlaylist($w, getThePlaylistTracks($w, $playlist_uri), $setting[1], $setting[2], false); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, 'Playlist '.$playlist_name.' added to '.$setting[2].' playlist', $playlist_artwork_path, 'Add Playlist to Playlist'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Playlist '.$playlist_name.' is already in '.$setting[2].' playlist', './images/warning.png', 'Error!'); + + return; + } + } // add album to playlist + elseif ($album_uri != '') { + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + $ret = addTracksToPlaylist($w, getTheAlbumTracks($w, $album_uri), $setting[1], $setting[2], false); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, 'Album '.$album_name.' added to '.$setting[2].' playlist', $album_artwork_path, 'Add Album to Playlist'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Album '.$album_name.' is already in '.$setting[2].' playlist', './images/warning.png', 'Error!'); + + return; + } + } + } elseif ($setting[0] == 'REMOVE_FROM_PLAYLIST') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + // remove track from playlist + if ($track_uri != '') { + $track_artwork_path = getTrackOrAlbumArtwork($w, $track_uri, true, false, false, $use_artworks); + $tmp = explode(':', $track_uri); + if ($tmp[1] == 'local') { + displayNotificationWithArtwork($w, 'Cannot remove local track '.$track_name, './images/warning.png', 'Error!'); + + return; + } + $ret = removeTrackFromPlaylist($w, $tmp[2], $setting[1], $setting[2]); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + + if ($ret == true) { + displayNotificationWithArtwork($w, ''.$track_name.' removed from '.$setting[2].' playlist', $track_artwork_path, 'Remove Track from Playlist'); + + return; + } + } + } elseif ($setting[0] == 'ADD_TO_YOUR_MUSIC') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + // add track to your music + if ($track_uri != '') { + $track_artwork_path = getTrackOrAlbumArtwork($w, $track_uri, true, false, false, $use_artworks); + $tmp = explode(':', $track_uri); + if ($tmp[1] == 'local') { + // local track, look it up online + + $query = 'track:'.$track_name.' artist:'.$artist_name; + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $artists = $track->artists; + $artist = $artists[0]; + logMsg("Error(action): Unknown track $track_uri / $track_name / $artist_name replaced by track: $track->uri / $track->name / $artist->name"); + $track_uri = $track->uri; + $tmp = explode(':', $track_uri); + } else { + logMsg("Error(action): Could not find track: $track_uri / $track_name / $artist_name"); + displayNotificationWithArtwork($w, 'Local track '.$track_name.' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + $ret = addTracksToYourMusic($w, $tmp[2], false); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, ''.$track_name.' added to Your Music', $track_artwork_path, 'Add Track to Your Music'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, ''.$track_name.' is already in Your Music', './images/warning.png', 'Error!'); + + return; + } + } // add playlist to your music + elseif ($playlist_uri != '') { + $playlist_artwork_path = getPlaylistArtwork($w, $playlist_uri, true, true, $use_artworks); + $ret = addTracksToYourMusic($w, getThePlaylistTracks($w, $playlist_uri), false); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, 'Playlist '.$playlist_name.' added to Your Music', $playlist_artwork_path, 'Add Playlist to Your Music'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Playlist '.$playlist_name.' is already in Your Music', './images/warning.png', 'Error!'); + + return; + } + } // add album to your music + elseif ($album_uri != '') { + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + $ret = addTracksToYourMusic($w, getTheAlbumTracks($w, $album_uri), false); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, 'Album '.$album_name.' added to Your Music', $album_artwork_path, 'Add Album to Your Music'); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Album '.$album_name.' is already in Your Music', './images/warning.png', 'Error!'); + + return; + } + } + } elseif ($setting[0] == 'REMOVE_FROM_YOUR_MUSIC') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + // remove track from your music + if ($track_uri != '') { + $track_artwork_path = getTrackOrAlbumArtwork($w, $track_uri, true, false, false, $use_artworks); + $tmp = explode(':', $track_uri); + $ret = removeTrackFromYourMusic($w, $tmp[2]); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, ''.$track_name.' removed from Your Music', $track_artwork_path, 'Remove Track from Your Music'); + + return; + } + } + } elseif ($setting[0] == 'Open') { + exec("open \"$setting[1]\""); + + return; + } elseif ($setting[0] == 'Reveal') { + exec("open -R \"$setting[1]\""); + + return; + } elseif ($setting[0] == 'CLEAR_ALFRED_PLAYLIST') { + if ($setting[1] == '' || $setting[2] == '') { + displayNotificationWithArtwork($w, 'Alfred Playlist is not set', './images/warning.png', 'Error!'); + + return; + } + if (clearPlaylist($w, $setting[1], $setting[2])) { + displayNotificationWithArtwork($w, 'Alfred Playlist '.$setting[2].' was cleared', getPlaylistArtwork($w, $setting[1], true, false, $use_artworks), 'Clear Alfred Playlist'); + } + + return; + } elseif ($setting[0] == 'SWITCH_USER') { + + if($setting[1] == 'NEW_USER') { + newUser($w); + } else { + switchUser($w, $setting[1]); + } + + + return; + } elseif ($setting[0] == 'CHANGE_DEVICE') { + + changeUserDevice($w, $setting[1]); + return; + } +} elseif ($other_action != '') { + if ($other_action == 'disable_all_playlist') { + $ret = updateSetting($w, 'all_playlists', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Search scope set to Your Music only', './images/search_scope_yourmusic_only.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_all_playlist') { + $ret = updateSetting($w, 'all_playlists', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Search scope set to your complete library', './images/search.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_now_playing_notifications') { + $ret = updateSetting($w, 'now_playing_notifications', 1); + exec('open "'.'./App/'.$theme_color.'/Spotify Mini Player.app'.'"'); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Now Playing notifications are now enabled', './images/enable_now_playing.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_now_playing_notifications') { + exec('./src/spotify_mini_player_notifications.ksh -d "'.$w->data().'" -a stop -v "'.getAlfredName().'" >> "'.$w->cache().'/action.log" 2>&1 & '); + $ret = updateSetting($w, 'now_playing_notifications', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Now Playing notifications are now disabled', './images/disable_now_playing.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_quick_mode') { + $ret = updateSetting($w, 'quick_mode', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Quick Mode is now enabled', './images/enable_quick_mode.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_quick_mode') { + $ret = updateSetting($w, 'quick_mode', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Quick Mode is now disabled', './images/disable_quick_mode.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_artworks') { + $ret = updateSetting($w, 'use_artworks', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Artworks are now enabled, library update is started', './images/enable_artworks.png', 'Settings'); + updateLibrary($w); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_artworks') { + $ret = updateSetting($w, 'use_artworks', 0); + if ($ret == true) { + if (file_exists($w->data().'/artwork')): + exec("rm -rf '".$w->data()."/artwork'"); + displayNotificationWithArtwork($w, 'All artworks have been erased', './images/warning.png', 'Warning!'); + updateLibrary($w); + endif; + displayNotificationWithArtwork($w, 'Artworks are now disabled', './images/disable_artworks.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_display_rating') { + $ret = updateSetting($w, 'is_display_rating', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Track Rating is now enabled', './images/enable_display_rating.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_display_rating') { + $ret = updateSetting($w, 'is_display_rating', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Track Rating is now disabled', './images/disable_display_rating.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_autoplay') { + $ret = updateSetting($w, 'is_autoplay_playlist', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Playlist Autoplay is now enabled', './images/enable_autoplay.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_autoplay') { + $ret = updateSetting($w, 'is_autoplay_playlist', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Playlist Autoplay is now disabled', './images/disable_autoplay.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_use_growl') { + $ret = updateSetting($w, 'use_growl', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Growl is now enabled', './images/enable_use_growl.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_use_growl') { + $ret = updateSetting($w, 'use_growl', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Growl is now disabled', './images/disable_use_growl.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + }elseif ($other_action == 'enable_always_display_lyrics_in_browser') { + $ret = updateSetting($w, 'always_display_lyrics_in_browser', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Lyrics will be displayed in browser', './images/lyrics.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_always_display_lyrics_in_browser') { + $ret = updateSetting($w, 'always_display_lyrics_in_browser', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Lyrics will be displayed in Alfred', './images/lyrics.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'use_twitter') { + $ret = updateSetting($w, 'use_facebook', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Twitter is now used for sharing', './images/twitter.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'use_facebook') { + $ret = updateSetting($w, 'use_facebook', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Facebook is now used for sharing', './images/facebook.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_mopidy') { + exec('./src/spotify_mini_player_notifications.ksh -d "'.$w->data().'" -a stop -v "'.getAlfredName().'" >> "'.$w->cache().'/action.log" 2>&1 & '); + $ret = updateSetting($w, 'output_application', 'MOPIDY'); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Mopidy is now used', './images/mopidy.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_applescript') { + exec('./src/spotify_mini_player_notifications.ksh -d "'.$w->data().'" -a stop -v "'.getAlfredName().'" >> "'.$w->cache().'/action.log" 2>&1 & '); + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.playback.pause', array()); + } + $ret = updateSetting($w, 'output_application', 'APPLESCRIPT'); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Spotify Desktop is now used', './images/spotify.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_connect') { + exec('./src/spotify_mini_player_notifications.ksh -d "'.$w->data().'" -a stop -v "'.getAlfredName().'" >> "'.$w->cache().'/action.log" 2>&1 & '); + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.playback.pause', array()); + } + $ret = updateSetting($w, 'output_application', 'CONNECT'); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Spotify Connect is now used', './images/connect.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'change_theme_color') { + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to run trigger \"change_theme_color\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"\"'"); + return; + } elseif ($other_action == 'change_search_order') { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to run trigger \"change_search_order\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"\"'"); + return; + } elseif ($other_action == 'change_theme_color_for_real') { + + switchThemeColor($w,getenv('chosen_color')); + return; + } elseif ($other_action == 'change_search_order_for_real') { + + updateSetting($w, 'search_order', getenv('chosen_search_order')); + + displayNotificationWithArtwork($w, 'Search order results is now changed', './images/search.png', 'Settings'); + return; + } elseif ($other_action == 'enable_alfred_playlist') { + $ret = updateSetting($w, 'is_alfred_playlist_active', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Controlling Alfred Playlist', './images/alfred_playlist.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_alfred_playlist') { + $ret = updateSetting($w, 'is_alfred_playlist_active', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'Controlling Your Music', './images/yourmusic.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'enable_public_playlists') { + $ret = updateSetting($w, 'is_public_playlists', 1); + if ($ret == true) { + displayNotificationWithArtwork($w, 'New playlists will be now public', './images/enable_public_playlists.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'disable_public_playlists') { + $ret = updateSetting($w, 'is_public_playlists', 0); + if ($ret == true) { + displayNotificationWithArtwork($w, 'New playlists will be now private', './images/disable_public_playlists.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Error while updating settings', './images/settings.png', 'Error!'); + } + + return; + } elseif ($other_action == 'play_track_in_album_context') { + if ($output_application == 'MOPIDY') { + playTrackInContextWithMopidy($w, $track_uri, $album_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$track_uri\" in context \"$album_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, $track_uri, $album_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + if ($now_playing_notifications == false) { + displayNotificationWithArtwork($w, '🔈 '.$track_name.' in album '.$album_name.' by '.$artist_name, $album_artwork_path, 'Play Track from Album'); + } + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addAlbumToPlayQueue($w, $album_uri, $album_name); + + return; + } elseif ($other_action == 'play') { + + if($type == '' || $type == 'TRACK') { + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.playback.resume', array()); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playSpotifyConnect($w, $device_id); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + } else { + $track_uri = ''; + // URL can be either passed as URI or full URL (works for tracks, playlists, artists and albums) + //spotify:track:7agPIlFzTpgKnqyxUVt7aM + //https://open.spotify.com/track/7agPIlFzTpgKnqyxUVt7aM?si=Jd3E3TCERuuU6gGS5QWkFg + $tmp = explode(':', $type); + if ($tmp[1] == 'track' || $tmp[1] == 'playlist' || $tmp[1] == 'artist' || $tmp[1] == 'album') { + $track_uri = $type; + } else { + $tmp = explode('/', $type); + + if ($tmp[3] == 'track' || $tmp[3] == 'playlist' || $tmp[3] == 'artist' || $tmp[3] == 'album') { + $tmp2 = explode('?', $tmp[4]); + $track_uri = "spotify:" . $tmp[3] . ":" . $tmp2[0]; + } + } + + if($track_uri == "") { + displayNotificationWithArtwork($w, 'Could not retrieve track/artist/playlist/album with argument <'.$type.'>', './images/warning.png', 'Error!'); + return; + } + + if ($output_application == 'MOPIDY') { + playUriWithMopidyWithoutClearing($w, $track_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$track_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $tmp = explode(':', $track_uri); + if ($tmp[1] == 'track') { + playTrackSpotifyConnect($w, $device_id, $track_uri, ''); + } else { + playTrackSpotifyConnect($w, $device_id, '', $track_uri); + } + + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + } + } + } + + + return; + } elseif ($other_action == 'change_theme_color') { + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to run trigger \"change_theme_color\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"\"'"); + return; + } elseif ($other_action == 'open_spotify_app') { + + exec("osascript -e 'tell application \"Spotify\" to activate'"); + return; + } elseif ($other_action == 'pause') { + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.playback.pause', array()); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to pause'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + pauseSpotifyConnect($w, $device_id); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'playpause') { + if ($output_application == 'MOPIDY') { + $state = invokeMopidyMethod($w, 'core.playback.get_state', array()); + if ($state == 'playing') { + invokeMopidyMethod($w, 'core.playback.pause', array()); + } else { + invokeMopidyMethod($w, 'core.playback.resume', array()); + } + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to playpause'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playpauseSpotifyConnect($w, $device_id, $country_code); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'kill_update') { + killUpdate($w); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'kill update', 1); + return; + } elseif ($other_action == 'lookup_current_artist') { + lookupCurrentArtist($w); + + return; + } elseif ($other_action == 'show_in_spotify') { + showInSpotify($w); + + return; + } elseif ($other_action == 'unfollow_playlist') { + unfollowThePlaylist($w, $playlist_uri); + + return; + } elseif ($other_action == 'follow_playlist') { + followThePlaylist($w, $playlist_uri); + + return; + } elseif ($other_action == 'lyrics') { + displayLyricsForCurrentTrack($w); + + return; + } elseif ($other_action == 'current_track_radio') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + createRadioSongPlaylistForCurrentTrack($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'radio', 1); + + return; + } elseif ($other_action == 'current_artist_radio') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + createRadioArtistPlaylistForCurrentArtist($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'radio', 1); + + return; + } elseif ($other_action == 'play_current_artist') { + playCurrentArtist($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + + return; + } elseif ($other_action == 'play_current_album') { + playCurrentAlbum($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + + return; + } elseif ($other_action == 'delete_artwork_folder') { + if (file_exists($w->data().'/artwork')): + exec("rm -rf '".$w->data()."/artwork'"); + displayNotificationWithArtwork($w, 'All artworks have been erased', './images/warning.png', 'Warning!'); + updateLibrary($w); + endif; + + return; + } elseif ($other_action == 'Oauth_Login') { + // check PHP version + $version = explode('.', phpversion()); + if ($version[0] < 5 && $version[1] < 4) { + displayNotificationWithArtwork($w, 'PHP 5.4.0 or later is required for authentication', './images/warning.png', 'Error!'); + exec('open http://alfred-spotify-mini-player.com/known-issues/#php_requirement'); + + return; + } + exec("kill -9 $(ps -efx | grep \"php\" | egrep \"php -S 127.0.0.1:15298\" | grep -v grep | awk '{print $2}')"); + sleep(1); + $cache_log = $w->cache().'/spotify_mini_player_web_server.log'; + exec("php -S 127.0.0.1:15298 > \"$cache_log\" 2>&1 &"); + sleep(2); + exec('open http://127.0.0.1:15298'); + + return; + } elseif ($other_action == 'current') { + displayNotificationForCurrentTrack($w); + if ($type != 'playing') { + updateCurrentTrackIndexFromPlayQueue($w); + } + + return; + } elseif ($other_action == 'copy_current_track_url_to_clipboard') { + copyCurrentTrackUrlToClipboard($w); + + return; + } elseif ($other_action == 'current_mopidy') { + $ret = getCurrentTrackInfoWithMopidy($w, false); + echo "$ret"; + + return; + } elseif ($other_action == 'current_connect') { + $ret = getCurrentTrackInfoWithSpotifyConnect($w, false); + echo "$ret"; + + return; + } elseif ($other_action == 'add_current_track_to') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + if($type == '') { + addCurrentTrackTo($w); + } else { + $playlist_uri = $type; + addCurrentTrackTo($w,$playlist_uri); + } + + return; + } elseif ($other_action == 'remove_current_track_from') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + removeCurrentTrackFrom($w); + + return; + } elseif ($other_action == 'download_update') { + $check_results = checkForUpdate($w, 0, true); + if ($check_results != null && is_array($check_results)) { + exec("open \"$check_results[1]\""); + displayNotificationWithArtwork($w, 'Please install the new version with Alfred', './images/check_update.png', 'Update available'); + + return; + } + + return; + } elseif ($other_action == 'previous') { + if ($output_application == 'MOPIDY') { + if(getenv('previous_track_for_real') == 1) { + invokeMopidyMethod($w, 'core.playback.previous', array()); + } else { + invokeMopidyMethod($w, 'core.playback.seek', array('time_position' => 0)); + } + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to previous track'"); + if(getenv('previous_track_for_real') == 1) { + // Previous track command does not go to previous track #270 + exec("osascript -e 'tell application \"Spotify\" to previous track'"); + } + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + if(getenv('previous_track_for_real') == 1) { + previousTrackSpotifyConnect($w, $device_id); + } else { + seekToBeginning($w); + } + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'next') { + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.playback.next', array()); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to next track'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + nextTrackSpotifyConnect($w, $device_id); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'reset_playlist_number_times_played') { + resetPlaylistNumberTimesPlayed($w); + + displayNotificationWithArtwork($w, 'Reset number of times played for playlists has been done', './images/settings.png', 'Info'); + + return; + } elseif ($other_action == 'add_current_track') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + addCurrentTrackToAlfredPlaylistOrYourMusic($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'add_or_remove', 1); + + return; + } elseif ($other_action == 'random') { + list($track_uri, $track_name, $artist_name, $album_name, $duration) = getRandomTrack($w); + if ($output_application == 'MOPIDY') { + playUriWithMopidyWithoutClearing($w, $track_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$track_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, $track_uri, ''); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addTrackToPlayQueue($w, $track_uri, $track_name, $artist_name, $album_name, $duration, $country_code); + + return; + } elseif ($other_action == 'random_album') { + list($album_uri, $album_name, $theartistname) = getRandomAlbum($w); + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $album_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$album_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $album_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, '🔈 Album '.$album_name.' by '.$theartistname, getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks), 'Play Random Album'); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addAlbumToPlayQueue($w, $album_uri, $album_name); + + return; + } elseif ($other_action == 'reset_settings') { + deleteTheFile($w->data().'/settings.json'); + + return; + } elseif ($other_action == 'reset_oauth_settings') { + updateSetting($w,'oauth_access_token',''); + updateSetting($w,'oauth_refresh_token',''); + displayNotificationWithArtwork($w, 'Oauth settings have been correctly reset', './images/settings.png', 'Info'); + + return; + } elseif ($other_action == 'biography') { + displayCurrentArtistBiography($w); + return; + } elseif ($other_action == 'go_back') { + $history = $w->read('history.json'); + + if ($history == false) { + displayNotificationWithArtwork($w, 'No history yet', './images/warning.png', 'Error!'); + } + $query = array_pop($history); + // pop twice + $query = array_pop($history); + $w->write($history, 'history.json'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini')." $query\"'"); + + return; + } elseif ($other_action == 'lookup_artist') { + if (!$w->internet()) { + displayNotificationWithArtwork($w, 'No internet connection', './images/warning.png', 'Error!'); + + return; + } + if ($artist_uri == '') { + $artist_uri = getArtistUriFromTrack($w, $track_uri); + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Online▹'.$artist_uri.'@'.escapeQuery($artist_name).'▹'."\"'"); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'lookup online', 1); + + return; + } elseif ($other_action == 'playartist') { + $artist_artwork_path = getArtistArtwork($w, $artist_uri, $artist_name, true, false, false, $use_artworks); + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $artist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$artist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $artist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, '🔈 Artist '.$artist_name, $artist_artwork_path, 'Play Artist'); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addArtistToPlayQueue($w, $artist_uri, $artist_name, $country_code); + + return; + } elseif ($other_action == 'playalbum') { + if ($album_uri == '') { + if ($track_uri == '') { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + $album_uri = getAlbumUriFromTrack($w, $track_uri); + if ($album_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get album', './images/warning.png', 'Error!'); + + return; + } + } + $album_artwork_path = getTrackOrAlbumArtwork($w, $album_uri, true, false, false, $use_artworks); + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $album_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$album_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $album_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, '🔈 Album '.$album_name, $album_artwork_path, 'Play Album'); + + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + addAlbumToPlayQueue($w, $album_uri, $album_name); + + return; + } elseif ($other_action == 'volume_up') { + if ($output_application == 'MOPIDY') { + $theVolume = invokeMopidyMethod($w, 'core.mixer.get_volume', array()); + if (($theVolume + $volume_percent) > getenv('settings_volume_max')) { + $theVolume = getenv('settings_volume_max'); + $theVolume = $theVolume + 0; + displayNotificationWithArtwork($w, 'Spotify volume is at maximum level '.getenv('settings_volume_max').'%.', './images/volume_up.png', 'Volume Up'); + } else { + $theVolume = $theVolume + $volume_percent; + displayNotificationWithArtwork($w, 'Spotify volume has been increased to '.$theVolume.'%', './images/volume_up.png', 'Volume Up'); + } + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => $theVolume)); + } else if($output_application == 'APPLESCRIPT') { + $volume_max = getenv('settings_volume_max'); + $command_output = exec("osascript -e 'tell application \"Spotify\" + if it is running then + if (sound volume + $volume_percent) > $volume_max then + set theVolume to $volume_max + set sound volume to theVolume + return \"Spotify volume is at maximum level \" & theVolume & \"%.\" + else + set theVolume to (sound volume + $volume_percent) + set sound volume to theVolume + return \"Spotify volume has been increased to \" & theVolume & \"%.\" + end if + end if + end tell'"); + displayNotificationWithArtwork($w, $command_output, './images/volume_up.png', 'Volume Up'); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $theVolume = getVolumeSpotifyConnect($w,$device_id); + if(!$theVolume) { + displayNotificationWithArtwork($w, 'Cannot control volume on this Spotify Connect device', './images/warning.png', 'Error!'); + return; + } + if (($theVolume + $volume_percent) > getenv('settings_volume_max')) { + $theVolume = getenv('settings_volume_max'); + $theVolume = $theVolume + 0; + displayNotificationWithArtwork($w, 'Spotify volume is at maximum level '.getenv('settings_volume_max').'%.', './images/volume_up.png', 'Volume Up'); + } else { + $theVolume = $theVolume + $volume_percent; + displayNotificationWithArtwork($w, 'Spotify volume has been increased to '.$theVolume.'%', './images/volume_up.png', 'Volume Up'); + } + changeVolumeSpotifyConnect($w, $device_id, $theVolume); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'volume_down') { + if ($output_application == 'MOPIDY') { + $theVolume = invokeMopidyMethod($w, 'core.mixer.get_volume', array()); + if (($theVolume - $volume_percent) < getenv('settings_volume_min')) { + $theVolume = getenv('settings_volume_min'); + displayNotificationWithArtwork($w, 'Spotify volume is at minimum level '.getenv('settings_volume_min').'%.', './images/volume_down.png', 'Volume Down'); + } else { + $theVolume = $theVolume - $volume_percent; + displayNotificationWithArtwork($w, 'Spotify volume has been decreased to '.$theVolume.'%', './images/volume_down.png', 'Volume Down'); + } + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => $theVolume)); + } else if($output_application == 'APPLESCRIPT') { + $volume_min = getenv('settings_volume_min'); + $command_output = exec("osascript -e 'tell application \"Spotify\" + if it is running then + if (sound volume - $volume_percent) < $volume_min then + set theVolume to $volume_min + set sound volume to theVolume + return \"Spotify volume is at minimum level \" & theVolume & \"%.\" + else + set theVolume to (sound volume - $volume_percent) + set sound volume to theVolume + return \"Spotify volume has been decreased to \" & theVolume & \"%.\" + end if + set sound volume to theVolume + end if + end tell'"); + displayNotificationWithArtwork($w, $command_output, './images/volume_down.png', 'Volume Down'); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $theVolume = getVolumeSpotifyConnect($w,$device_id); + if(!$theVolume) { + displayNotificationWithArtwork($w, 'Cannot control volume on this Spotify Connect device', './images/warning.png', 'Error!'); + return; + } + if (($theVolume - $volume_percent) < getenv('settings_volume_min')) { + $theVolume = getenv('settings_volume_min'); + displayNotificationWithArtwork($w, 'Spotify volume is at minimum level '.getenv('settings_volume_min').'%.', './images/volume_down.png', 'Volume Down'); + } else { + $theVolume = $theVolume - $volume_percent; + displayNotificationWithArtwork($w, 'Spotify volume has been decreased to '.$theVolume.'%', './images/volume_down.png', 'Volume Down'); + } + changeVolumeSpotifyConnect($w, $device_id, $theVolume); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + + return; + } elseif ($other_action == 'volmax') { + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => getenv('settings_volume_max'))); + } else if($output_application == 'APPLESCRIPT') { + $volume_max = getenv('settings_volume_max'); + exec("osascript -e 'tell application \"Spotify\" + if it is running then + set sound volume to $volume_max + end if + end tell'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $theVolume = getVolumeSpotifyConnect($w,$device_id); + if(!$theVolume) { + displayNotificationWithArtwork($w, 'Cannot control volume on this Spotify Connect device', './images/warning.png', 'Error!'); + return; + } + $volume_max = getenv('settings_volume_max'); + changeVolumeSpotifyConnect($w, $device_id, $volume_max); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, 'Spotify volume has been set to maximum '.$volume_max.'%', './images/volmax.png', 'Volume Max'); + + return; + } elseif ($other_action == 'volmid') { + if ($output_application == 'MOPIDY') { + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => getenv('settings_volume_mid'))); + } else if($output_application == 'APPLESCRIPT') { + $volume_mid = getenv('settings_volume_mid'); + exec("osascript -e 'tell application \"Spotify\" + if it is running then + set sound volume to $volume_mid + end if + end tell'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $theVolume = getVolumeSpotifyConnect($w,$device_id); + if(!$theVolume) { + displayNotificationWithArtwork($w, 'Cannot control volume on this Spotify Connect device', './images/warning.png', 'Error!'); + return; + } + $volume_mid = getenv('settings_volume_mid'); + changeVolumeSpotifyConnect($w, $device_id, $volume_mid); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, 'Spotify volume has been set to '.$volume_mid.'%', './images/volmid.png', 'Volume '.$volume_mid.'%'); + + return; + } elseif ($other_action == 'mute') { + $volume_max = getenv('settings_volume_max'); + $volume_min = getenv('settings_volume_min'); + if ($output_application == 'MOPIDY') { + $volume = invokeMopidyMethod($w, 'core.mixer.get_volume', array()); + if ($volume <= 0) { + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => $volume_max)); + $command_output = 'Spotify volume is unmuted.'; + } else { + invokeMopidyMethod($w, 'core.mixer.set_volume', array('volume' => $volume_min)); + $command_output = 'Spotify volume is muted.'; + } + } else if($output_application == 'APPLESCRIPT') { + $command_output = exec("osascript -e 'tell application \"Spotify\" + if sound volume is less than or equal to $volume_min then + set sound volume to $volume_max + return \"Spotify volume is unmuted.\" + else + set sound volume to $volume_min + return \"Spotify volume is muted.\" + end if + end tell'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + $theVolume = getVolumeSpotifyConnect($w,$device_id); + if(!$theVolume) { + displayNotificationWithArtwork($w, 'Cannot control volume on this Spotify Connect device', './images/warning.png', 'Error!'); + return; + } + if ($theVolume <= 0) { + changeVolumeSpotifyConnect($w, $device_id, $volume_max); + $command_output = 'Spotify volume is unmuted.'; + } else { + if($volume_min == 0) { + // there is a bug that if we set 0 then volume + // control is no more possible + $volume_min = 5; + } + changeVolumeSpotifyConnect($w, $device_id, $volume_min); + $command_output = 'Spotify volume is muted.'; + } + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, $command_output, './images/mute.png', 'Mute'); + + return; + } elseif ($other_action == 'shuffle') { + if ($output_application == 'MOPIDY') { + $isShuffleEnabled = invokeMopidyMethod($w, 'core.tracklist.get_random', array()); + if ($isShuffleEnabled) { + invokeMopidyMethod($w, 'core.tracklist.set_random', array('value' => false)); + $command_output = 'Shuffle is now disabled.'; + } else { + invokeMopidyMethod($w, 'core.tracklist.set_random', array('value' => true)); + $command_output = 'Shuffle is now enabled.'; + } + } else if($output_application == 'APPLESCRIPT') { + $command_output = exec("osascript -e ' + tell application \"Spotify\" + if shuffling enabled is true then + if shuffling is true then + set shuffling to false + return \"Shuffle is now disabled.\" + else + set shuffling to true + return \"Shuffle is now enabled.\" + end if + else + return \"Shuffle is not currently enabled.\" + end if + end tell'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + if (isShuffleActive(false) == 'true') { + setShuffleStateSpotifyConnect($w, $device_id, false); + $command_output = 'Shuffle is now disabled.'; + } else { + setShuffleStateSpotifyConnect($w, $device_id, true); + $command_output = 'Shuffle is now enabled.'; + } + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, $command_output, './images/shuffle.png', 'Shuffle'); + + return; + } elseif ($other_action == 'web_search') { + $search_text = getCurrentArtistAndTrackName($w, $output_application); + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to run trigger \"web_search\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"" . $search_text . "\"'"); + return; + } elseif ($other_action == 'web_search_artist_track') { + $search_text = getCurrentArtistAndTrackName($w, $output_application); + + $tmp = explode('▹',$search_text); + + echo "$tmp[1] $tmp[0]"; + + return; + } elseif ($other_action == 'web_search_artist') { + $search_text = getCurrentArtistAndTrackName($w, $output_application); + + $tmp = explode('▹',$search_text); + + echo "$tmp[1]"; + + return; + } elseif ($other_action == 'share') { + if ($output_application == 'MOPIDY') { + $ret = getCurrentTrackInfoWithMopidy($w, false); + $results = explode('▹', $ret); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + } + } else { + $ret = getCurrentTrackInfoWithSpotifyConnect($w, false); + $results = explode('▹', $ret); + } + + if (!isset($results[0])) { + displayNotificationWithArtwork($w, 'Cannot get current track', './images/warning.png', 'Error!'); + return; + } + + if($use_facebook) { + $service = 'facebook'; + } else { + $service = 'twitter'; + } + $text = getenv('sharing_hashtag1'); + $text .= ' '; + $text .= escapeQuery($results[0]); + $text .= ' by '; + $text .= escapeQuery($results[1]); + $text .= ' '; + if(getenv('sharing_text1') != '') { + $text .= getenv('sharing_text1'); + $text .= ' '; + } + if(getenv('sharing_text2') != '') { + $text .= getenv('sharing_text2'); + $text .= ' '; + } + if(getenv('sharing_hashtag2') != '') { + $text .= getenv('sharing_hashtag2'); + $text .= ' '; + } + + $tmp = explode(':', $results[4]); + if ($tmp[1] != 'local') { + $text .= ' https://open.spotify.com/track/'; + $text .= $tmp[2]; + } + exec("./terminal-share.app/Contents/MacOS/terminal-share -service '".$service."' -text '".$text."'"); + + return; + } elseif ($other_action == 'repeating') { + if ($output_application == 'MOPIDY') { + $isRepeatingEnabled = invokeMopidyMethod($w, 'core.tracklist.get_repeat', array()); + if ($isRepeatingEnabled) { + invokeMopidyMethod($w, 'core.tracklist.set_repeat', array('value' => false)); + $command_output = 'Repeating is now disabled.'; + } else { + invokeMopidyMethod($w, 'core.tracklist.set_repeat', array('value' => true)); + $command_output = 'Repeating is now enabled.'; + } + } else if($output_application == 'APPLESCRIPT') { + $command_output = exec("osascript -e ' + tell application \"Spotify\" + if repeating enabled is true then + if repeating is true then + set repeating to false + return \"Repeating is now disabled.\" + else + set repeating to true + return \"Repeating is now enabled.\" + end if + else + return \"Repeating is not currently enabled.\" + end if + end tell'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + if (isRepeatStateSpotifyConnectActive($w)) { + setRepeatStateSpotifyConnect($w, $device_id, 'off'); + $command_output = 'Repeating is now disabled.'; + } else { + setRepeatStateSpotifyConnect($w, $device_id, 'context'); + $command_output = 'Repeating is now enabled.'; + } + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + displayNotificationWithArtwork($w, $command_output, './images/repeating.png', 'Repeating'); + + return; + } elseif ($other_action == 'spot_mini_debug') { + createDebugFile($w); + + return; + } elseif ($other_action == 'radio_artist') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + createRadioArtistPlaylist($w, $artist_name, $artist_uri); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'radio', 1); + + return; + } elseif ($other_action == 'complete_collection_artist') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + createCompleteCollectionArtistPlaylist($w, $artist_name, $artist_uri); + + return; + } elseif ($other_action == 'show_alfred_playlist') { + + if($alfred_playlist_uri != '' ) { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Playlist▹'.$alfred_playlist_uri.'▹'."\"'"); + } else { + displayNotificationWithArtwork($w, 'Alfred Playlist is not set', './images/warning.png', 'Error!'); + } + + return; + } elseif ($other_action == 'play_alfred_playlist') { + playAlfredPlaylist($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'play', 1); + + return; + } elseif ($other_action == 'update_library') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + updateLibrary($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'update library', 1); + + return; + } elseif ($other_action == 'refresh_library') { + if (file_exists($w->data().'/update_library_in_progress')) { + displayNotificationWithArtwork($w, 'Cannot modify library while update is in progress', './images/warning.png', 'Error!'); + + return; + } + refreshLibrary($w); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'update library', 1); + + return; + } +} diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/alerter.ksh b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/alerter.ksh new file mode 100755 index 0000000..348dcbe --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/alerter.ksh @@ -0,0 +1,39 @@ +#!/bin/ksh + +title="$1" +theme_color="$2" +subtitle="$3" +alfred_name="$4" + +actions="" +if [[ "${title}" == Now* ]] +then + actions="-actions Next,Pause,Lyrics,Add,Share" +fi + +APPICON="/tmp/tmp_"$(whoami) +ANSWER=$(./alerter -title "${title}" -sender "com.spotify.miniplayer.${theme_color}" -appIcon "${APPICON}" -message "${subtitle}" -closeLabel Close ${actions} -timeout 10 -group com.spotify.miniplayer -remove com.spotify.miniplayer) +case ${ANSWER} in + "@TIMEOUT") echo "Timeout man, sorry" ;; + "@CLOSED") echo "You clicked on the default alert' close button" ;; + "@CONTENTCLICKED") open -a "Spotify" ;; + #"@ACTIONCLICKED") echo "You clicked the alert default action button" ;; + "Next") + osascript -e "tell application id \"$alfred_name\" to run trigger \"next\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"test\"" + ;; + "Pause") + osascript -e "tell application id \"$alfred_name\" to run trigger \"playpause\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"test\"" + ;; + "Lyrics") + osascript -e "tell application id \"$alfred_name\" to run trigger \"lyrics\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"test\"" + ;; + "Add") + osascript -e "tell application id \"$alfred_name\" to run trigger \"add_current_track_to\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"test\"" + ;; + "Share") + osascript -e "tell application id \"$alfred_name\" to run trigger \"share\" in workflow \"com.vdesabou.spotify.mini.player\" with argument \"test\"" + ;; + **) + echo "? --> $ANSWER" + ;; +esac diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/country_names.json b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/country_names.json new file mode 100644 index 0000000..4e216c8 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/country_names.json @@ -0,0 +1,252 @@ +{ + "BD": "Bangladesh", + "BE": "Belgium", + "BF": "Burkina Faso", + "BG": "Bulgaria", + "BA": "Bosnia and Herzegovina", + "BB": "Barbados", + "WF": "Wallis and Futuna", + "BL": "Saint Barthelemy", + "BM": "Bermuda", + "BN": "Brunei", + "BO": "Bolivia", + "BH": "Bahrain", + "BI": "Burundi", + "BJ": "Benin", + "BT": "Bhutan", + "JM": "Jamaica", + "BV": "Bouvet Island", + "BW": "Botswana", + "WS": "Samoa", + "BQ": "Bonaire, Saint Eustatius and Saba ", + "BR": "Brazil", + "BS": "Bahamas", + "JE": "Jersey", + "BY": "Belarus", + "BZ": "Belize", + "RU": "Russia", + "RW": "Rwanda", + "RS": "Serbia", + "TL": "East Timor", + "RE": "Reunion", + "TM": "Turkmenistan", + "TJ": "Tajikistan", + "RO": "Romania", + "TK": "Tokelau", + "GW": "Guinea-Bissau", + "GU": "Guam", + "GT": "Guatemala", + "GS": "South Georgia and the South Sandwich Islands", + "GR": "Greece", + "GQ": "Equatorial Guinea", + "GP": "Guadeloupe", + "JP": "Japan", + "GY": "Guyana", + "GG": "Guernsey", + "GF": "French Guiana", + "GE": "Georgia", + "GD": "Grenada", + "GB": "United Kingdom", + "GA": "Gabon", + "SV": "El Salvador", + "GN": "Guinea", + "GM": "Gambia", + "GL": "Greenland", + "GI": "Gibraltar", + "GH": "Ghana", + "OM": "Oman", + "TN": "Tunisia", + "JO": "Jordan", + "HR": "Croatia", + "HT": "Haiti", + "HU": "Hungary", + "HK": "Hong Kong", + "HN": "Honduras", + "HM": "Heard Island and McDonald Islands", + "VE": "Venezuela", + "PR": "Puerto Rico", + "PS": "Palestinian Territory", + "PW": "Palau", + "PT": "Portugal", + "SJ": "Svalbard and Jan Mayen", + "PY": "Paraguay", + "IQ": "Iraq", + "PA": "Panama", + "PF": "French Polynesia", + "PG": "Papua New Guinea", + "PE": "Peru", + "PK": "Pakistan", + "PH": "Philippines", + "PN": "Pitcairn", + "PL": "Poland", + "PM": "Saint Pierre and Miquelon", + "ZM": "Zambia", + "EH": "Western Sahara", + "EE": "Estonia", + "EG": "Egypt", + "ZA": "South Africa", + "EC": "Ecuador", + "IT": "Italy", + "VN": "Vietnam", + "SB": "Solomon Islands", + "ET": "Ethiopia", + "SO": "Somalia", + "ZW": "Zimbabwe", + "SA": "Saudi Arabia", + "ES": "Spain", + "ER": "Eritrea", + "ME": "Montenegro", + "MD": "Moldova", + "MG": "Madagascar", + "MF": "Saint Martin", + "MA": "Morocco", + "MC": "Monaco", + "UZ": "Uzbekistan", + "MM": "Myanmar", + "ML": "Mali", + "MO": "Macao", + "MN": "Mongolia", + "MH": "Marshall Islands", + "MK": "Macedonia", + "MU": "Mauritius", + "MT": "Malta", + "MW": "Malawi", + "MV": "Maldives", + "MQ": "Martinique", + "MP": "Northern Mariana Islands", + "MS": "Montserrat", + "MR": "Mauritania", + "IM": "Isle of Man", + "UG": "Uganda", + "TZ": "Tanzania", + "MY": "Malaysia", + "MX": "Mexico", + "IL": "Israel", + "FR": "France", + "IO": "British Indian Ocean Territory", + "SH": "Saint Helena", + "FI": "Finland", + "FJ": "Fiji", + "FK": "Falkland Islands", + "FM": "Micronesia", + "FO": "Faroe Islands", + "NI": "Nicaragua", + "NL": "Netherlands", + "NO": "Norway", + "NA": "Namibia", + "VU": "Vanuatu", + "NC": "New Caledonia", + "NE": "Niger", + "NF": "Norfolk Island", + "NG": "Nigeria", + "NZ": "New Zealand", + "NP": "Nepal", + "NR": "Nauru", + "NU": "Niue", + "CK": "Cook Islands", + "XK": "Kosovo", + "CI": "Ivory Coast", + "CH": "Switzerland", + "CO": "Colombia", + "CN": "China", + "CM": "Cameroon", + "CL": "Chile", + "CC": "Cocos Islands", + "CA": "Canada", + "CG": "Republic of the Congo", + "CF": "Central African Republic", + "CD": "Democratic Republic of the Congo", + "CZ": "Czech Republic", + "CY": "Cyprus", + "CX": "Christmas Island", + "CR": "Costa Rica", + "CW": "Curacao", + "CV": "Cape Verde", + "CU": "Cuba", + "SZ": "Swaziland", + "SY": "Syria", + "SX": "Sint Maarten", + "KG": "Kyrgyzstan", + "KE": "Kenya", + "SS": "South Sudan", + "SR": "Suriname", + "KI": "Kiribati", + "KH": "Cambodia", + "KN": "Saint Kitts and Nevis", + "KM": "Comoros", + "ST": "Sao Tome and Principe", + "SK": "Slovakia", + "KR": "South Korea", + "SI": "Slovenia", + "KP": "North Korea", + "KW": "Kuwait", + "SN": "Senegal", + "SM": "San Marino", + "SL": "Sierra Leone", + "SC": "Seychelles", + "KZ": "Kazakhstan", + "KY": "Cayman Islands", + "SG": "Singapore", + "SE": "Sweden", + "SD": "Sudan", + "DO": "Dominican Republic", + "DM": "Dominica", + "DJ": "Djibouti", + "DK": "Denmark", + "VG": "British Virgin Islands", + "DE": "Germany", + "YE": "Yemen", + "DZ": "Algeria", + "US": "United States", + "UY": "Uruguay", + "YT": "Mayotte", + "UM": "United States Minor Outlying Islands", + "LB": "Lebanon", + "LC": "Saint Lucia", + "LA": "Laos", + "TV": "Tuvalu", + "TW": "Taiwan", + "TT": "Trinidad and Tobago", + "TR": "Turkey", + "LK": "Sri Lanka", + "LI": "Liechtenstein", + "LV": "Latvia", + "TO": "Tonga", + "LT": "Lithuania", + "LU": "Luxembourg", + "LR": "Liberia", + "LS": "Lesotho", + "TH": "Thailand", + "TF": "French Southern Territories", + "TG": "Togo", + "TD": "Chad", + "TC": "Turks and Caicos Islands", + "LY": "Libya", + "VA": "Vatican", + "VC": "Saint Vincent and the Grenadines", + "AE": "United Arab Emirates", + "AD": "Andorra", + "AG": "Antigua and Barbuda", + "AF": "Afghanistan", + "AI": "Anguilla", + "VI": "U.S. Virgin Islands", + "IS": "Iceland", + "IR": "Iran", + "AM": "Armenia", + "AL": "Albania", + "AO": "Angola", + "AQ": "Antarctica", + "AS": "American Samoa", + "AR": "Argentina", + "AU": "Australia", + "AT": "Austria", + "AW": "Aruba", + "IN": "India", + "AX": "Aland Islands", + "AZ": "Azerbaijan", + "IE": "Ireland", + "ID": "Indonesia", + "UA": "Ukraine", + "QA": "Qatar", + "MZ": "Mozambique" +} diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/debug.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/debug.php new file mode 100644 index 0000000..10d4ac3 --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/debug.php @@ -0,0 +1,295 @@ + 1) { + if (startsWith($query, 'DB Exception')) { + $w->result(null, '', 'DB Exception occurred: '.$query,array( + 'Try to re-create library as explained below.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(uniqid(), '', 'There is a problem with the library, try to re-create it.',array( + 'Select Re-Create Library library below', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(uniqid(), serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'update_library' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '', + /* $alfred_playlist_name */ + )), 'Re-Create Library', "when done you'll receive a notification. you can check progress by invoking the workflow again", './images/update.png', 'yes', null, ''); + } elseif (startsWith($query, 'AppleScript Exception')) { + $w->result(null, 'help', 'AppleScript execution failed!',array( + 'Message: '.$query, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/blog/issue-with-latest-spotify-update/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Maybe you have an issue with a Broken Spotify version?', 'Go to the article to get more information', './images/website.png', 'yes', null, ''); + } elseif (startsWith($query, 'Mopidy Exception')) { + $w->result(null, 'help', 'Mopidy execution failed!',array( + 'Message: '.$query, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/articles/mopidy/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Is Mopidy correctly installed and running?', 'Go to the article to get more information', './images/website.png', 'yes', null, ''); + } elseif (startsWith($query, 'Refresh token revoked')) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_oauth_settings' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'The workflow needs to re-authenticate, click to restart authentication', array( + 'Next time you invoke the workflow, you will have to re-authenticate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'yes', null, ''); + echo $w->tojson(); + return; + } else { + $w->result(null, '', 'Exception occurred: '.$query,array( + 'Use the Send an email to the author option below to send generated spot_mini_debug.zip', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } +} + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'spot_mini_debug' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ +)), 'Send an email to the author with a link to generated spot_mini_debug.zip file', 'This will open your default mail application, with all needed information for troubleshooting.', './images/mail.png', 'yes', null, ''); + +$w->result(null, '', 'Quick access to workflow folders:',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.$w->data() /* other_settings*/, + '' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '' /* $alfred_playlist_name */, + '' /* now_playing_notifications */, + '' /* is_alfred_playlist_active */, + '' /* country_code*/, + '', /* userid*/ +)), 'Browse to App Support Folder', 'This will open the folder in Finder', 'fileicon:'.$w->data(), 'yes', null, ''); + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.$w->cache() /* other_settings*/, + '' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '' /* $alfred_playlist_name */, + '' /* now_playing_notifications */, + '' /* is_alfred_playlist_active */, + '' /* country_code*/, + '', /* userid*/ +)), 'Browse to Workflow Cache Folder', 'This will open the folder in Finder', 'fileicon:'.$w->cache(), 'yes', null, ''); + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.exec('pwd') /* other_settings*/, + '' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '' /* $alfred_playlist_name */, + '' /* now_playing_notifications */, + '' /* is_alfred_playlist_active */, + '' /* country_code*/, + '', /* userid*/ +)), 'Browse to Alfred workflow folder', 'This will open the folder in Finder', 'fileicon:'.exec('pwd'), 'yes', null, ''); + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.$w->cache().'/action.log'/* other_settings*/, + '' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '' /* $alfred_playlist_name */, + '' /* now_playing_notifications */, + '' /* is_alfred_playlist_active */, + '' /* country_code*/, + '', /* userid*/ +)), 'Open log file', 'This will open the log file', 'fileicon:'.$w->cache().'/action.log', 'yes', null, ''); + +$w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'delete_artwork_folder' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '' /* $alfred_playlist_name */, + '' /* now_playing_notifications */, + '' /* is_alfred_playlist_active */, + '' /* country_code*/, + '', /* userid*/ +)), 'Delete artwork folder', 'This will erase all existing artworks and re-download them', './images/warning.png', 'yes', null, ''); + +echo $w->tojson(); diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/firstDelimiter.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/firstDelimiter.php new file mode 100644 index 0000000..283c50c --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/firstDelimiter.php @@ -0,0 +1,3650 @@ +all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + + // Search playlists + + $theplaylist = $words[1]; + try { + if (mb_strlen($theplaylist) < 2) { + $getPlaylists = 'select uri,name,nb_tracks,author,username,playlist_artwork_path,ownedbyuser,nb_playable_tracks,duration_playlist,collaborative,public,nb_times_played from playlists order by nb_times_played desc'; + $stmt = $db->prepare($getPlaylists); + } else { + $getPlaylists = 'select uri,name,nb_tracks,author,username,playlist_artwork_path,ownedbyuser,nb_playable_tracks,duration_playlist,collaborative,public,nb_times_played from playlists where (name like :query or author like :query) order by nb_times_played desc'; + $stmt = $db->prepare($getPlaylists); + $stmt->bindValue(':query', '%'.$theplaylist.'%'); + } + + $playlists = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + exit; + } + + $noresult = true; + if ($query == 'Playlist▹Artist radio') { + while ($playlist = $stmt->fetch()) { + $noresult = false; + if ($playlist[9]) { + $public_status = 'collaborative'; + } else { + if ($playlist[10]) { + $public_status = 'public'; + } else { + $public_status = 'private'; + } + } + if (startswith($playlist[1], 'Artist radio for')) { + $w->result(null, '', '🎵 '.$playlist[1],array( + $public_status.' playlist by '.$playlist[3].' ● '.$playlist[7].' tracks ● '.$playlist[8].' ● '.$playlist[11].' times played', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $playlist[5], 'no', null, 'Playlist▹'.$playlist[0].'▹'); + } + } + } elseif ($query == 'Playlist▹Song radio') { + while ($playlist = $stmt->fetch()) { + $noresult = false; + if ($playlist[9]) { + $public_status = 'collaborative'; + } else { + if ($playlist[10]) { + $public_status = 'public'; + } else { + $public_status = 'private'; + } + } + if (startswith($playlist[1], 'Song radio for')) { + $w->result(null, '', '🎵 '.$playlist[1],array( + $public_status.' playlist by '.$playlist[3].' ● '.$playlist[7].' tracks ● '.$playlist[8].' ● '.$playlist[11].' times played', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $playlist[5], 'no', null, 'Playlist▹'.$playlist[0].'▹'); + } + } + } else { + $savedPlaylists = array(); + $nb_artist_radio_playlist = 0; + $nb_song_radio_playlist = 0; + while ($playlist = $stmt->fetch()) { + if (startswith($playlist[1], 'Artist radio for')) { + ++$nb_artist_radio_playlist; + continue; + } + + if (startswith($playlist[1], 'Song radio for')) { + ++$nb_song_radio_playlist; + continue; + } + + $savedPlaylists[] = $playlist; + } + + if (mb_strlen($theplaylist) < 2) { + if ($nb_artist_radio_playlist > 0) { + $w->result(null, '', 'Browse your artist radio playlists ('.$nb_artist_radio_playlist.' playlists)',array( + 'Display all your artist radio playlists', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/radio_artist.png', 'no', null, 'Playlist▹Artist radio'); + } + if ($nb_song_radio_playlist > 0) { + $w->result(null, '', 'Browse your song radio playlists ('.$nb_song_radio_playlist.' playlists)',array( + 'Display all your song radio playlists', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/radio_song.png', 'no', null, 'Playlist▹Song radio'); + } + $w->result(null, '', 'Featured Playlists',array( + 'Browse the current featured playlists', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/star.png', 'no', null, 'Featured Playlist▹'); + } + + foreach ($savedPlaylists as $playlist) { + $noresult = false; + $added = ' '; + if ($playlist[9]) { + $public_status = 'collaborative'; + } else { + if ($playlist[10]) { + $public_status = 'public'; + } else { + $public_status = 'private'; + } + } + $w->result(null, '', '🎵'.$added.$playlist[1],array( + $public_status.' playlist by '.$playlist[3].' ● '.$playlist[7].' tracks ● '.$playlist[8].' ● '.$playlist[11].' times played', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $playlist[5], 'no', null, 'Playlist▹'.$playlist[0].'▹'); + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for your search',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_playlist_number_times_played' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Reset number of times played for playlists', 'This will reset playlists all times played counters to 0', './images/settings.png', 'yes', ''); +} + +/** + * firstDelimiterArtists function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterArtists($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $output_application = $settings->output_application; + + // Search artists + + $artist = $words[1]; + + try { + if (mb_strlen($artist) < 2) { + if ($all_playlists == false) { + $getTracks = 'select artist_name,artist_artwork_path,artist_uri,uri from tracks where yourmusic=1 group by artist_name'.' limit '.$max_results; + } else { + $getTracks = 'select artist_name,artist_artwork_path,artist_uri,uri from tracks group by artist_name'.' limit '.$max_results; + } + $stmt = $db->prepare($getTracks); + } else { + if ($all_playlists == false) { + $getTracks = 'select artist_name,artist_artwork_path,artist_uri,uri from tracks where yourmusic=1 and artist_name like :query limit '.$max_results; + } else { + $getTracks = 'select artist_name,artist_artwork_path,artist_uri,uri from tracks where artist_name like :query limit '.$max_results; + } + $stmt = $db->prepare($getTracks); + $stmt->bindValue(':query', '%'.$artist.'%'); + } + + $tracks = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + exit; + } + + // display all artists + $noresult = true; + while ($track = $stmt->fetch()) { + $noresult = false; + $nb_artist_tracks = getNumberOfTracksForArtist($db, $track[0]); + if (checkIfResultAlreadyThere($w->results(), '👤 '.$track[0].' ('.$nb_artist_tracks.' tracks)') == false) { + $uri = $track[2]; + // in case of local track, pass track uri instead + if ($uri == '') { + $uri = $track[3]; + } + + $w->result(null, '', '👤 '.$track[0].' ('.$nb_artist_tracks.' tracks)',array( + 'Browse this artist', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $track[1], 'no', null, 'Artist▹'.$uri.'∙'.$track[0].'▹'); + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for your search',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + if ($output_application != 'MOPIDY') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + base64_encode('artist:'.$artist) /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + '' /* other_action */, + + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Search for artist '.$artist.' in Spotify', array( + 'This will start a new search in Spotify', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/spotify.png', 'yes', null, ''); + } + } +} + +/** + * firstDelimiterAlbums function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterAlbums($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $output_application = $settings->output_application; + + // New Releases menu + $w->result(null, '', 'New Releases',array( + 'Browse new album releases', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/new_releases.png', 'no', null, 'New Releases▹'); + + // Search albums + + $album = $words[1]; + try { + if (mb_strlen($album) < 2) { + if ($all_playlists == false) { + $getTracks = 'select album_name,album_artwork_path,artist_name,album_uri,album_type from tracks where yourmusic=1'.' group by album_name order by max(added_at) desc limit '.$max_results; + } else { + $getTracks = 'select album_name,album_artwork_path,artist_name,album_uri,album_type from tracks group by album_name order by max(added_at) desc limit '.$max_results; + } + $stmt = $db->prepare($getTracks); + } else { + if ($all_playlists == false) { + $getTracks = 'select album_name,album_artwork_path,artist_name,album_uri,album_type from tracks where yourmusic=1 and album_name like :query group by album_name order by max(added_at) desc limit '.$max_results; + } else { + $getTracks = 'select album_name,album_artwork_path,artist_name,album_uri,album_type from tracks where album_name like :query group by album_name order by max(added_at) desc limit '.$max_results; + } + $stmt = $db->prepare($getTracks); + $stmt->bindValue(':query', '%'.$album.'%'); + } + + $tracks = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + exit; + } + + // display all albums + $noresult = true; + while ($track = $stmt->fetch()) { + $noresult = false; + $nb_album_tracks = getNumberOfTracksForAlbum($db, $track[3]); + if (checkIfResultAlreadyThere($w->results(), $track[0].' ('.$nb_album_tracks.' tracks)') == false) { + $w->result(null, '', $track[0].' ('.$nb_album_tracks.' tracks)',array( + $track[4].' by '.$track[2], + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $track[1], 'no', null, 'Album▹'.$track[3].'∙'.$track[0].'▹'); + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for your search',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + if ($output_application != 'MOPIDY') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + base64_encode('album:'.$album) /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Search for album '.$album.' in Spotify', array( + 'This will start a new search in Spotify', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available' + ), './images/spotify.png', 'yes', null, ''); + } + } +} + +/** + * firstDelimiterFeaturedPlaylist function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterFeaturedPlaylist($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $search = $words[1]; + + $country_code = $settings->country_code; + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName($country_code)), strtolower($search)) !== false) { + $w->result(null, '', getCountryName($country_code),array( + 'Browse the current featured playlists in '.getCountryName($country_code), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/star.png', 'no', null, 'Featured Playlist▹'.$country_code.'▹'); + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('US')), strtolower($search)) !== false) { + if ($country_code != 'US') { + $w->result(null, '', getCountryName('US'),array( + 'Browse the current featured playlists in '.getCountryName('US'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/star.png', 'no', null, 'Featured Playlist▹US▹'); + } + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('GB')), strtolower($search)) !== false) { + if ($country_code != 'GB') { + $w->result(null, '', getCountryName('GB'),array( + 'Browse the current featured playlists in '.getCountryName('GB'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/star.png', 'no', null, 'Featured Playlist▹GB▹'); + } + } + + if (mb_strlen($search) < 2 || strpos(strtolower('Choose Another country'), strtolower($search)) !== false) { + $w->result(null, '', 'Choose Another country',array( + 'Browse the current featured playlists in another country of your choice', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/star.png', 'no', null, 'Featured Playlist▹Choose a Country▹'); + } +} + +/** + * firstDelimiterSearchOnline function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterSearchOnline($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + $search_order = $settings->search_order; + + // Search online + + $the_query = $words[1].'*'; + + if (mb_strlen($the_query) < 2) { + if ($kind == 'Search Online') { + $w->result(null, 'help', 'Search for playlists, artists, albums or tracks online, i.e not in your library',array( + 'Begin typing at least 3 characters to start search online. This is using slow Spotify API be patient.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + + $w->result(null, null, 'Search for playlists only', array( + 'This will search for playlists online, i.e not in your library', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/playlists.png', 'no', null, 'Search Playlists Online▹'); + + $w->result(null, null, 'Search for tracks only', array( + 'This will search for tracks online, i.e not in your library', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/tracks.png', 'no', null, 'Search Tracks Online▹'); + + $w->result(null, null, 'Search for artists only', array( + 'This will search for artists online, i.e not in your library', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/artists.png', 'no', null, 'Search Artists Online▹'); + + $w->result(null, null, 'Search for albums only', array( + 'This will search for albums online, i.e not in your library', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/albums.png', 'no', null, 'Search Albums Online▹'); + } elseif ($kind == 'Search Playlists Online') { + $w->result(null, 'help', 'Search playlists online, i.e not in your library',array( + 'Begin typing at least 3 characters to start search online. This is using slow Spotify API be patient.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } elseif ($kind == 'Search Artists Online') { + $w->result(null, 'help', 'Search artists online, i.e not in your library',array( + 'Begin typing at least 3 characters to start search online. This is using slow Spotify API be patient.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } elseif ($kind == 'Search Tracks Online') { + $w->result(null, 'help', 'Search tracks online, i.e not in your library',array( + 'Begin typing at least 3 characters to start search online. This is using slow Spotify API be patient.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } elseif ($kind == 'Search Albums Online') { + $w->result(null, 'help', 'Search albums online, i.e not in your library',array( + 'Begin typing at least 3 characters to start search online. This is using slow Spotify API be patient.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } + } else { + $search_playlists = false; + $search_artists = false; + $search_albums = false; + $search_tracks = false; + + if ($kind == 'Search Online') { + $search_playlists = true; + $search_artists = true; + $search_albums = true; + $search_tracks = true; + $search_playlists_limit = 8; + $search_artists_limit = 5; + $search_albums_limit = 5; + $search_tracks_limit = 20; + } elseif ($kind == 'Search Playlists Online') { + $search_playlists = true; + $search_playlists_limit = ($max_results <= 50) ? $max_results : 50; + } elseif ($kind == 'Search Artists Online') { + $search_artists = true; + $search_artists_limit = ($max_results <= 50) ? $max_results : 50; + } elseif ($kind == 'Search Albums Online') { + $search_albums = true; + $search_albums_limit = ($max_results <= 50) ? $max_results : 50; + } elseif ($kind == 'Search Tracks Online') { + $search_tracks = true; + $search_tracks_limit = ($max_results <= 50) ? $max_results : 50; + } + + $noresult = true; + + $search_categories = explode('▹', $search_order); + + foreach($search_categories as $search_category) { + + if($search_category == 'artist') { + + if ($search_artists == true) { + // Search Artists + + // call to web api, if it fails, + // it displays an error in main window + $query = 'artist:'.$the_query; + $results = searchWebApi($w, $country_code, $query, 'artist', $search_artists_limit, false); + + foreach ($results as $artist) { + if (checkIfResultAlreadyThere($w->results(), '👤 '.escapeQuery($artist->name)) == false) { + $noresult = false; + $w->result(null, '', '👤 '.escapeQuery($artist->name), 'Browse this artist', getArtistArtwork($w, $artist->uri, $artist->name, false, false, false, $use_artworks), 'no', null, 'Online▹'.$artist->uri.'@'.escapeQuery($artist->name).'▹'); + } + } + } + } + + if($search_category == 'album') { + + if ($search_albums == true) { + // Search Albums + + // call to web api, if it fails, + // it displays an error in main window + $query = 'album:'.$the_query; + $results = searchWebApi($w, $country_code, $query, 'album', $search_albums_limit, false); + + try { + $api = getSpotifyWebAPI($w); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + + foreach ($results as $album) { + if (checkIfResultAlreadyThere($w->results(), escapeQuery($album->name)) == false) { + $noresult = false; + + try { + $full_album = $api->getAlbum($album->id); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + $w->result(null, '', escapeQuery($album->name).' ('.$full_album->tracks->total.' tracks)', $album->album_type.' by '.escapeQuery($full_album->artists[0]->name), getTrackOrAlbumArtwork($w, $album->uri, false, false, false, $use_artworks), 'no', null, 'Online▹'.$full_album->artists[0]->uri.'@'.escapeQuery($full_album->artists[0]->name).'@'.$album->uri.'@'.escapeQuery($album->name).'▹'); + } + } + } + } + + if($search_category == 'playlist') { + + if ($search_playlists == true) { + // Search Playlists + + // call to web api, if it fails, + // it displays an error in main window + $query = $the_query; + $results = searchWebApi($w, $country_code, $query, 'playlist', $search_playlists_limit, false); + + foreach ($results as $playlist) { + $noresult = false; + $w->result(null, '', '🎵'.escapeQuery($playlist->name), 'by '.$playlist->owner->id.' ● '.$playlist->tracks->total.' tracks', getPlaylistArtwork($w, $playlist->uri, false, false, $use_artworks), 'no', null, 'Online Playlist▹'.$playlist->uri.'∙'.base64_encode($playlist->name).'▹'); + } + } + } + + if($search_category == 'artist') { + if ($search_tracks == true) { + // Search Tracks + + // call to web api, if it fails, + // it displays an error in main window + $query = 'track:'.$the_query; + $results = searchWebApi($w, $country_code, $query, 'track', $search_tracks_limit, false); + $first = true; + foreach ($results as $track) { + $noresult = false; + $track_artwork = getTrackOrAlbumArtwork($w, $track->uri, false, false, false, $use_artworks); + + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $w->result(null, serialize(array( + $track->uri /*track_uri*/, + $album->uri /* album_uri */, + $artist->uri /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'play_track_in_album_context' /* other_action */, + escapeQuery($artist->name) /* artist_name */, + escapeQuery($track->name) /* track_name */, + escapeQuery($album->name) /* album_name */, + $track_artwork /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), escapeQuery($artist->name).' ● '.escapeQuery($track->name), array( + beautifyTime($track->duration_ms / 1000).' ● '.escapeQuery($album->name), + 'alt' => 'Play album '.escapeQuery($album->name).' in Spotify', + 'cmd' => 'Play artist '.escapeQuery($artist->name).' in Spotify', + 'fn' => 'Add track '.escapeQuery($track->name).' to ...', + 'shift' => 'Add album '.escapeQuery($album->name).' to ...', + 'ctrl' => 'Search artist '.escapeQuery($artist->name).' online', + ), $track_artwork, 'yes', null, ''); + } + } + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for this search',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + } +} + +/** + * firstDelimiterNewReleases function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterNewReleases($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $search = $words[1]; + + $country_code = $settings->country_code; + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName($country_code)), strtolower($search)) !== false) { + $w->result(null, '', getCountryName($country_code),array( + 'Browse the new album releases in '.getCountryName($country_code), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/new_releases.png', 'no', null, 'New Releases▹'.$country_code.'▹'); + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('US')), strtolower($search)) !== false) { + if ($country_code != 'US') { + $w->result(null, '', getCountryName('US'),array( + 'Browse the new album releases in '.getCountryName('US'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/new_releases.png', 'no', null, 'New Releases▹US▹'); + } + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('GB')), strtolower($search)) !== false) { + if ($country_code != 'GB') { + $w->result(null, '', getCountryName('GB'),array( + 'Browse the new album releases in '.getCountryName('GB'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/new_releases.png', 'no', null, 'New Releases▹GB▹'); + } + } + + if (mb_strlen($search) < 2 || strpos(strtolower('Choose Another country'), strtolower($search)) !== false) { + $w->result(null, '', 'Choose Another country',array( + 'Browse the new album releases in another country of your choice', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/new_releases.png', 'no', null, 'New Releases▹Choose a Country▹'); + } +} + +/** + * firstDelimiterCurrentTrack function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterCurrentTrack($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $input = $words[1]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $is_public_playlists = $settings->is_public_playlists; + $output_application = $settings->output_application; + $is_display_rating = $settings->is_display_rating; + $use_artworks = $settings->use_artworks; + $always_display_lyrics_in_browser = $settings->always_display_lyrics_in_browser; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + $w->result(null, 'help', 'AppleScript execution failed!',array( + 'Message: '.htmlspecialchars($retArr[0]), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/blog/issue-with-latest-spotify-update/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Maybe you have an issue with a Broken Spotify version?', 'Go to the article to get more information', './images/website.png', 'yes', null, ''); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + if ($results[1] == '' || $results[2] == '') { + + $tmp = explode(':', $results[4]); + + if (isset($tmp[1]) && $tmp[1] == 'ad') { + $w->result(null, 'help', 'Current track is an Ad',array( + 'Wait for the end of the ad and try again', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + + $w->result(null, 'help', 'Current track is not valid: Artist or Album name is missing',array( + 'Fill missing information in Spotify and retry again', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + + $href = explode(':', $results[4]); + $added = ''; + $shared_url = ''; + if ($href[1] == 'local') { + $added = '📌 '; + } else { + $shared_url .= ' https://open.spotify.com/track/'; + $shared_url .= $href[2]; + } + $subtitle = '⌥ (play album) ⌘ (play artist) ctrl (lookup online)'; + $subtitle = "$subtitle fn (add track to ...) ⇧ (add album to ...)"; + if (mb_strlen($input) < 2) { + $popularity = ''; + if($is_display_rating) { + $popularity = floatToStars($results[6]/100); + } + if ($results[3] == 'playing') { + $w->result(null, serialize(array( + $results[4] /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'pause' /* other_action */, + escapeQuery($results[1]) /* artist_name */, + escapeQuery($results[0]) /* track_name */, + escapeQuery($results[2]) /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), $added.escapeQuery($results[0]).' ● '.escapeQuery($results[1]).' ● '.escapeQuery($results[2]).' ● '.$popularity.' ('.beautifyTime($results[5] / 1000).')', array( + $subtitle, + 'alt' => 'Play album '.escapeQuery($results[2]).' in Spotify', + 'cmd' => 'Play artist '.escapeQuery($results[1]).' in Spotify', + 'fn' => 'Add track '.escapeQuery($results[0]).' to ...', + 'shift' => 'Add album '.escapeQuery($results[2]).' to ...', + 'ctrl' => 'Search artist '.escapeQuery($results[1]).' online', + ), ($results[3] == 'playing') ? './images/pause.png' : './images/play.png', 'yes', array( + 'copy' => '#NowPlaying ' . escapeQuery($results[0]).' by '.escapeQuery($results[1]) . $shared_url, + 'largetype' => escapeQuery($results[0]).' by '.escapeQuery($results[1]), + ), ''); + } else { + $w->result(null, serialize(array( + $results[4] /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'play' /* other_action */, + escapeQuery($results[1]) /* artist_name */, + escapeQuery($results[0]) /* track_name */, + escapeQuery($results[2]) /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), $added.escapeQuery($results[0]).' ● '.escapeQuery($results[1]).' ● '.escapeQuery($results[2]).' ● '.$popularity.' ('.beautifyTime($results[5] / 1000).')', array( + $subtitle, + 'alt' => 'Play album '.escapeQuery($results[2]).' in Spotify', + 'cmd' => 'Play artist '.escapeQuery($results[1]).' in Spotify', + 'fn' => 'Add track '.escapeQuery($results[0]).' to ...', + 'shift' => 'Add album '.escapeQuery($results[2]).' to ...', + 'ctrl' => 'Search artist '.escapeQuery($results[1]).' online', + ), ($results[3] == 'playing') ? './images/pause.png' : './images/play.png', 'yes', array( + 'copy' => '#NowPlaying ' . escapeQuery($results[0]).' by '.escapeQuery($results[1]) . $shared_url, + 'largetype' => escapeQuery($results[0]).' by '.escapeQuery($results[1]), + ), ''); + } + } + + if ($output_application == 'CONNECT') { + if (mb_strlen($input) < 2) { + try { + $api = getSpotifyWebAPI($w); + + $playback_info = $api->getMyCurrentPlaybackInfo(array( + 'market' => $country_code, + )); + + $track_name = $playback_info->item->name; + $artist_name = $playback_info->item->artists[0]->name; + $album_name = $playback_info->item->album->name; + $is_playing = $playback_info->is_playing; + if($is_playing) { + $state = 'playing'; + } else { + $state = 'paused'; + } + $track_uri = $playback_info->item->uri; + $length = ($playback_info->item->duration_ms/1000); + $popularity = $playback_info->item->popularity; + $progress_ms = $playback_info->progress_ms; + + // device + $device_name = $playback_info->device->name; + $device_type = $playback_info->device->type; + + + $shuffle_state = "inactive"; + if($playback_info->shuffle_state) { + $shuffle_state = "active"; + } + + $context_type = ''; + if($playback_info->context != null) { + $context_type = $playback_info->context->type; + if($context_type == 'playlist') { + $playlist_uri = $playback_info->context->uri; + $context = 'playlist ' . getPlaylistName($w, $playlist_uri). ' '; + } else if($context_type == 'album') { + $album_uri = $playback_info->context->uri; + $context = 'album ' . getAlbumName($w, $album_uri) . ' '; + } else if($context_type == 'artist') { + $artist_uri = $playback_info->context->uri; + $context = 'artist ' . getArtistName($w, $artist_uri) . ' '; + } + } + $repeat_state = "Repeat is "; + if($playback_info->repeat_state == 'track') { + $repeat_state = "Repeat track is "; + } else if($playback_info->repeat_state == 'context') { + $repeat_state = "Repeat " . $context_type . " is "; + } + + if ($device_name != '') { + $w->result(null, 'help', 'Playing ' . $context . 'on ' . $device_type . ' ' . $device_name,array( + 'Progress: ' . floatToCircles($progress_ms / $results[5]) . ' Shuffle is <' . $shuffle_state . '> ' . $repeat_state, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/connect.png', 'no', null, ''); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if($e->getMessage() == 'Permissions missing') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_oauth_settings' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'The workflow needs more privilages to do this, click to restart authentication', array( + 'Next time you invoke the workflow, you will have to re-authenticate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'yes', null, ''); + } else { + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + echo $w->tojson(); + exit; + } + } + } + + + $getTracks = 'select artist_name,artist_uri from tracks where artist_name=:artist_name limit '. 1; + + try { + $stmt = $db->prepare($getTracks); + $stmt->bindValue(':artist_name', escapeQuery($results[1])); + $tracks = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + + if (mb_strlen($input) < 2 || strpos(strtolower('browse artist'), strtolower($input)) !== false) { + // check if artist is in library + $noresult = true; + while ($track = $stmt->fetch()) { + if ($track[1] != '') { + $artist_uri = $track[1]; + $noresult = false; + } + } + if ($noresult == false) { + + $href = explode(':', $artist_uri); + $shared_url .= ' https://open.spotify.com/artist/'; + $shared_url .= $href[2]; + + $w->result(null, '', '👤 '.escapeQuery($results[1]), 'Browse this artist', getArtistArtwork($w, $artist_uri, $results[1], false, false, false, $use_artworks), 'no', array( + false, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + 'copy' => '#NowPlaying artist ' . escapeQuery($results[1]).' ' . $shared_url, + 'largetype' => escapeQuery($results[1]), + ), 'Artist▹'.$artist_uri.'∙'.escapeQuery($results[1]).'▹'); + + } else { + // artist is not in library + $artist_uri = getArtistUriFromTrack($w, $results[4]); + + $href = explode(':', $artist_uri); + $shared_url .= ' https://open.spotify.com/artist/'; + $shared_url .= $href[2]; + + $w->result(null, '', '👤 '.escapeQuery($results[1]), 'Browse this artist', getArtistArtwork($w, $artist_uri /* empty artist_uri */, $results[1], false, false, false, $use_artworks), 'no', array( + false, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + 'copy' => '#NowPlaying artist ' . escapeQuery($results[1]).' ' . $shared_url, + 'largetype' => escapeQuery($results[1]), + ), 'Artist▹'.$results[4].'∙'.escapeQuery($results[1]).'▹'); + } + } + + if (mb_strlen($input) < 2 || strpos(strtolower('play album'), strtolower($input)) !== false) { + + $album_uri = getAlbumUriFromTrack($w, $results[4]); + + $shared_url = ''; + if ($album_uri != false) { + $href = explode(':', $album_uri); + $shared_url .= ' https://open.spotify.com/album/'; + $shared_url .= $href[2]; + } + + // use track uri here + $album_artwork_path = getTrackOrAlbumArtwork($w, $results[4], false, false, false, $use_artworks); + $w->result(null, serialize(array( + $results[4] /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'playalbum' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + escapeQuery($results[2]) /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + $album_artwork_path /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), '💿 '.escapeQuery($results[2]), 'Play album', $album_artwork_path, 'yes', array( + 'copy' => '#NowPlaying album ' . escapeQuery($results[2]).' ' . $shared_url, + 'largetype' => escapeQuery($results[2]), + ), ''); + } + + // use track uri here + if (mb_strlen($input) < 2 || strpos(strtolower('query lookup online'), strtolower($input)) !== false) { + $w->result(null, '', '💿 '.escapeQuery($results[2]),array( + '☁︎ Query all tracks from this album online..', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/online_album.png', 'no', null, 'Online▹'.$results[4].'@'.escapeQuery($results[1]).'@'.$results[4].'@'.escapeQuery($results[2]).'▹'); + } + + if (mb_strlen($input) < 2 || strpos(strtolower('get lyrics'), strtolower($input)) !== false) { + if($always_display_lyrics_in_browser == false) { + $w->result(null, '', 'Get Lyrics for track '.escapeQuery($results[0]),array( + 'This will fetch lyrics online and display them in Alfred', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/lyrics.png', 'no', null, 'Lyrics▹'.$results[4].'∙'.escapeQuery($results[1]).'∙'.escapeQuery($results[0])); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'lyrics' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Get Lyrics for track '.escapeQuery($results[0]), array( + 'This will display them in default browser', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/lyrics.png', 'yes', null, ''); + } + } + + + if ($update_in_progress == false) { + if (mb_strlen($input) < 2 || strpos(strtolower('add'), strtolower($input)) !== false) { + $w->result(null, '', 'Add track '.escapeQuery($results[0]).' to...',array( + 'This will add current track to Your Music or a playlist you will choose in next step', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/add.png', 'no', null, 'Add▹'.$results[4].'∙'.escapeQuery($results[0]).'▹'); + } + + if (mb_strlen($input) < 2 || strpos(strtolower('remove'), strtolower($input)) !== false) { + $w->result(null, '', 'Remove track '.escapeQuery($results[0]).' from...',array( + 'This will remove current track from Your Music or a playlist you will choose in next step', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/remove.png', 'no', null, 'Remove▹'.$results[4].'∙'.escapeQuery($results[0]).'▹'); + } + + $privacy_status = 'private'; + if ($is_public_playlists) { + $privacy_status = 'public'; + } + if (mb_strlen($input) < 2 || strpos(strtolower('song radio'), strtolower($input)) !== false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'current_track_radio' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Create a Song Radio Playlist based on '.escapeQuery($results[0]), array( + 'This will create a '.$privacy_status.' song radio playlist with '.$radio_number_tracks.' tracks for the current track', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/radio_song.png', 'yes', null, ''); + } + } + + if (mb_strlen($input) < 2 || strpos(strtolower('share'), strtolower($input)) !== false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'share' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Share current track using Mac OS X Sharing ', array( + 'This will open the Mac OS X Sharing for the current track', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/share.png', 'yes', null, ''); + } + + if (mb_strlen($input) < 2 || strpos(strtolower('web search'), strtolower($input)) !== false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'web_search' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Do a web search for current track or artist on Youtube, Facebook, etc.. ', array( + 'You will be prompted to choose the web service you want to use', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/youtube.png', 'yes', null, ''); + } + + if (mb_strlen($input) < 2) { + if ($all_playlists == true) { + $getTracks = 'select playlist_uri from tracks where uri=:uri limit '.$max_results; + try { + $stmtgetTracks = $db->prepare($getTracks); + $stmtgetTracks->bindValue(':uri', $results[4]); + $stmtgetTracks->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + + while ($track = $stmtgetTracks->fetch()) { + if ($track[0] == '') { + // The track is in Your Music + $w->result(null, '', 'In "Your Music"',array( + 'The track is in Your Music', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/yourmusic.png', 'no', null, 'Your Music▹Tracks▹'.escapeQuery($results[0])); + } else { + $getPlaylists = 'select uri,name,nb_tracks,author,username,playlist_artwork_path,ownedbyuser,nb_playable_tracks,duration_playlist,collaborative,public from playlists where uri=:uri'; + + try { + $stmtGetPlaylists = $db->prepare($getPlaylists); + $stmtGetPlaylists->bindValue(':uri', $track[0]); + $playlists = $stmtGetPlaylists->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + + while ($playlist = $stmtGetPlaylists->fetch()) { + $added = ' '; + if (startswith($playlist[1], 'Artist radio for')) { + $added = '📻 '; + } + if (checkIfResultAlreadyThere($w->results(), '🎵'.$added.'In playlist '.$playlist[1]) == false) { + if ($playlist[9]) { + $public_status = 'collaborative'; + } else { + if ($playlist[10]) { + $public_status = 'public'; + } else { + $public_status = 'private'; + } + } + $w->result(null, '', '🎵'.$added.'In playlist '.$playlist[1],array( + $public_status.' playlist by '.$playlist[3].' ● '.$playlist[7].' tracks ● '.$playlist[8], + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $playlist[5], 'no', null, 'Playlist▹'.$playlist[0].'▹'); + } + } + } + } + } + } + } else { + $w->result(null, 'help', 'There is no track currently playing',array( + 'Launch a track and come back here', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } +} + +/** + * firstDelimiterSpotifyConnect function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ + function firstDelimiterSpotifyConnect($w, $query, $settings, $db, $update_in_progress) + { + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $is_public_playlists = $settings->is_public_playlists; + $output_application = $settings->output_application; + $is_display_rating = $settings->is_display_rating; + $use_artworks = $settings->use_artworks; + $always_display_lyrics_in_browser = $settings->always_display_lyrics_in_browser; + + + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $noresult = true; + + $savedDevices = array(); + $devices = $api->getMyDevices(); + $retry = false; + if(isset($devices->devices)) { + foreach ($devices->devices as $device) { + if ($device->is_active) { + array_unshift($savedDevices , $device); + } else { + $savedDevices[] = $device; + } + $noresult = false; + } + } + + if(!$noresult) { + $w->result(null, '', 'Select one of your Spotify Connect devices',array( + 'Select one of your Spotify Connect devices below as your listening device', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/connect.png', 'no', null, ''); + + foreach ($savedDevices as $device) { + $added = ''; + if($device->is_active) { + $added = '🔈'; + } + if($device->type == 'Computer') { + $icon = './images/computer.png'; + } else if($device->type == 'Smartphone') { + $icon = './images/smartphone.png'; + } else { + $icon = './images/speaker.png'; + } + $volume = ''; + if(isset($device->volume_percent)) { + $volume = '- volume: '.floatToSquares($device->volume_percent/100, 5); + } + if($device->is_restricted) { + $w->result(null, 'help', $added . $device->type . ' ' .$device->name.' cannot be controlled',array( + '⚠ This device cannot be controlled by Spotify WEB API', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $icon, 'no', null, ''); + } else { + if (!$device->is_active) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'CHANGE_DEVICE▹'.$device->id /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), $added.'Switch playback to '. $device->type . ' '.$device->name.' '.$volume, array( + 'Type enter to validate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $icon, 'yes', null, ''); + } else { + $w->result(null, 'help', $added.' '. $device->type . ' '.$device->name.' is currently active '.$volume,array( + 'This device is the currently active device', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $icon, 'no', null, ''); + } + } + } + + } else { + $w->result(null, 'help', 'There was no Spotify Connect device found!',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + if(isSpotifyAppInstalled()) { + $w->result('SpotifyMiniPlayer_'.'open_spotify_app', serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'open_spotify_app' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Open Spotify application', 'This will open Spotify', './images/spotify.png', 'yes', null, ''); + } + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if($e->getMessage() == 'Permissions missing') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_oauth_settings' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'The workflow needs more privilages to do this, click to restart authentication', array( + 'Next time you invoke the workflow, you will have to re-authenticate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'yes', null, ''); + echo $w->tojson(); + exit; + } else { + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + $retry = false; + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + + echo $w->tojson(); + exit; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + } + } + } + + } +/** + * firstDelimiterYourMusic function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterYourMusic($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + + $thequery = $words[1]; + + if (mb_strlen($thequery) < 2) { + $getCounters = 'select * from counters'; + try { + $stmt = $db->prepare($getCounters); + + $counters = $stmt->execute(); + $counter = $stmt->fetch(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + + $all_tracks = $counter[0]; + $yourmusic_tracks = $counter[1]; + $all_artists = $counter[2]; + $yourmusic_artists = $counter[3]; + $all_albums = $counter[4]; + $yourmusic_albums = $counter[5]; + $nb_playlists = $counter[6]; + + $w->result(null, '', 'Tracks',array( + 'Browse your '.$yourmusic_tracks.' tracks in Your Music', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/tracks.png', 'no', null, 'Your Music▹Tracks▹'); + $w->result(null, '', 'Albums',array( + 'Browse your '.$yourmusic_albums.' albums in Your Music', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/albums.png', 'no', null, 'Your Music▹Albums▹'); + $w->result(null, '', 'Artists',array( + 'Browse your '.$yourmusic_artists.' artists in Your Music', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/artists.png', 'no', null, 'Your Music▹Artists▹'); + } else { + + // Search artists + + $getTracks = 'select artist_name,artist_uri,artist_artwork_path from tracks where yourmusic=1 and artist_name like :artist_name limit '.$max_results; + + try { + $stmt = $db->prepare($getTracks); + $stmt->bindValue(':artist_name', '%'.$thequery.'%'); + + $tracks = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + $noresult = true; + while ($track = $stmt->fetch()) { + if (checkIfResultAlreadyThere($w->results(), '👤 '.$track[0]) == false) { + $noresult = false; + $w->result(null, '', '👤 '.$track[0],array( + 'Browse this artist', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $track[2], 'no', null, 'Artist▹'.$track[1].'∙'.$track[0].'▹'); + } + } + + // Search everything + + $getTracks = 'select yourmusic, popularity, uri, album_uri, artist_uri, track_name, album_name, artist_name, album_type, track_artwork_path, artist_artwork_path, album_artwork_path, playlist_name, playlist_uri, playable, added_at, duration, nb_times_played, local_track from tracks where yourmusic=1 and (artist_name like :query or album_name like :query or track_name like :query)'.' limit '.$max_results; + + try { + $stmt = $db->prepare($getTracks); + $stmt->bindValue(':query', '%'.$thequery.'%'); + + $tracks = $stmt->execute(); + } catch (PDOException $e) { + handleDbIssuePdoXml($db); + + return; + } + + while ($track = $stmt->fetch()) { + $noresult = false; + $subtitle = $track[6]; + + if (checkIfResultAlreadyThere($w->results(), $track[7].' ● '.$track[5]) == false) { + $w->result(null, serialize(array( + $track[2] /*track_uri*/, + $track[3] /* album_uri */, + $track[4] /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + '' /* other_action */, + $track[7] /* artist_name */, + $track[5] /* track_name */, + $track[6] /* album_name */, + $track[9] /* track_artwork_path */, + $track[10] /* artist_artwork_path */, + $track[11] /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), $track[7].' ● '.$track[5], $arrayresult = array( + $track[16].' ● '.$subtitle.getPlaylistsForTrack($db, $track[2]), + 'alt' => 'Play album '.$track[6].' in Spotify', + 'cmd' => 'Play artist '.$track[7].' in Spotify', + 'fn' => 'Add track '.$track[5].' to ...', + 'shift' => 'Add album '.$track[6].' to ...', + 'ctrl' => 'Search artist '.$track[7].' online', + ), $track[9], 'yes', array( + 'copy' => $track[7].' ● '.$track[5], + 'largetype' => $track[7].' ● '.$track[5], + ), ''); + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for your search',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + } +} + +/** + * firstDelimiterLyrics function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterLyrics($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + + if (substr_count($query, '∙') == 2) { + + // Search Lyrics + + $tmp = $words[1]; + $words = explode('∙', $tmp); + $track_uri = $words[0]; + $artist_name = $words[1]; + $track_name = $words[2]; + + list($lyrics_url, $lyrics) = getLyrics($w, $artist_name, $track_name); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'lyrics', 1); + + if ($lyrics_url != false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.$lyrics_url /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'See lyrics for '.$track_name.' by '.$artist_name.' online', 'This will open your default browser', './images/lyrics.png', 'yes', null, ''); + + $track_artwork = getTrackOrAlbumArtwork($w, $track_uri, false, false, false, $use_artworks); + + $wrapped = wordwrap($lyrics, 70, "\n", false); + $lyrics_sentances = explode("\n", $wrapped); + + for ($i = 0; $i < count($lyrics_sentances); ++$i) { + $w->result(null, '', $lyrics_sentances[$i],array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $track_artwork, 'no', null, ''); + } + } else { + $w->result(null, 'help', 'No lyrics found!',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + echo $w->tojson(); + exit; + } + } +} + +/** + * firstDelimiterSettings function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterSettings($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $is_public_playlists = $settings->is_public_playlists; + $quick_mode = $settings->quick_mode; + $output_application = $settings->output_application; + $mopidy_server = $settings->mopidy_server; + $mopidy_port = $settings->mopidy_port; + $is_display_rating = $settings->is_display_rating; + $volume_percent = $settings->volume_percent; + $is_autoplay_playlist = $settings->is_autoplay_playlist; + $use_growl = $settings->use_growl; + $use_artworks = $settings->use_artworks; + $use_facebook = $settings->use_facebook; + $always_display_lyrics_in_browser = $settings->always_display_lyrics_in_browser; + + if ($update_in_progress == false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'refresh_library' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Refresh your library', array( + 'Do this when your library has changed (outside the scope of this workflow)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/update.png', 'yes', null, ''); + } + + $w->result(null, '', 'Switch Spotify user (currently '.$userid.')', array( + 'Switch to another Spotify user', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), getUserArtwork($w, $userid), 'no', null, 'Settings▹Users▹'); + + if ($is_alfred_playlist_active == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_alfred_playlist' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Control Your Music', array( + 'You will control Your Music (if disabled, you control Alfred Playlist)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/yourmusic.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_alfred_playlist' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Control Alfred Playlist', array( + 'You will control the Alfred Playlist (if disabled, you control Your Music)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/alfred_playlist.png', 'yes', null, ''); + } + + if ($all_playlists == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_all_playlist' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Set Search Scope to Your Music only', array( + 'Select to search only in "Your Music"', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/search_scope_yourmusic_only.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_all_playlist' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Unset Search Scope to Your Music only', array( + 'Select to search in your complete library ("Your Music" and all Playlists)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/search.png', 'yes', null, ''); + } + $w->result(null, '', 'Configure Max Number of Results (currently '.$max_results.')',array( + 'Number of results displayed (it does not apply to the list of your playlists)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/results_numbers.png', 'no', null, 'Settings▹MaxResults▹'); + $w->result(null, '', 'Configure Number of Radio tracks (currently '.$radio_number_tracks.')',array( + 'Number of tracks when creating a Radio Playlist.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/radio_numbers.png', 'no', null, 'Settings▹RadioTracks▹'); + $w->result(null, '', 'Configure Volume Percent (currently '.$volume_percent.'%)',array( + 'The percentage of volume which is increased or decreased.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/volume_up.png', 'no', null, 'Settings▹VolumePercentage▹'); + + $w->result(null, '', 'Select the output: Spotify Connect, Mopidy or Spotify Desktop',array( + 'Spotify Connect and Mopidy are for premium users only', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/speaker.png', 'no', null, 'Settings▹Output▹'); + + if ($output_application == 'MOPIDY') { + $w->result(null, '', 'Configure Mopidy server (currently '.$mopidy_server.')',array( + 'Server name/ip where Mopidy server is running', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/mopidy_server.png', 'no', null, 'Settings▹MopidyServer▹'); + $w->result(null, '', 'Configure Mopidy port (currently '.$mopidy_port.')',array( + 'TCP port where Mopidy server is running', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/mopidy_port.png', 'no', null, 'Settings▹MopidyPort▹'); + } + + if ($now_playing_notifications == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_now_playing_notifications' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Now Playing notifications', array( + 'Do not display notifications for current playing track', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_now_playing.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_now_playing_notifications' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Now Playing notifications', array( + 'Display notifications for current playing track', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_now_playing.png', 'yes', null, ''); + } + + if ($quick_mode == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_quick_mode' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Quick Mode', array( + 'Do not launch directly tracks/album/artists/playlists in main search', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_quick_mode.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_quick_mode' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Quick Mode', array( + 'Launch directly tracks/album/artists/playlists in main search', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_quick_mode.png', 'yes', null, ''); + } + + if ($use_artworks == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_artworks' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Artworks', array( + 'All existing artworks will be deleted and workflow will only show default artworks (library will be re-created)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_artworks.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_artworks' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Artworks', array( + 'Use Artworks for playlists, tracks, etc..(library will be re-created)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_artworks.png', 'yes', null, ''); + } + + if ($is_display_rating == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_display_rating' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Track Rating', array( + 'Do not display track rating with stars in Current Track menu and notifications', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_display_rating.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_display_rating' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Track Rating', array( + 'Display track rating with stars in Current Track menu and notifications', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_display_rating.png', 'yes', null, ''); + } + + if ($is_autoplay_playlist == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_autoplay' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Playlist Autoplay', array( + 'Do not autoplay playlists (radios and complete collection) when they are created', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_autoplay.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_autoplay' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Playlist Autoplay', array( + 'Autoplay playlists (radios and complete collection) when they are created', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_autoplay.png', 'yes', null, ''); + } + + if ($use_growl == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_use_growl' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Disable Growl', array( + 'Use Notification Center instead of Growl', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_use_growl.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_use_growl' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Growl', array( + 'Use Growl instead of Notification Center', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_use_growl.png', 'yes', null, ''); + } + + if ($always_display_lyrics_in_browser == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_always_display_lyrics_in_browser' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Display lyrics in Alfred', array( + 'Lyrics will be displayed in Alfred', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/lyrics.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_always_display_lyrics_in_browser' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Display lyrics in Browser', array( + 'Lyrics will be displayed in default browser', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/lyrics.png', 'yes', null, ''); + } + + if ($use_facebook == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'use_twitter' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Use Twitter for sharing', array( + 'Use Twitter instead of Facebook', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/twitter.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'use_facebook' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Enable Facebook for sharing', array( + 'Use Facebook instead of Twitter', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/facebook.png', 'yes', null, ''); + } + + if ($update_in_progress == false) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'update_library' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Re-Create your library from scratch', array( + 'Do this when refresh library is not working as you would expect', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/recreate.png', 'yes', null, ''); + } + + if ($is_public_playlists == true) { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'disable_public_playlists' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Automatically make new playlists private', array( + 'If disabled, the workflow will mark new playlists (created or followed) as private', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/disable_public_playlists.png', 'yes', null, ''); + } else { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'enable_public_playlists' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Automatically make new playlists public', array( + 'If enabled, the workflow will mark new playlists (created or followed) as public', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/enable_public_playlists.png', 'yes', null, ''); + } + + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'change_theme_color' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Change theme color', array( + 'All existing icons will be replaced by chosen color icons', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/change_theme_color.png', 'yes', null, ''); + + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'change_search_order' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Change search order results', array( + 'Choose order of search results between playlist, artist, track and album', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/search.png', 'yes', null, ''); + + $w->result(null, '', 'Check for workflow update', array( + 'Last checked: '.beautifyTime(time() - $last_check_update_time, true).' ago (note this is automatically done otherwise once per week)', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/check_update.png', 'no', null, 'Check for update...'.'▹'); + + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Go to the website alfred-spotify-mini-player.com', 'Find out all information on the workflow on the website', './images/website.png', 'yes', null, ''); +} + +/** + * firstDelimiterCheckForUpdate function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterCheckForUpdate($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + + $check_results = checkForUpdate($w, 0); + if ($check_results != null && is_array($check_results)) { + $w->result(null, '', 'New version '.$check_results[0].' is available !',array( + $check_results[2], + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.$check_results[1] /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Click to open and install the new version', 'This will open the new version of the Spotify Mini Player workflow', './images/alfred-workflow-icon.png', 'yes', null, ''); + } elseif ($check_results == null) { + $w->result(null, '', 'No update available',array( + 'You are good to go!', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } else { + $w->result(null, '', 'Error happened : '.$check_results,array( + 'The check for workflow update could not be done', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + if ($check_results == 'This release has not been downloaded from Packal') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://www.packal.org/workflow/spotify-mini-player' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Download workflow from Packal', 'This will open the Spotify Mini Player Packal page with your default browser', './images/packal.png', 'yes', null, ''); + } + echo $w->tojson(); + exit; + } + echo $w->tojson(); + exit; +} + +/** + * firstDelimiterPlayQueue function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterPlayQueue($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $search = $words[1]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $output_application = $settings->output_application; + $use_artworks = $settings->use_artworks; + + if ($output_application == 'MOPIDY') { + $playqueue = $w->read('playqueue.json'); + if ($playqueue == false) { + $w->result(null, 'help',array( + 'There is no track in the play queue', 'Make sure to always use the workflow to launch tracks, playlists etc..Internet connectivity is also required', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/articles/play-queue/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Learn more about Play Queue', 'Find out all information about Play Queue on alfred-spotify-mini-player.com', './images/website.png', 'yes', null, ''); + echo $w->tojson(); + exit; + } + $tl_tracks = invokeMopidyMethod($w, 'core.tracklist.get_tl_tracks', array()); + $current_tl_track = invokeMopidyMethod($w, 'core.playback.get_current_tl_track', array()); + + $isShuffleEnabled = invokeMopidyMethod($w, 'core.tracklist.get_random', array()); + if ($isShuffleEnabled) { + $w->result(null, 'help', 'Shuffle is enabled',array( + 'The order of tracks presented below is not relevant', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + $noresult = true; + $firstTime = true; + $nb_tracks = 0; + $track_name = ''; + $album_name = ''; + $playlist_name = ''; + $current_track_found = false; + $current_track_index = 0; + foreach ($tl_tracks as $tl_track) { + ++$current_track_index; + if ($current_track_found == false && + $tl_track->tlid == $current_tl_track->tlid) { + $current_track_found = true; + } + if ($current_track_found == false && + $tl_track->tlid != $current_tl_track->tlid) { + continue; + } + if ($firstTime == true) { + $added = '🔈 '; + if ($playqueue->type == 'playlist') { + $playlist_name = $playqueue->name; + } elseif ($playqueue->type == 'album') { + $album_name = $playqueue->name; + } elseif ($playqueue->type == 'track') { + $track_name = $playqueue->name; + } + if (mb_strlen($search) < 2) { + $w->result(null, 'help', 'Playing from: '.$playqueue->type.' '.$playqueue->name,array( + 'Track '.$current_track_index.' on '.count($tl_tracks).' tracks queued', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/play_queue.png', 'no', null, ''); + } + } + $firstTime = false; + $max_tracks_displayed = 150; + if ($nb_tracks >= $max_tracks_displayed) { + if (mb_strlen($search) < 2) { + $w->result(null, 'help', '[...] '.(count($tl_tracks) - $max_tracks_displayed).' additional tracks are in the queue',array( + 'A maximum of '.$max_tracks_displayed.' tracks is displayed.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } + break; + } + $track_name = ''; + if (isset($tl_track->track->name)) { + $track_name = $tl_track->track->name; + } + $artist_name = ''; + if (isset($tl_track->track->artists[0]->name)) { + $artist_name = $tl_track->track->artists[0]->name; + } + $album_name = ''; + if (isset($tl_track->track->album->name)) { + $album_name = $tl_track->track->album->name; + } + $duration = 'na'; + if (isset($tl_track->track->length)) { + $duration = beautifyTime($tl_track->track->length / 1000); + } + $track_artwork = getTrackOrAlbumArtwork($w, $tl_track->track->uri, false, false, false, $use_artworks); + + if (strpos($track_name, '[unplayable]') !== false) { + $track_name = str_replace('[unplayable]', '', $track_name); + if (mb_strlen($search) < 2 || strpos(strtolower($artist_name), strtolower($search)) !== false + || strpos(strtolower($track_name), strtolower($search)) !== false + || strpos(strtolower($album_name), strtolower($search)) !== false) { + $w->result(null, '', '🚫 '.escapeQuery($artist_name).' ● '.escapeQuery($track_name),array( + $duration.' ● '.$album_name, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), $track_artwork, 'no', null, ''); + } + } else { + if (mb_strlen($search) < 2 || strpos(strtolower($artist_name), strtolower($search)) !== false + || strpos(strtolower($track_name), strtolower($search)) !== false + || strpos(strtolower($album_name), strtolower($search)) !== false) { + $w->result(null, serialize(array( + $tl_track->track->uri /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'play_track_from_play_queue' /* other_action */, + escapeQuery($artist_name) /* artist_name */, + escapeQuery($track_name) /* track_name */, + escapeQuery($album_name) /* album_name */, + $track_artwork /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + $playlist_name /* playlist_name */, + '', /* playlist_artwork_path */ + )), $added.escapeQuery($artist_name).' ● '.escapeQuery($track_name), array( + $duration.' ● '.escapeQuery($album_name), + 'alt' => 'Play album '.escapeQuery($album_name).' in Spotify', + 'cmd' => 'Play artist '.escapeQuery($artist_name).' in Spotify', + 'fn' => 'Add track '.escapeQuery($track->name).' to ...', + 'shift' => 'Add album '.escapeQuery($album_name).' to ...', + 'ctrl' => 'Search artist '.escapeQuery($artist_name).' online', + ), $track_artwork, 'yes', null, ''); + } + } + $noresult = false; + $added = ''; + $nb_tracks += 1; + } + + if ($noresult) { + $w->result(null, 'help', 'There is no track in the play queue from Mopidy',array( + 'Make sure to always use the workflow to launch tracks, playlists etc..Internet connectivity is also required', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/articles/play-queue/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Learn more about Play Queue', 'Find out all information about Play Queue on alfred-spotify-mini-player.com', './images/website.png', 'yes', null, ''); + echo $w->tojson(); + exit; + } + } else if($output_application == 'APPLESCRIPT' || $output_application == 'CONNECT') { + $playqueue = $w->read('playqueue.json'); + if ($playqueue == false) { + $w->result(null, 'help', 'There is no track in the play queue',array( + 'Make sure to always use the workflow to launch tracks, playlists etc..Internet connectivity is also required', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/articles/play-queue/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Learn more about Play Queue', 'Find out all information about Play Queue on alfred-spotify-mini-player.com', './images/website.png', 'yes', null, ''); + echo $w->tojson(); + exit; + } + if (isShuffleActive(false) == 'true') { + if (mb_strlen($search) < 2) { + $w->result(null, 'help', 'Shuffle is enabled',array( + 'The order of tracks presented below is not relevant', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + } + $noresult = true; + $nb_tracks = 0; + $track_name = ''; + $album_name = ''; + $playlist_name = ''; + for ($i = $playqueue->current_track_index; $i < count($playqueue->tracks); ++$i) { + $track = $playqueue->tracks[$i]; + if ($noresult == true) { + $added = '🔈 '; + if ($playqueue->type == 'playlist') { + $playlist_name = $playqueue->name; + } elseif ($playqueue->type == 'album') { + $album_name = $playqueue->name; + } elseif ($playqueue->type == 'track') { + $track_name = $playqueue->name; + } + if (mb_strlen($search) < 2) { + $w->result(null, 'help', 'Playing from: '.$playqueue->type.' '.$playqueue->name,array( + 'Track '.($playqueue->current_track_index + 1).' on '.count($playqueue->tracks).' tracks queued', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/play_queue.png', 'no', null, ''); + } + } + $max_tracks_displayed = 150; + if ($nb_tracks >= $max_tracks_displayed) { + if (mb_strlen($search) < 2) { + $w->result(null, 'help', '[...] '.(count($playqueue->tracks) - $max_tracks_displayed).' additional tracks are in the queue',array( + 'A maximum of '.$max_tracks_displayed.' tracks is displayed.', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/info.png', 'no', null, ''); + } + break; + } + $track_name = ''; + if (isset($track->name)) { + $track_name = $track->name; + } + $artist_name = ''; + if (isset($track->artists[0]->name)) { + $artist_name = $track->artists[0]->name; + } + $album_name = ''; + if (isset($track->album->name)) { + $album_name = $track->album->name; + } + $duration = 'na'; + if (isset($track->duration_ms)) { + $duration = beautifyTime($track->duration_ms / 1000); + } + if (isset($track->duration)) { + $duration = $track->duration; + } + $track_artwork = getTrackOrAlbumArtwork($w, $track->uri, false, false, false, $use_artworks); + if (mb_strlen($search) < 2 || strpos(strtolower($artist_name), strtolower($search)) !== false + || strpos(strtolower($track_name), strtolower($search)) !== false + || strpos(strtolower($album_name), strtolower($search)) !== false) { + $w->result(null, serialize(array( + $track->uri /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'play_track_from_play_queue' /* other_action */, + escapeQuery($artist_name) /* artist_name */, + escapeQuery($track_name) /* track_name */, + escapeQuery($album_name) /* album_name */, + $track_artwork /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + $playlist_name /* playlist_name */, + '', /* playlist_artwork_path */ + )), $added.escapeQuery($artist_name).' ● '.escapeQuery($track_name), array( + $duration.' ● '.escapeQuery($album_name), + 'alt' => 'Play album '.escapeQuery($album_name).' in Spotify', + 'cmd' => 'Play artist '.escapeQuery($artist_name).' in Spotify', + 'fn' => 'Add track '.escapeQuery($track->name).' to ...', + 'shift' => 'Add album '.escapeQuery($album_name).' to ...', + 'ctrl' => 'Search artist '.escapeQuery($artist_name).' online', + ), $track_artwork, 'yes', null, ''); + } + $noresult = false; + $added = ''; + $nb_tracks += 1; + } + + if ($noresult) { + $w->result(null, 'help', 'There is no track in the play queue',array( + 'Make sure to always use the workflow to launch tracks, playlists etc..Internet connectivity is also required', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'Open▹'.'http://alfred-spotify-mini-player.com/articles/play-queue/' /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Learn more about Play Queue', 'Find out all information about Play Queue on alfred-spotify-mini-player.com', './images/website.png', 'yes', null, ''); + echo $w->tojson(); + exit; + } + } +} + +/** + * firstDelimiterBrowse function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterBrowse($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $search = $words[1]; + + $country_code = $settings->country_code; + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName($country_code)), strtolower($search)) !== false) { + $w->result(null, '', getCountryName($country_code),array( + 'Browse the Spotify categories in '.getCountryName($country_code), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/browse.png', 'no', null, 'Browse▹'.$country_code.'▹'); + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('US')), strtolower($search)) !== false) { + if ($country_code != 'US') { + $w->result(null, '', getCountryName('US'),array( + 'Browse the Spotify categories in '.getCountryName('US'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/browse.png', 'no', null, 'Browse▹US▹'); + } + } + + if (mb_strlen($search) < 2 || strpos(strtolower(getCountryName('GB')), strtolower($search)) !== false) { + if ($country_code != 'GB') { + $w->result(null, '', getCountryName('GB'),array( + 'Browse the Spotify categories in '.getCountryName('GB'), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/browse.png', 'no', null, 'Browse▹GB▹'); + } + } + if (mb_strlen($search) < 2 || strpos(strtolower('Choose Another country'), strtolower($search)) !== false) { + $w->result(null, '', 'Choose Another country',array( + 'Browse the Spotify categories in another country of your choice', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/browse.png', 'no', null, 'Browse▹Choose a Country▹'); + } +} + +/** + * firstDelimiterYourTops function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterYourTops($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + + $w->result(null, '', 'Get your top artists (last 4 weeks)',array( + 'Get your top artists for last 4 weeks', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_artists.png', 'no', null, 'Your Tops▹Artists▹short_term'); + + $w->result(null, '', 'Get your top artists (last 6 months)',array( + 'Get your top artists for last 6 months', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_artists.png', 'no', null, 'Your Tops▹Artists▹medium_term'); + + $w->result(null, '', 'Get your top artists (all time)',array( + 'Get your top artists for all time', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_artists.png', 'no', null, 'Your Tops▹Artists▹long_term'); + + $w->result(null, '', 'Get your top tracks (last 4 weeks)',array( + 'Get your top tracks for last 4 weeks', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_tracks.png', 'no', null, 'Your Tops▹Tracks▹short_term'); + + $w->result(null, '', 'Get your top tracks (last 6 months)',array( + 'Get your top tracks for last 6 months', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_tracks.png', 'no', null, 'Your Tops▹Tracks▹medium_term'); + + $w->result(null, '', 'Get your top tracks (all time)',array( + 'Get your top tracks for all time', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/your_tops_tracks.png', 'no', null, 'Your Tops▹Tracks▹long_term'); +} + +/** + * firstDelimiterYourRecentTracks function. + * + * @param mixed $w + * @param mixed $query + * @param mixed $settings + * @param mixed $db + * @param mixed $update_in_progress + */ +function firstDelimiterYourRecentTracks($w, $query, $settings, $db, $update_in_progress) +{ + $words = explode('▹', $query); + $kind = $words[0]; + $search = $words[1]; + + $all_playlists = $settings->all_playlists; + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $radio_number_tracks = $settings->radio_number_tracks; + $now_playing_notifications = $settings->now_playing_notifications; + $max_results = $settings->max_results; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $last_check_update_time = $settings->last_check_update_time; + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + + try { + $api = getSpotifyWebAPI($w); + + $recentTracks = $api->getMyRecentTracks(array( + 'limit' => ($max_results <= 50) ? $max_results : 50, + )); + + $noresult = true; + $items = $recentTracks->items; + + foreach ($items as $item) { + + $track = $item->track; + $noresult = false; + $artists = $track->artists; + $artist = $artists[0]; + + if (mb_strlen($search) < 2 || strpos(strtolower($track->name), strtolower($search)) !== false || strpos(strtolower($artist->name), strtolower($search)) !== false) { + $track_artwork_path = getTrackOrAlbumArtwork($w, $track->uri, false, false, false, $use_artworks); + $w->result(null, serialize(array( + $track->uri /*track_uri*/, + '' /* album_uri */, + $artist->uri /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + '' /* other_action */, + escapeQuery($artist->name) /* artist_name */, + escapeQuery($track->name) /* track_name */, + ''/* album_name */, + $track_artwork_path /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), escapeQuery($artist->name).' ● '.escapeQuery($track->name), array( + beautifyTime($track->duration_ms / 1000).' ● '.time2str($item->played_at), + 'alt' => 'Not Available', + 'cmd' => 'Play artist '.escapeQuery($artist->name).' in Spotify', + 'fn' => 'Add track '.escapeQuery($track->name).' to ...', + 'shift' => 'Not Available', + 'ctrl' => 'Search artist '.escapeQuery($artist->name).' online', + ), $track_artwork_path, 'yes', null, ''); + ++$nb_results; + } + } + + if ($noresult) { + $w->result(null, 'help', 'There is no result for your recent tracks',array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if($e->getMessage() == 'Insufficient client scope') { + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_oauth_settings' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'The workflow needs more privilages to do this, click to restart authentication', array( + 'Next time you invoke the workflow, you will have to re-authenticate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'yes', null, ''); + } else { + $w->result(null, 'help', 'Exception occurred',array( + ''.$e->getMessage(), + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + } + echo $w->tojson(); + exit; + } +} diff --git a/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/functions copy.php b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/functions copy.php new file mode 100644 index 0000000..fd64bfd --- /dev/null +++ b/alfred/Alfred.alfredpreferences/workflows/user.workflow.26252FA4-D99E-49E9-9C82-4514AAFA9979/src/functions copy.php @@ -0,0 +1,9607 @@ + 3) { + return "com.runningwithcrayons.Alfred"; + } else { + return "com.runningwithcrayons.Alfred-3"; + } +} + +/** + * getCurrentArtistAndTrackName function. + * + * @param mixed $w + * @param mixed $output_application + */ +function getCurrentArtistAndTrackName($w, $output_application) +{ + if ($output_application == 'MOPIDY') { + $ret = getCurrentTrackInfoWithMopidy($w, false); + $results = explode('▹', $ret); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + } + } else { + $ret = getCurrentTrackInfoWithSpotifyConnect($w, false); + $results = explode('▹', $ret); + } + + if (!isset($results[0])) { + displayNotificationWithArtwork($w, 'Cannot get current track', './images/warning.png', 'Error!'); + return; + } + $search_text = escapeQuery($results[0]); + $search_text .= '▹'; + $search_text .= escapeQuery($results[1]); + + return $search_text; +} + +/** + * copyCurrentTrackUrlToClipboard function. + * + * @param mixed $w + */ +function copyCurrentTrackUrlToClipboard($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + + $tmp = explode(':', $results[4]); + if ($tmp[1] != 'local') { + $text = 'https://open.spotify.com/track/'; + $text .= $tmp[2]; + + copy2clipboard($text); + } + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * copy2clipboard function. + * + * @param mixed $string + * + * https://stackoverflow.com/questions/29181038/how-to-copy-string-to-system-clipboard-with-php-which-runs-as-client-side + */ +function copy2clipboard($string) { + $descriptorspec = array( + 0 => array("pipe", "r"), // stdin is a pipe that the child will read from + 1 => array("pipe", "w"), // stdout is a pipe that the child will write to + 2 => array("file", "a.txt", "a") // stderr is a file to write to + ); + $process = proc_open('pbcopy', $descriptorspec, $pipes); + if (is_resource($process)) { + fwrite($pipes[0], $string); + fclose($pipes[0]); + fclose($pipes[1]); + + $return_value = proc_close($process); + return $return_value; + } +} + +/** + * showInSpotify function. + * + * @param mixed $w + */ +function showInSpotify($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + exec("osascript -e 'tell application \"Spotify\" to activate'"); + exec("osascript -e 'set uri to \"$results[4]\"' -e 'tell application \"Spotify\" to open location uri'"); + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * getPlaylistOwner function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function getPlaylistOwner($w, $playlist_uri) +{ + $url = ''; + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + try { + $api = getSpotifyWebAPI($w); + $playlist = $api->getPlaylist($playlist_id, array( + 'fields' => array( + 'owner', + ), + )); + + return $playlist->owner->id; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, '', 'Error: Spotify WEB API returned error '.$e->getMessage(),array( + 'function getPlaylistOwner playlist_uri=' . $playlist_uri, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + + return ''; + } +} + + +/** + * resetPlaylistNumberTimesPlayed function. + * + * @param mixed $w + */ +function resetPlaylistNumberTimesPlayed($w) +{ + $dbfile = $w->data().'/library.db'; + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $resetPlaylistNumberTimesPlayed = 'update playlists set nb_times_played=0'; + $stmtResetPlaylistNumberTimesPlayed = $db->prepare($resetPlaylistNumberTimesPlayed); + $stmtResetPlaylistNumberTimesPlayed->execute(); + + } catch (PDOException $e) { + logMsg('Error(resetPlaylistNumberTimesPlayed): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return false; + } + return true; +} + +/** + * updatePlaylistNumberTimesPlayed function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function updatePlaylistNumberTimesPlayed($w, $playlist_uri) +{ + $dbfile = $w->data().'/library.db'; + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $updatePlaylistNumberTimesPlayed = 'update playlists set nb_times_played=nb_times_played+1 where uri=:uri'; + $stmtUpdatePlaylistNumberTimesPlayed = $db->prepare($updatePlaylistNumberTimesPlayed); + + $stmtUpdatePlaylistNumberTimesPlayed->bindValue(':uri', $playlist_uri); + $stmtUpdatePlaylistNumberTimesPlayed->execute(); + + } catch (PDOException $e) { + logMsg('Error(updatePlaylistNumberTimesPlayed): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return false; + } + return true; +} + +/** + * isUserPremiumSubscriber function. + * + * @param mixed $w + */ + function isUserPremiumSubscriber($w) + { + try { + $api = getSpotifyWebAPI($w); + $me = $api->me(); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + return false; + } + + if (isset($me->product)) { + if($me->product == 'premium') { + return true; + } + } + + return false; + } + +/** + * getArtistName function. + * + * @param mixed $w + * @param mixed $artist_uri + */ + function getArtistName($w, $artist_uri) + { + try { + $api = getSpotifyWebAPI($w); + // check if it is part collection + $tmp = explode(':', $artist_uri); + if (isset($tmp[3]) && $tmp[3] == 'collection') { + $artist_uri = 'spotify:artist:' . $tmp[5]; + } + $artist = $api->getArtist($artist_uri); + + return $artist->name; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, '', 'Error: Spotify WEB API returned error '.$e->getMessage(),array( + 'function getArtistName artist_uri=' . $artist_uri, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + + return ''; + } + } + +/** + * getAlbumName function. + * + * @param mixed $w + * @param mixed $album_uri + */ + function getAlbumName($w, $album_uri) + { + try { + $api = getSpotifyWebAPI($w); + // check if it is part collection + $tmp = explode(':', $album_uri); + if (isset($tmp[3]) && $tmp[3] == 'collection') { + $album_uri = 'spotify:album:' . $tmp[5]; + } + + $album = $api->getAlbum($album_uri); + + return $album->name; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, '', 'Error: Spotify WEB API returned error '.$e->getMessage(),array( + 'function getAlbumName album_uri=' . $album_uri, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + + return ''; + } + } + +/** + * getPlaylistName function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ + function getPlaylistName($w, $playlist_uri) + { + $url = ''; + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else if(isset($tmp[2])) { + $playlist_id = $tmp[2]; + } else { + return ''; + } + try { + $api = getSpotifyWebAPI($w); + $playlist = $api->getPlaylist($playlist_id, array( + 'fields' => array( + 'name', + ), + )); + + return $playlist->name; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w->result(null, '', 'Error: Spotify WEB API returned error '.$e->getMessage(),array( + 'function getPlaylistName playlist_uri=' . $playlist_uri, + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + + return ''; + } + } + +/** + * setRepeatStateSpotifyConnect function. + * + * @param string $w + */ + function setRepeatStateSpotifyConnect($w, $device_id, $state) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->repeat([ + 'state' => $state, + 'device_id' => $device_id, + ]); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(setRepeatStateSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * isRepeatStateSpotifyConnectActive function. + * + * @param mixed $w + */ + function isRepeatStateSpotifyConnectActive($w) + { + // Read settings from JSON + + $settings = getSettings($w); + + $country_code = $settings->country_code; + + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $playback_info = $api->getMyCurrentPlaybackInfo(array( + 'market' => $country_code, + )); + $retry = false; + + if($playback_info->repeat_state == 'track') { + return true; + } else if($playback_info->repeat_state == 'context') { + return true; + } + return false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(isRepeatStateSpotifyConnectActive): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return false; + } + } + } + } + + +/** + * setShuffleStateSpotifyConnect function. + * + * @param mixed $w + */ + function setShuffleStateSpotifyConnect($w, $device_id, $state) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->shuffle([ + 'state' => $state, + 'device_id' => $device_id, + ]); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(setShuffleStateSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * getVolumeSpotifyConnect function. + * + * @param mixed $w + */ + function getVolumeSpotifyConnect($w, $device_id) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $devices = $api->getMyDevices(); + $retry = false; + if(isset($devices->devices)) { + foreach ($devices->devices as $device) { + if ($device->is_active) { + return $device->volume_percent; + } + } + } + return false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getVolumeSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } +} + +/** + * changeVolumeSpotifyConnect function. + * + * @param mixed $w + */ + function changeVolumeSpotifyConnect($w, $device_id, $volume_percent) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->changeVolume([ + 'volume_percent' => $volume_percent, + ]); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(changeVolumeSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * playTrackSpotifyConnect function. + * + * @param mixed $w + */ + function playTrackSpotifyConnect($w, $device_id, $track_uri, $context_uri) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + if ($context_uri != '') { + if ($track_uri != '') { + $offset = [ + 'uri' => $track_uri, + ]; + $options = [ + 'context_uri' => $context_uri, + 'offset' => $offset, + ]; + } else { + $options = [ + 'context_uri' => $context_uri, + ]; + } + $api->play($device_id, $options); + $retry = false; + } else { + $uris = array(); + $uris[] = $track_uri; + $options = [ + 'uris' => $uris + ]; + $api->play($device_id, $options); + $retry = false; + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(playTrackSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * nextTrackSpotifyConnect function. + * + * @param mixed $w + */ + function nextTrackSpotifyConnect($w, $device_id) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->next($device_id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(nextTrackSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * previousTrackSpotifyConnect function. + * + * @param mixed $w + */ + function previousTrackSpotifyConnect($w, $device_id) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->previous($device_id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(previousTrackSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * playpauseSpotifyConnect function. + * + * @param mixed $w + */ + function playpauseSpotifyConnect($w, $device_id, $country_code) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $playback_info = $api->getMyCurrentPlaybackInfo(array( + 'market' => $country_code, + )); + + if(isset($playback_info->is_playing)) { + $is_playing = $playback_info->is_playing; + if ($is_playing) { + $api->pause($device_id); + } else { + $api->play($device_id); + } + $retry = false; + } else { + logMsg('Error(playpauseSpotifyConnect): is_playing not set '.$device_id); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(playpauseSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * playSpotifyConnect function. + * + * @param mixed $w + */ + function playSpotifyConnect($w, $device_id) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->play($device_id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(playSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * pauseSpotifyConnect function. + * + * @param mixed $w + */ + function pauseSpotifyConnect($w, $device_id) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->pause($device_id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(pauseSpotifyConnect): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + +/** + * getSpotifyConnectCurrentDeviceId function. + * + * @param mixed $w + */ + function getSpotifyConnectCurrentDeviceId($w) + { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $devices = $api->getMyDevices(); + $retry = false; + if(isset($devices->devices)) { + foreach ($devices->devices as $device) { + if ($device->is_active) { + return $device->id; + } + } + // no active device, get first in the list + foreach ($devices->devices as $device) { + changeUserDevice($w, $device->id); + return $device->id; + } + } + // open Spotify App + if(getenv('automatically_open_spotify_app')) { + $retry = true; + exec("osascript -e 'tell application \"Spotify\" to activate'"); + sleep(5); + continue; + } + return ''; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getMessage() == 'Permissions missing') { + $retry = false; + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'reset_oauth_settings' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'The workflow needs more privilages to do this, click to restart authentication', array( + 'Next time you invoke the workflow, you will have to re-authenticate', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'yes', null, ''); + } else { + logMsg('Error(getSpotifyConnectCurrentDeviceId): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + } + } + + +/** + * changeUserDevice function. + * + * @param mixed $w + */ + function changeUserDevice($w, $device_id) + { + $options = [ + 'device_ids' => $device_id, + 'play' => true + ]; + + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $api->changeMyDevice($options); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(changeUserDevice): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + return true; + } + +function isSpotifyAppInstalled() +{ + exec("osascript -e 'id of application \"Spotify\"'", $retArr, $retVal); + if ($retVal != 0) { + return false; + } + return true; +} +/** + * isShuffleActive function. + * + */ +function isShuffleActive($print_output) +{ + $w = new Workflows('com.vdesabou.spotify.mini.player'); + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $country_code = $settings->country_code; + + if ($output_application == 'MOPIDY') { + $isShuffleEnabled = invokeMopidyMethod($w, 'core.tracklist.get_random', array()); + if ($isShuffleEnabled) { + $command_output = 'true'; + } else { + $command_output = 'false'; + } + } else if($output_application == 'APPLESCRIPT') { + $command_output = exec("osascript -e ' + tell application \"Spotify\" + if shuffling enabled is true then + if shuffling is true then + return \"true\" + else + return \"false\" + end if + else + return \"false\" + end if + end tell'"); + } else { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $playback_info = $api->getMyCurrentPlaybackInfo(array( + 'market' => $country_code, + )); + + if($playback_info->shuffle_state) { + $command_output = 'true'; + } else { + $command_output = 'false'; + } + + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(isShuffleActive): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return false; + } + } + } + } + if($print_output) { + echo $command_output; + } + + return $command_output; +} + +/** + * getUserArtworkURL function. + * + * @param mixed $w + */ +function getUserArtworkURL($w, $user_id) +{ + $url = ''; + try { + $api = getSpotifyWebAPI($w); + $user = $api->getUser(urlencode($user_id)); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + return $url; + } + + if (isset($user->images)) { + + if (isset($user->images[0]) && isset($user->images[0]->url)) { + return $user->images[0]->url; + } + } + + return $url; +} + +/** + * getUserArtwork function. + * + * @param mixed $w + */ +function getUserArtwork($w, $user_id, $forceFetch = false) +{ + $user_folder = $w->data().'/users/'.$user_id; + $currentArtwork = $user_folder.'/'.$user_id.'.png'; + + if(!$forceFetch) { + if(file_exists($currentArtwork)) { + return $currentArtwork; + } + } + + $url = getUserArtworkURL($w, $user_id); + + if($url != '') { + if (!file_exists($user_folder)) { + return './images/artists.png'; + } + + $fp = fopen($currentArtwork, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + $w->request("$url", $options); + + return $currentArtwork; + } else { + copy('./images/artists.png', $currentArtwork); + return './images/artists.png'; + } +} + +/** + * getCurrentUser function. + * + * @param mixed $w + */ +function getCurrentUser($w) +{ + $current_user = $w->read('current_user.json'); + + if ($current_user == false) { + // This should only happen once + + $settings = getSettings($w); + $userid = $settings->userid; + + if($userid == false) { + return; + } + + $ret = $w->write($userid, 'current_user.json'); + + $user_folder = $w->data().'/users/'.$userid; + if (!file_exists($user_folder)) { + exec("mkdir -p '".$user_folder."'"); + + if (file_exists($w->data().'/library.db')) { + rename($w->data().'/library.db', $user_folder.'/library.db'); + link($user_folder.'/library.db',$w->data().'/library.db'); + } + if (file_exists($w->data().'/settings.json')) { + rename($w->data().'/settings.json', $user_folder.'/settings.json'); + link($user_folder.'/settings.json',$w->data().'/settings.json'); + } + if (file_exists($w->data().'/history.json')) { + rename($w->data().'/history.json', $user_folder.'/history.json'); + link($user_folder.'/history.json',$w->data().'/history.json'); + } + } + + $current_user = $w->read('current_user.json'); + } + + return $current_user; +} + +/** + * switchUser function. + * + * @param mixed $w + */ +function switchUser($w, $new_user) +{ + $new_user_folder = $w->data().'/users/'.$new_user; + + if (file_exists($w->data().'/library.db')) { + deleteTheFile($w->data().'/library.db'); + } + if (file_exists($new_user_folder.'/library.db')) { + link($new_user_folder.'/library.db',$w->data().'/library.db'); + } + + if (file_exists($w->data().'/settings.json')) { + deleteTheFile($w->data().'/settings.json'); + } + if (file_exists($new_user_folder.'/settings.json')) { + link($new_user_folder.'/settings.json',$w->data().'/settings.json'); + } + + if (file_exists($w->data().'/history.json')) { + deleteTheFile($w->data().'/history.json'); + } + if (file_exists($new_user_folder.'/history.json')) { + link($new_user_folder.'/history.json',$w->data().'/history.json'); + } + + $ret = $w->write($new_user, 'current_user.json'); + + displayNotificationWithArtwork($w, 'Current user is now ' . $new_user, getUserArtwork($w, $new_user, true), 'Switch User'); + + return; +} + +/** + * newUser function. + * + * @param mixed $w + */ +function newUser($w) +{ + if (file_exists($w->data().'/library.db')) { + deleteTheFile($w->data().'/library.db'); + } + if (file_exists($w->data().'/settings.json')) { + deleteTheFile($w->data().'/settings.json'); + } + if (file_exists($w->data().'/history.json')) { + deleteTheFile($w->data().'/history.json'); + } + + // just delete the file + if (file_exists($w->data().'/current_user.json')) { + deleteTheFile($w->data().'/current_user.json'); + } + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini')."\"'"); + + return; +} + +/** + * listUsers function. + * + * @param mixed $w + */ +function listUsers($w) +{ + $users_folder = $w->data().'/users/'; + $users = scandir($users_folder); + // loop on users + foreach ($users as $user) { + if ($user == '.' || $user == '..' || $user == '.DS_Store') { + continue; + } + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + 'SWITCH_USER▹'.$user /* other_settings*/, + '' /* other_action */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '', /* playlist_artwork_path */ + )), 'Switch user to '.$user.'', 'Type enter to validate', getUserArtwork($w, $user), 'yes', null, ''); + } +} +/** + * getSpotifyWebAPI function. + * + * @param mixed $w + */ +function getSpotifyWebAPI($w, $old_api = null) +{ + // Read settings from JSON + + $settings = getSettings($w); + $oauth_client_id = $settings->oauth_client_id; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_redirect_uri = $settings->oauth_redirect_uri; + $oauth_access_token = $settings->oauth_access_token; + $oauth_expires = $settings->oauth_expires; + $oauth_refresh_token = $settings->oauth_refresh_token; + + if ($old_api == null) { + // create a new api object + $session = new SpotifyWebAPI\Session($oauth_client_id, $oauth_client_secret, $oauth_redirect_uri); + $api = new SpotifyWebAPI\SpotifyWebAPI(); + } + + // Check if refresh token necessary + // if token validity < 20 minutes + if (time() - $oauth_expires > 2400) { + if ($old_api != null) { + // when refresh needed: + // create a new api object (even if api not null) + $session = new SpotifyWebAPI\Session($oauth_client_id, $oauth_client_secret, $oauth_redirect_uri); + $api = new SpotifyWebAPI\SpotifyWebAPI(); + } + if ($session->refreshAccessToken($oauth_refresh_token) == true) { + $oauth_access_token = $session->getAccessToken(); + // Set new token to settings + $ret = updateSetting($w, 'oauth_access_token', $oauth_access_token); + if ($ret == false) { + throw new SpotifyWebAPI\SpotifyWebAPIException('Cannot set oauth_access_token', 100); + } + + $ret = updateSetting($w, 'oauth_expires', time()); + if ($ret == false) { + throw new SpotifyWebAPI\SpotifyWebAPIException('Cannot set oauth_expires', 100); + } + $api->setAccessToken($oauth_access_token); + } else { + throw new SpotifyWebAPI\SpotifyWebAPIException('Token could not be refreshed', 100); + } + } else { + // no need to refresh, the old api is + // stil valid + if ($old_api != null) { + $api = $old_api; + } else { + // set the access token for the new api + $api->setAccessToken($oauth_access_token); + } + } + + return $api; +} + +/** + * invokeMopidyMethod function. + * + * @param mixed $w + * @param mixed $method + * @param mixed $params + * @param bool $displayError (default: true) + */ +function invokeMopidyMethod($w, $method, $params, $displayError = true) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $mopidy_server = $settings->mopidy_server; + $mopidy_port = $settings->mopidy_port; + + exec("curl -s -X POST -H Content-Type:application/json -d '{ + \"method\": \"" .$method.'", + "jsonrpc": "2.0", + "params": ' .json_encode($params, JSON_HEX_APOS).", + \"id\": 1 +}' http://" .$mopidy_server.':'.$mopidy_port.'/mopidy/rpc', $retArr, $retVal); + + if ($retVal != 0) { + if ($displayError) { + displayNotificationWithArtwork($w, 'Mopidy Exception: returned error '.$retVal, './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' Mopidy Exception: returned error '.$retVal."\"'"); + } + + return false; + } + + if (isset($retArr[0])) { + $result = json_decode($retArr[0]); + if (isset($result->result)) { + return $result->result; + } + if (isset($result->error)) { + logMsg('Error(invokeMopidyMethod): '.$method.' params: '.json_encode($params, JSON_HEX_APOS).' exception:'.print_r($result)); + + if ($displayError) { + displayNotificationWithArtwork($w, 'Mopidy Exception: '.htmlspecialchars($result->error->message), './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' Mopidy Exception: '.htmlspecialchars($result->error->message)."\"'"); + } + + return false; + } + } else { + logMsg('Error(invokeMopidyMethod): empty response from Mopidy method: '.$method.' params: '.json_encode($params, JSON_HEX_APOS)); + displayNotificationWithArtwork($w, 'ERROR: empty response from Mopidy method: '.$method.' params: '.json_encode($params, JSON_HEX_APOS), './images/warning.png'); + } +} + +/** + * switchThemeColor function. + * + * @param mixed $w + */ +function switchThemeColor($w,$theme_color) +{ + touch($w->data().'/change_theme_color_in_progress'); + $nb_images_downloaded = 0; + $nb_images_total = 222; + $w->write('Change Theme Color to ' . $theme_color . '▹'. 0 .'▹'. $nb_images_total .'▹'.time().'▹'.'starting', 'change_theme_color_in_progress'); + $in_progress_data = $w->read('change_theme_color_in_progress'); + $words = explode('▹', $in_progress_data); + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + + $imgs = scandir('./images/'); + + // replace icons from images directory + foreach ($imgs as $img) { + if ($img == '.' || $img == '..' + || $img == 'alfred-workflow-icon.png') { + continue; + } + + $icon_url = 'https://github.com/vdesabou/alfred-spotify-mini-player/raw/master/resources/images_' . $theme_color . '/'.$img; + + $fp = fopen('./images/'.$img, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$icon_url", $options); + + ++$nb_images_downloaded; + if ($nb_images_downloaded % 10 === 0) { + $w->write('Change Theme Color to ' . $theme_color . '▹'.$nb_images_downloaded.'▹'.$nb_images_total.'▹'.$words[3].'▹'.'Icons', 'change_theme_color_in_progress'); + } + } + + // check icons from images directory + $hasError = false; + foreach ($imgs as $img) { + if ($img == '.' || $img == '..' + || $img == 'alfred-workflow-icon.png') { + continue; + } + + if (!is_file('./images/'.$img) || (is_file('./images/'.$img) && filesize('./images/'.$img) == 0)) { + $hasError = true; + logMsg('Error(switchThemeColor): (failed to load '.$img.')'); + } + } + + // replace UUID images + $uuid_imgs = array( + '0A7E4CC3-BA4A-4DD4-AB4B-E2E8F9DBBE8C' => 'playpause', + 'F0ED23FA-8524-4769-B610-828611958D6A' => 'recent', + '0B75CF43-8B04-405F-86C3-2FFC59AC4A70' => 'artists', + '05F86AA1-D3EE-4409-9A58-898B36FFE503' => 'kill', + '15209065-AB33-44E4-ADFC-BAFC5033762E' => 'numbers', + '15B503BB-DA3F-4B7B-8E4C-94E968ECDCF2' => 'volmax', + '16F5C3BF-01EE-493C-9E7B-CC54D482B7A6' => 'playlists', + '1BA522F3-B2D0-4F36-B86C-738FB3AC55DD' => 'volume_up', + '1F30DEA9-0A81-4E00-9CF0-E7D086C6B5B0' => 'keyup', + '2B0C6211-1DD0-4CE6-8082-37957F15CC1D' => 'mute', + '2B0C8466-4AED-4272-9C10-50F3BCE88043' => 'update', + '804D8959-D2AE-453E-BBC1-3C11B275597B' => 'spotify', + '2F1F6369-46C0-483B-816F-3796168AE060' => 'repeating', + '2FC567E2-E6C5-4A91-B42E-1996532B78C9' => 'albums', + '303A65BF-8E81-48E8-AA28-E1CA408FDD53' => 'keydown', + '3040749D-6B5C-4CCD-AF95-AEC0F83B48D9' => 'current_track', + '3617F927-558D-4F30-B8D1-B7789F863AB0' => 'play_queue', + '39A1935A-37F5-49FA-A860-BCF7765A8C65' => 'icon', + '3F85747B-FC44-4B07-AA6E-3645F0CC0DF7' => 'add_to_ap_yourmusic', + '450AEF8B-BDAA-409C-A0D4-68769545FBCF' => 'keyescape', + '455BDE70-BCF4-447F-ABFF-C25D8E5B08B6' => 'radio_song', + '4BE9FB30-9B4F-4E44-861D-D178507A7568' => 'remove_from', + '4EB5FB5E-6472-4757-A479-B206B6080036' => 'next', + '552D77E3-1550-4035-AB49-8B708B081EC9' => 'online_artist', + '5AF7EEEC-2E55-482C-8750-4CE6AD752683' => 'play', + '5C5C6FFD-4A1B-42C4-AF81-E88A92245DD2' => 'play', + '5EB4A672-01BC-4DBB-AD39-60EBB0F79A67' => 'add_to_ap_yourmusic', + '62AA861E-C910-4354-84C9-58A5660365D8' => 'remove_from', + '66F8A022-163E-42CB-A9E9-B32E8158ACA7' => 'previous', + '6E9B4F21-F907-4A22-8689-9A146F909454' => 'playpause', + '78DAB9D1-72A3-4B44-AB3B-D1C71F13DF7A' => 'keyenter', + '794A76A7-BB98-4A83-92BE-386A56875120' => 'issue', + '79F70A28-E2D9-4705-81A9-86F3EA8EB47F' => 'alfred_playlist', + '7FE5D993-C14D-4B94-9479-B361680F1C40' => 'add_to', + '7FF09231-F068-4EA0-8537-6C1EB608CA5A' => 'volume_down', + '8339BE15-274E-4A77-A6A0-CEDF30EFD0E5' => 'next', + '8598A5C9-72B6-4CEF-A498-D6C2ED06DC88' => 'radio_song', + '873EF61A-BD03-4946-87B0-C7AE5DFC5E5B' => 'debug', + '89BC46B4-E178-4855-8863-393730814F6E' => 'shuffle', + 'BD255BDB-07A5-4EE9-858F-A58C6207D191' => 'shuffle', + '8C78472B-13EB-4512-B94D-4BF92867CD92' => 'random', + '8E4347FE-0FC3-4FF1-AAAF-E0C6CD084BB5' => 'volume_down', + '8F478980-199B-45B5-AD41-EBA185446705' => 'issue', + '8F8CF9CC-2B4D-4F8E-A211-C32DD49E84F4' => 'playlists', + '9661EF24-91C3-44A1-9066-8E9B9817841D' => 'artists', + '9B2621F0-0190-4ABD-A09F-3DBF85548580' => 'random_album', + '9E3FE06C-F5F8-41F3-A70F-B92E187EED75' => 'volmid', + 'A0EAB8B1-F034-490F-9534-44ADF572AF4E' => 'uncheck', + 'A0F746BD-C7AF-490F-B4D9-8BAEDDDAEF90' => 'alfred_playlist', + 'E6CEF7D4-CFA9-4608-A188-65B33A602BAF' => 'alfred_playlist', + '11E4CA98-E51E-45E4-91ED-72B4A1A34283' => 'alfred_playlist', + 'A38DD404-DE03-42C2-B0CB-A37891B6F24D' => 'info', + 'A41190FA-4B23-4908-A4B7-16A14F338C11' => 'repeating', + 'A76C26BD-BA48-4797-839B-BE439FF40846' => 'pause', + 'A8BE6109-BCC0-4A41-9375-C1D2E3A755BD' => 'volmax', + 'AC236315-8CDE-41E3-A9BA-BB59D292FE14' => 'lyrics', + 'B23712E3-4564-4668-BD6D-4D535839CC8C' => 'uncheck', + 'B77F5F98-C065-49A4-BBB1-68ADADDD8E7D' => 'albums', + 'BA289B3E-779E-482F-AFEA-8E1395513365' => 'browse', + 'BC488027-E76B-43A7-B414-C7FAA9CF9995' => 'random', + 'C10A975C-0DAE-4A45-AEAB-4E07CF125703' => 'radio_artist', + 'C588A188-D8D3-450F-9020-5EBB563F6B8A' => 'update', + 'C7CFF014-DBC8-4663-A0AB-219C57A427EE' => 'mute', + 'C93B7A2B-9105-4456-997A-1BCC4EDA5A27' => 'radio_artist', + 'CD9D3654-8137-49B2-80DC-095E97A58E67' => 'previous', + 'CEF36AB9-7CC2-4765-BF84-751E88B69023' => 'debug', + 'D31A5001-4590-418E-9AB0-6183E75E59DE' => 'random_album', + 'D4442911-E17B-49CC-8F7F-EAC1830B11CD' => 'volume_up', + 'D8C53798-B7E2-4A51-AC12-37FEBDB624E0' => 'online_artist', + 'D931B685-B5F8-4BBC-9FCB-D78F9FA0AB66' => 'volume_up', + 'DC403223-17FA-466B-9488-7292DA9D8223' => 'info', + 'DC678CF5-D8B2-4508-A2FA-CB0F0E253108' => 'online', + 'DD0755A4-3C70-467C-A005-11F10E23CEF0' => 'settings', + 'E45DF42A-58A9-4069-A410-EC2BBC8A0575' => 'new_releases', + 'EA03C1F5-912A-4422-B766-2BBC94DC0344' => 'volmid', + 'EBD3FE58-A201-4C3D-A2DD-7CD9A6D50A2E' => 'alfred_playlist', + 'EF574432-0896-4A92-9944-7DA5DD7295DA' => 'biography', + 'F250A59C-0B2D-4A08-9085-9CA0A2FB2DCC' => 'volume_up', + 'F4382654-9318-4849-82E4-550AC235148C' => 'pause', + 'F4F5AC18-3C04-4673-9CC3-E563094C9446' => 'add_to', + '0EBF4C61-5630-4629-8B4F-AD91D3470760' => 'share', + 'E5BAF801-726E-49C0-ABF2-7AD9F9ECD22A' => 'share', + 'FAA5FC99-7909-45B6-9BF0-7601DBAADC4F' => 'youtube', + 'C323BECC-0183-4562-B817-65624E13B3F3' => 'share', + 'B8D706BB-D6E9-4AE3-B36B-ED6D4B34AD5F' => 'connect', + 'icon' => 'icon', + ); + + foreach ($uuid_imgs as $key => $value) { + $icon_url = 'https://github.com/vdesabou/alfred-spotify-mini-player/raw/master/resources/images_' . $theme_color . '/'.$value.'@3x.png'; + + $fp = fopen('./'.$key.'.png', 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$icon_url", $options); + ++$nb_images_downloaded; + if ($nb_images_downloaded % 5 === 0) { + $w->write('Change Theme Color to ' . $theme_color . '▹'.$nb_images_downloaded.'▹'.$nb_images_total.'▹'.$words[3].'▹'.'Icons UUID', 'change_theme_color_in_progress'); + } + } + + // check UUID images + foreach ($uuid_imgs as $key => $value) { + if (!is_file('./'.$key.'.png') || (is_file('./'.$key.'.png') && filesize('./'.$key.'.png') == 0)) { + $hasError = true; + logMsg('Error(switchThemeColor): (failed to load UUID '.$key.')'); + } + } + + // replace UUID items images for remote + $uuid_imgs = array( + 'FDAEECD4-DE40-443C-89F9-B46D5592D8C4' => 'issue', + 'F14D664A-48D5-4232-A6CD-772F3361630B' => 'new_releases', + 'EE84BB33-1412-4F21-8B4D-D09362ECFE7A' => 'volmax', + 'EA114C5E-A6A7-479E-BDB8-17E9C3163B53' => 'current_track', + 'E8BE74B6-2928-4513-A0BC-B88EBF839ABD' => 'mute', + 'E7ECAC10-DDC2-4860-A342-A876756D8812' => 'playpause', + 'DF3FC215-4E94-472D-91B2-9D94A3B8632F' => 'keyenter', + 'D427D63A-3C3A-420D-87D5-46185FE361E3' => 'online_artist', + 'DA2F787C-11F7-4C7A-B275-A4CFFE171012' => 'spotify', + 'D191C6F2-CF3A-4F3A-AEDB-9D8B03EA7EC9' => 'albums', + 'D51D9C70-68AF-4D63-ABD0-09906D9B1EC9' => 'playlists', + 'CED135C7-B958-4C68-8C47-956FBAA9086A' => 'remove_from', + 'CC39269A-4977-48A1-8427-F9CFC2AE8EED' => 'play', + 'AF86DFA1-E6C7-4C2B-BD00-66614B6CFE81' => 'update', + 'AEC59638-4779-4470-9A6A-E32992498ED2' => 'pause', + 'AE944AAF-0B18-436F-AB21-1B22AA446063' => 'browse', + 'A6374417-A3FC-4360-9913-504F7A21F4F1' => 'radio_artist', + '3690378D-02F4-4BF9-BC91-975F3739542B' => 'random', + '2737969D-A8B4-4550-8568-3C926D36DD81' => 'add_to_ap_yourmusic', + '2375184C-CC97-4763-A846-D2FAB1259FD1' => 'random_album', + '707403B7-FF4A-4995-99F3-AB2B5F39B34F' => 'debug', + 'E9C9194B-AF5F-4BAD-88AB-DB7AFED380BF' => 'recent', + '163265DD-5CAB-4D11-B984-F86871709AEE' => 'icon', + '9045D879-6632-4113-9915-85534EBECBB1' => 'online', + '5365AF85-EDB1-4789-9ABD-B272A8C96AA0' => 'volume_down', + '4368A343-21A8-44C7-96F9-4870FA1C2EFB' => 'previous', + '924A7250-A8D3-4944-BDEF-74B3DD32DC75' => 'volume_up', + '749D3ABB-38FB-4EFB-9E3D-881C5AF5CAC9' => 'next', + '577A4640-8D94-4813-9223-B355BE7FE1BD' => 'shuffle', + '569B0F42-A04A-40B7-9E86-EA1C61EF0AE5' => 'play_queue', + '26215986-3B9E-4491-A93B-67878CE04EB5' => 'alfred_playlist', + '89CD46BC-7C18-4D85-A23B-CF5F93273B1A' => 'keyescape', + '83F461DC-A47F-4407-92C3-BF269BB49953' => 'uncheck', + '83D8A06D-1B1C-4B90-A00A-5B5E575DF7E8' => 'radio_song', + '58AF0E83-EC70-42B2-AED5-DB7DF65C043C' => 'info', + '41AECA11-8410-4CFF-8BAB-51FE6DE283F4' => 'volmid', + '27BDEB50-2E71-474D-B329-30EBFB7BC663' => 'artists', + '19E641F3-FE15-4058-9597-255FDDAA4F48' => 'settings', + '9B2EBB97-E54C-420E-BB2E-20AC87764C68' => 'repeating', + '8B60A0B6-910F-4B63-A0B1-953D9A99990F' => 'lyrics', + '6D35BFAD-C96C-4BF8-B76B-5C4BB4313DF9' => 'keydown', + '5C18A3F0-C5CC-4B8D-B71E-B00B420CA2DC' => 'keyup', + '4FE5620A-FB79-440E-8633-B8148EE1191E' => 'add_to', + 'C5B9A789-80F3-41BA-9A46-C34DD4CDE050' => 'share', + '15D6EBE2-6D82-4F2C-A4B3-5949424B4EF9' => 'youtube', + '28180F27-0728-414D-88F3-76E99A58FA7D' => 'connect', + ); + + foreach ($uuid_imgs as $key => $value) { + $icon_url = 'https://github.com/vdesabou/alfred-spotify-mini-player/raw/master/resources/images_' . $theme_color . '/'.$value.'@3x.png'; + + $fp = fopen('./_remote/images/items/'.$key.'.png', 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$icon_url", $options); + + ++$nb_images_downloaded; + if ($nb_images_downloaded % 5 === 0) { + $w->write('Change Theme Color to ' . $theme_color . '▹'.$nb_images_downloaded.'▹'.$nb_images_total.'▹'.$words[3].'▹'.'Icons remote', 'change_theme_color_in_progress'); + } + } + + // check UUID images + foreach ($uuid_imgs as $key => $value) { + if (!is_file('./_remote/images/items/'.$key.'.png') || (is_file('./_remote/images/items/'.$key.'.png') && filesize('./_remote/images/items/'.$key.'.png') == 0)) { + $hasError = true; + logMsg('Error(switchThemeColor): (failed to load UUID items remote '.$key.')'); + } + } + + // replace UUID pages images for remote + $uuid_imgs = array( + '8F6D8768-149A-492E-B88F-DECA4DB283B5' => 'keyenter', + '31BE3663-05A1-4380-9955-ECBD4E1AD618' => 'next', + '657FE771-8978-4E40-9AA9-201603AC8B5F' => 'update', + ); + + foreach ($uuid_imgs as $key => $value) { + $icon_url = 'https://github.com/vdesabou/alfred-spotify-mini-player/raw/master/resources/images_' . $theme_color . '/'.$value.'@3x.png'; + + $fp = fopen('./_remote/images/pages/'.$key.'.png', 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$icon_url", $options); + + ++$nb_images_downloaded; + if ($nb_images_downloaded % 5 === 0) { + $w->write('Change Theme Color to ' . $theme_color . '▹'.$nb_images_downloaded.'▹'.$nb_images_total.'▹'.$words[3].'▹'.'Icons UUID remote page', 'change_theme_color_in_progress'); + } + } + + // check UUID images + foreach ($uuid_imgs as $key => $value) { + if (!is_file('./_remote/images/pages/'.$key.'.png') || (is_file('./_remote/images/pages/'.$key.'.png') && filesize('./_remote/images/pages/'.$key.'.png') == 0)) { + $hasError = true; + logMsg('Error(switchThemeColor): (failed to load UUID pages remote '.$key.')'); + } + } + + // Get APP + $app_url = 'https://github.com/vdesabou/alfred-spotify-mini-player/raw/master/resources/images_' . $theme_color . '/' . rawurlencode('Spotify Mini Player.app.zip'); + + $zip_file = '/tmp/SpotifyMiniPlayer.app.zip'; + $fp = fopen($zip_file, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$app_url", $options); + ++$nb_images_downloaded; + $w->write('Change Theme Color to ' . $theme_color . '▹'.$nb_images_downloaded.'▹'.$nb_images_total.'▹'.$words[3].'▹'.'Icons UUID remote page', 'change_theme_color_in_progress'); + + if (!is_file($zip_file) || (is_file($zip_file) && filesize($zip_file) == 0)) { + $hasError = true; + logMsg('Error(switchThemeColor): (failed to load /tmp/SpotifyMiniPlayer.app.zip for '.$theme_color.')'); + } + $zip_command = 'unzip ' . $zip_file . ' -d ' . '\'./App/'.$theme_color.'/\''; + exec($zip_command); + + exec('open "'.'./App/'.$theme_color.'/Spotify Mini Player.app'.'"'); + //update settings + $ret = updateSetting($w, 'theme_color', $theme_color); + + deleteTheFile($w->data().'/change_theme_color_in_progress'); + if (!$hasError) { + displayNotificationWithArtwork($w, 'All existing icons have been replaced by ' . $theme_color . ' icons', './images/change_theme_color.png', 'Settings'); + } else { + displayNotificationWithArtwork($w, 'Some icons have not been replaced', './images/warning.png'); + } +} + +/** + * createDebugFile function. + * + * @param mixed $w + */ +function createDebugFile($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + $oauth_client_secret = $settings->oauth_client_secret; + $oauth_access_token = $settings->oauth_access_token; + $oauth_refresh_token = $settings->oauth_refresh_token; + $display_name = $settings->display_name; + $userid = $settings->userid; + $theme_color = $settings->theme_color; + + exec('mkdir -p /tmp/spot_mini_debug'); + date_default_timezone_set('UTC'); + $date = date('Y-m-d H:i:s', time()); + + $output = "Please take time to describe your problem in a few lines:\n"; + + $output = $output."----------------------------------------------\n"; + + $output = $output."\n\n\n\n"; + + $output = $output."----------------------------------------------\n"; + + $output = $output."\n\n\n"; + + $output = $output."-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"; + $output = $output.'Generated: '.$date."\n"; + + // check for library update in progress + if (file_exists($w->data().'/update_library_in_progress')) { + $output = $output.'Library update in progress: '.'the file'.$w->data()."/update_library_in_progress is present\n"; + } + + // settings.json + + copy($w->data().'/settings.json', '/tmp/spot_mini_debug/settings.json'); + // Remove oAuth values from file that will be uploaded + updateSetting($w, 'oauth_client_secret', 'xxx', '/tmp/spot_mini_debug/settings.json'); + updateSetting($w, 'oauth_access_token', 'xxx', '/tmp/spot_mini_debug/settings.json'); + updateSetting($w, 'display_name', 'xxx', '/tmp/spot_mini_debug/settings.json'); + $output = $output.'* display_name: '.$display_name."\n\n"; + $output = $output.'* oauth_client_secret: '.$oauth_client_secret."\n\n"; + $output = $output.'* oauth_access_token: '.$oauth_access_token."\n\n"; + $output = $output.'* oauth_refresh_token: '.$oauth_refresh_token."\n\n"; + + $output = $output."****\n"; + + copyDirectory($w->cache(), '/tmp/spot_mini_debug/cache'); + + if (!file_exists($w->data().'/fetch_artworks.db')) { + $output = $output.'The file '.$w->data()."/fetch_artworks.db is not present\n"; + } else { + copy($w->data().'/fetch_artworks.db', '/tmp/spot_mini_debug/fetch_artworks.db'); + } + + if (!file_exists($w->data().'/library.db')) { + $output = $output.'The file '.$w->data()."/library.db is not present\n"; + } else { + copy($w->data().'/library.db', '/tmp/spot_mini_debug/library.db'); + } + + if (!file_exists($w->data().'/library_new.db')) { + $output = $output.'The file '.$w->data()."/library_new.db is not present\n"; + } else { + copy($w->data().'/library_new.db', '/tmp/spot_mini_debug/library_new.db'); + } + + if (!file_exists($w->data().'/library_old.db')) { + $output = $output.'The file '.$w->data()."/library_old.db is not present\n"; + } else { + copy($w->data().'/library_old.db', '/tmp/spot_mini_debug/library_old.db'); + } + + if (!file_exists($w->data().'/history.json')) { + $output = $output.'The file '.$w->data()."/history.json is not present\n"; + } else { + copy($w->data().'/history.json', '/tmp/spot_mini_debug/history.json'); + } + + if (!file_exists($w->data().'/playqueue.json')) { + $output = $output.'The file '.$w->data()."/playqueue.json is not present\n"; + } else { + copy($w->data().'/playqueue.json', '/tmp/spot_mini_debug/playqueue.json'); + } + + if (!file_exists(exec('pwd').'/packal/package.xml')) { + $output = $output.'The file '.exec('pwd')."/packal/package.xml is not present\n"; + } else { + copy(exec('pwd').'/packal/package.xml', '/tmp/spot_mini_debug/package.xml'); + } + + if (!file_exists($w->data().'/users')) { + $output = $output.'The directory '.$w->data()."/users is not present\n"; + } + + copyDirectory($w->path().'/src', '/tmp/spot_mini_debug/src'); + + $output = $output.exec('uname -a'); + $output = $output."\n"; + $output = $output.exec('sw_vers -productVersion'); + $output = $output."\n"; + $output = $output.exec('sysctl hw.memsize'); + $output = $output."\n"; + $output = $output.'alfred_version:'.getenv('alfred_version'); + $output = $output."\n"; + $output = $output.'alfred_version_build:'.getenv('alfred_version_build'); + $output = $output."\n"; + $output = $output.'alfred_workflow_version:'.getenv('alfred_workflow_version'); + $output = $output."\n"; + $output = $output.'alfred_debug:'.getenv('alfred_debug'); + $output = $output."\n"; + if ($output_application != 'MOPIDY') { + $output = $output.'Spotify desktop version:'.exec("osascript -e 'tell application \"Spotify\" to version'"); + } else { + $output = $output.'Mopidy version:'.invokeMopidyMethod($w, 'core.get_version', array(), false); + } + $output = $output."\n"; + + + exec('/usr/bin/xattr "'.'./App/'.$theme_color.'/Spotify Mini Player.app'.'"',$response); + $output = $output."xattr Spotify Mini Player.app returned: "; + foreach($response as $line) { + $output = $output.$line; + $output = $output."\n"; + } + $output = $output."\n"; + exec('/usr/bin/xattr "'.'./terminal-notifier.app'.'"',$response); + $output = $output."xattr alerter returned: "; + foreach($response as $line) { + $output = $output.$line; + $output = $output."\n"; + } + $output = $output."\n"; + + exec('cd /tmp;zip -r spot_mini_debug.zip spot_mini_debug'); + + $output = $output."****\n"; + + $output = $output.exec("curl -s --upload-file /tmp/spot_mini_debug.zip https://transfer.sh/spot_mini_debug_$userid.zip"); + + exec('cd /tmp;rm -rf spot_mini_debug.zip spot_mini_debug'); + + copy2clipboard($output); + + exec("open \"mailto:alfred.spotify.mini.player@gmail.com?subject=Alfred Spotify Mini Player debug file&body=$output\""); +} +/** + * getCurrentTrackInfoWithMopidy function. + * + * @param mixed $w + * @param bool $displayError (default: true) + */ +function getCurrentTrackInfoWithMopidy($w, $displayError = true) +{ + $tl_track = invokeMopidyMethod($w, 'core.playback.get_current_track', array(), $displayError); + if ($tl_track == false) { + return 'mopidy_stopped'; + } + $state = invokeMopidyMethod($w, 'core.playback.get_state', array(), $displayError); + + $track_name = ''; + $artist_name = ''; + $album_name = ''; + $track_uri = ''; + $length = 0; + + if (isset($tl_track->name)) { + $track_name = $tl_track->name; + } + + if (isset($tl_track->artists) && + isset($tl_track->artists[0]) && + isset($tl_track->artists[0])) { + $artist_name = $tl_track->artists[0]->name; + } + + if (isset($tl_track->album) && isset($tl_track->album->name)) { + $album_name = $tl_track->album->name; + } + + if (isset($tl_track->uri)) { + $track_uri = $tl_track->uri; + } + + if (isset($tl_track->length)) { + $length = $tl_track->length; + } + + return ''.$track_name.'▹'.$artist_name.'▹'.$album_name.'▹'.$state.'▹'.$track_uri.'▹'.$length.'▹'.'0'; +} + +/** + * getCurrentTrackInfoWithSpotifyConnect function. + * + * @param mixed $w + * @param bool $displayError (default: true) + */ + function getCurrentTrackInfoWithSpotifyConnect($w, $displayError = true) + { + // Read settings from JSON + $settings = getSettings($w); + $country_code = $settings->country_code; + + $track_name = ''; + $artist_name = ''; + $album_name = ''; + $track_uri = ''; + $length = 0; + + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + + $current_track_info = $api->getMyCurrentTrack(array( + 'market' => $country_code, + )); + + $retry = false; + + if(!isset($current_track_info->item->name)) { + return ''; + } + $track_name = $current_track_info->item->name; + $artist_name = $current_track_info->item->artists[0]->name; + $album_name = $current_track_info->item->album->name; + $is_playing = $current_track_info->is_playing; + if ($is_playing) { + $state = 'playing'; + } else { + $state = 'paused'; + } + if (isset($current_track_info->item->linked_from) && isset($current_track_info->item->linked_from->uri)) { + $track_uri = $current_track_info->item->linked_from->uri; + } else { + $track_uri = $current_track_info->item->uri; + } + + $length = ($current_track_info->item->duration_ms); + $popularity = $current_track_info->item->popularity; + + $retArr = array(''.$track_name.'▹'.$artist_name.'▹'.$album_name.'▹'.$state.'▹'.$track_uri.'▹'.$length.'▹'.$popularity); + return ''.$track_name.'▹'.$artist_name.'▹'.$album_name.'▹'.$state.'▹'.$track_uri.'▹'.$length.'▹'.$popularity; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return 'connect_stopped'; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return 'connect_stopped'; + } + return 'connect_stopped'; + } + } + } + +/** + * playUriWithMopidyWithoutClearing function. + * + * @param mixed $w + * @param mixed $uri + */ +function playUriWithMopidyWithoutClearing($w, $uri) +{ + $tl_tracks = invokeMopidyMethod($w, 'core.tracklist.add', array('uris' => array($uri), 'at_position' => 0)); + if (isset($tl_tracks[0])) { + invokeMopidyMethod($w, 'core.playback.play', array('tl_track' => $tl_tracks[0])); + } else { + displayNotificationWithArtwork($w, 'Cannot play track with uri '.$uri, './images/warning.png', 'Error!'); + } +} + +/** + * playUriWithMopidy function. + * + * @param mixed $w + * @param mixed $uri + */ +function playUriWithMopidy($w, $uri) +{ + invokeMopidyMethod($w, 'core.tracklist.clear', array()); + playUriWithMopidyWithoutClearing($w, $uri); +} + +/** + * playTrackInContextWithMopidy function. + * + * @param mixed $w + * @param mixed $track_uri + * @param mixed $context_uri + */ +function playTrackInContextWithMopidy($w, $track_uri, $context_uri) +{ + invokeMopidyMethod($w, 'core.tracklist.clear', array()); + invokeMopidyMethod($w, 'core.tracklist.add', array('uri' => $context_uri, 'at_position' => 0)); + $tl_tracks = invokeMopidyMethod($w, 'core.tracklist.get_tl_tracks', array()); + + // loop to find track_uri + $i = 0; + foreach ($tl_tracks as $tl_track) { + if ($tl_track->track->uri == $track_uri) { + // found the track move it to position 0 + invokeMopidyMethod($w, 'core.tracklist.move', array('start' => $i, 'end' => $i, 'to_position' => 0)); + } + ++$i; + } + + $tl_tracks = invokeMopidyMethod($w, 'core.tracklist.get_tl_tracks', array()); + invokeMopidyMethod($w, 'core.playback.play', array('tl_track' => $tl_tracks[0])); +} + +/** + * setThePlaylistPrivacy function. + * + * @param mixed $w + * @param mixed $playlist_uri + * @param mixed $playlist_name + * @param bool $public + */ +function setThePlaylistPrivacy($w, $playlist_uri, $playlist_name, $public) +{ + try { + $tmp = explode(':', $playlist_uri); + $api = getSpotifyWebAPI($w); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $ret = $api->updatePlaylist($playlist_id, array('name' => escapeQuery($playlist_name), + 'public' => $public, )); + if ($ret == true) { + // refresh library + refreshLibrary($w); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(updatePlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } +} + +/** + * followThePlaylist function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function followThePlaylist($w, $playlist_uri) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $is_public_playlists = $settings->is_public_playlists; + + $public = false; + if ($is_public_playlists) { + $public = true; + } + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + try { + $api = getSpotifyWebAPI($w); + $ret = $api->followPlaylistForCurrentUser($playlist_id, array('public' => $public)); + if ($ret == true) { + // refresh library + refreshLibrary($w); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(followThePlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } +} + +/** + * unfollowThePlaylist function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function unfollowThePlaylist($w, $playlist_uri) +{ + try { + $tmp = explode(':', $playlist_uri); + $api = getSpotifyWebAPI($w); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $ret = $api->unfollowPlaylistForCurrentUser($playlist_id); + if ($ret == true) { + // refresh library + refreshLibrary($w); + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(unfollowPlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } +} + +/** + * addPlaylistToPlayQueue function. + * + * @param mixed $w + * @param mixed $playlist_uri + * @param mixed $playlist_name + */ +function addPlaylistToPlayQueue($w, $playlist_uri, $playlist_name) +{ + if (!$w->internet()) { + return false; + } + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + + if ($output_application != 'MOPIDY') { + $tracks = getThePlaylistFullTracks($w, $playlist_uri); + if ($tracks == false) { + displayNotificationWithArtwork($w, 'Cannot get tracks for playlist '.$playlist_name, './images/warning.png', 'Error!'); + + return false; + } + } else { + $tracks = array(); + } + $playqueue = array( + 'type' => 'playlist', + 'uri' => $playlist_uri, + 'name' => escapeQuery($playlist_name), + 'current_track_index' => 0, + 'tracks' => $tracks, + ); + $w->write($playqueue, 'playqueue.json'); +} + +/** + * addAlbumToPlayQueue function. + * + * @param mixed $w + * @param mixed $album_uri + * @param mixed $album_name + */ +function addAlbumToPlayQueue($w, $album_uri, $album_name) +{ + if (!$w->internet()) { + return false; + } + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + + if ($output_application != 'MOPIDY') { + $tracks = getTheAlbumFullTracks($w, $album_uri); + if ($tracks == false) { + displayNotificationWithArtwork($w, 'Cannot get tracks for album '.$album_name, './images/warning.png', 'Error!'); + + return false; + } + } else { + $tracks = array(); + } + + $playqueue = array( + 'type' => 'album', + 'uri' => $album_uri, + 'name' => escapeQuery($album_name), + 'current_track_index' => 0, + 'tracks' => $tracks, + ); + $w->write($playqueue, 'playqueue.json'); +} + +/** + * addArtistToPlayQueue function. + * + * @param mixed $w + * @param mixed $artist_uri + * @param mixed $artist_name + * @param mixed $country_code + */ +function addArtistToPlayQueue($w, $artist_uri, $artist_name, $country_code) +{ + if (!$w->internet()) { + return false; + } + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + $country_code = $settings->country_code; + + if ($output_application != 'MOPIDY') { + $tracks = getTheArtistFullTracks($w, $artist_uri, $country_code); + if ($tracks == false) { + displayNotificationWithArtwork($w, 'Cannot get tracks for artist '.$artist_name, './images/warning.png', 'Error!'); + + return false; + } + } else { + $tracks = array(); + } + + $playqueue = array( + 'type' => 'artist', + 'uri' => $artist_uri, + 'name' => escapeQuery($artist_name), + 'current_track_index' => 0, + 'tracks' => $tracks, + ); + $w->write($playqueue, 'playqueue.json'); +} + +/** + * addTrackToPlayQueue function. + * + * @param mixed $w + * @param mixed $track_uri + * @param mixed $track_name + * @param mixed $artist_name + * @param mixed $album_name + * @param mixed $duration + * @param mixed $country_code + */ +function addTrackToPlayQueue($w, $track_uri, $track_name, $artist_name, $album_name, $duration, $country_code) +{ + if (!$w->internet()) { + return false; + } + + // Read settings from JSON + + $settings = getSettings($w); + $output_application = $settings->output_application; + + $track = new stdClass(); + if ($output_application != 'MOPIDY') { + $tracks = array(); + $track = getTheFullTrack($w, $track_uri, $country_code); + if ($track == false) { + $track = new stdClass(); + $track->uri = $track_uri; + $track->name = $track_name; + $artists = array(); + $artist = new stdClass(); + $artist->name = $artist_name; + $artists[0] = $artist; + $track->artists = $artists; + $album = new stdClass(); + $album->name = $album_name; + $track->album = $album; + if (is_numeric($duration)) { + $track->duration_ms = $duration * 1000; + } else { + $track->duration = $duration; + } + } + } else { + $tracks = array(); + } + + $playqueue = $w->read('playqueue.json'); + if ($playqueue == false) { + $tracks[] = $track; + $newplayqueue = array( + 'type' => 'track', + 'uri' => $track_uri, + 'name' => escapeQuery($track_name), + 'current_track_index' => 0, + 'tracks' => $tracks, + ); + } else { + // replace current track by new track + $playqueue->tracks[$playqueue->current_track_index] = $track; + if ($output_application != 'MOPIDY') { + $tracks = $playqueue->tracks; + } + if ($playqueue->type != '') { + $newplayqueue = array( + 'type' => $playqueue->type, + 'uri' => $playqueue->uri, + 'name' => $playqueue->name, + 'current_track_index' => $playqueue->current_track_index, + 'tracks' => $tracks, + ); + } else { + $newplayqueue = array( + 'type' => 'track', + 'uri' => $track_uri, + 'name' => escapeQuery($track_name), + 'current_track_index' => $playqueue->current_track_index, + 'tracks' => $tracks, + ); + } + } + $w->write($newplayqueue, 'playqueue.json'); +} + +/** + * updategkIndexFromPlayQueue function. + * + * @param mixed $w + */ +function updateCurrentTrackIndexFromPlayQueue($w) +{ + $playqueue = $w->read('playqueue.json'); + if ($playqueue == false) { + displayNotificationWithArtwork($w, 'No play queue yet', './images/warning.png', 'Error!'); + } + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $found = false; + $i = 0; + $current_track_name = cleanupTrackName($results[0]); + if (isset($playqueue->tracks)) { + if (count($playqueue->tracks) > 0) { + foreach ($playqueue->tracks as $track) { + $track_name = cleanupTrackName($track->name); + if (escapeQuery($track_name) == escapeQuery($current_track_name) && + escapeQuery($track->artists[0]->name) == escapeQuery($results[1])) { + $found = true; + break; + } + ++$i; + } + } + } + + if ($found == false) { + // empty queue + $newplayqueue = array( + 'type' => '', + 'uri' => '', + 'name' => '', + 'current_track_index' => 0, + 'tracks' => array(), + ); + } else { + $newplayqueue = array( + 'type' => $playqueue->type, + 'uri' => $playqueue->uri, + 'name' => $playqueue->name, + 'current_track_index' => $i, + 'tracks' => $playqueue->tracks, + ); + } + $w->write($newplayqueue, 'playqueue.json'); + } +} + +/** + * getBiography function. + * + * @param mixed $w + * @param mixed $artist_uri + * @param mixed $artist_name + */ +function getBiography($w, $artist_uri, $artist_name) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $echonest_api_key = $settings->echonest_api_key; + + // THIS IS BROKEN, see http://developer.echonest.com + // SPOTIFY WEB API DOES NO SUPPORT IT YET https://github.com/spotify/web-api/issues/207 + + $json = doJsonRequest($w, 'http://developer.echonest.com/api/v4/artist/biographies?api_key='.$echonest_api_key.'&id='.$artist_uri); + $response = $json->response; + + foreach ($response->biographies as $biography) { + if ($biography->site == 'wikipedia') { + $wikipedia = $biography->text; + $wikipedia_url = $biography->url; + } + if ($biography->site == 'last.fm') { + $lastfm = $biography->text; + $lastfm_url = $biography->url; + } + $default = 'Source: '.$biography->site.'\n'.$biography->text; + $default_url = $biography->url; + } + + if ($lastfm) { + $text = $lastfm; + $source = 'Last FM'; + $url = $lastfm_url; + } elseif ($wikipedia) { + $text = $wikipedia; + $source = 'Wikipedia'; + $url = $wikipedia_url; + } else { + $text = $default; + $source = $biography->site; + $url = $default_url; + } + if ($text == '') { + return array(false, '', '', ''); + } + $output = strip_tags($text); + + // Get URLs of artist, if available + $json = doJsonRequest($w, 'http://developer.echonest.com/api/v4/artist/urls?api_key='.$echonest_api_key.'&id='.$artist_uri); + + $twitter_url = ''; + if (isset($json->response->urls->twitter_url)) { + $twitter_url = $json->response->urls->twitter_url; + } + + $official_url = ''; + if (isset($json->response->urls->official_url)) { + $official_url = $json->response->urls->official_url; + } + + return array($url, $source, $output, $twitter_url, $official_url); +} + +/** + * searchWebApi function. + * + * @param mixed $w + * @param mixed $country_code + * @param mixed $query + * @param mixed $type + * @param int $limit (default: 50) + * @param bool $actionMode (default: true) + */ +function searchWebApi($w, $country_code, $query, $type, $limit = 50, $actionMode = true) +{ + $results = array(); + + try { + if ($limit != 50) { + $limitSearch = $limit; + } else { + $limitSearch = 50; + } + $api = getSpotifyWebAPI($w); + $searchResults = $api->search($query, $type, array( + 'market' => $country_code, + 'limit' => $limitSearch, + )); + + if ($type == 'artist') { + foreach ($searchResults->artists->items as $item) { + $results[] = $item; + } + } elseif ($type == 'track') { + foreach ($searchResults->tracks->items as $item) { + $results[] = $item; + } + } elseif ($type == 'album') { + foreach ($searchResults->albums->items as $item) { + $results[] = $item; + } + } elseif ($type == 'playlist') { + foreach ($searchResults->playlists->items as $item) { + $results[] = $item; + } + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($actionMode == true) { + logMsg('Error(search): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + } else { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + } + + return false; + } + + return $results; +} + +/** + * playAlfredPlaylist function. + * + * @param mixed $w + */ +function playAlfredPlaylist($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $output_application = $settings->output_application; + $use_artworks = $settings->use_artworks; + + if ($alfred_playlist_uri == '' || $alfred_playlist_name == '') { + displayNotificationWithArtwork($w, 'Alfred Playlist is not set', './images/warning.png'); + + return; + } + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $alfred_playlist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$alfred_playlist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $alfred_playlist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addPlaylistToPlayQueue($w, $alfred_playlist_uri, $alfred_playlist_name); + $playlist_artwork_path = getPlaylistArtwork($w, $alfred_playlist_uri, true, true, $use_artworks); + displayNotificationWithArtwork($w, '🔈 Alfred Playlist '.$alfred_playlist_name, $playlist_artwork_path, 'Play Alfred Playlist'); +} + +/** + * lookupCurrentArtist function. + * + * @param mixed $w + */ +function lookupCurrentArtist($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + $artist_uri = getArtistUriFromSearch($w, $results[1]); + } else { + $artist_uri = getArtistUriFromTrack($w, $results[4]); + } + + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Online▹'.$artist_uri.'@'.escapeQuery($results[1]).'▹'."\"'"); + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * displayCurrentArtistBiography function. + * + * @param mixed $w + */ +function displayCurrentArtistBiography($w) +{ + if (!$w->internet()) { + displayNotificationWithArtwork($w, 'No internet connection', './images/warning.png'); + + return; + } + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + $artist_uri = getArtistUriFromSearch($w, $results[1]); + } else { + $artist_uri = getArtistUriFromTrack($w, $results[4]); + } + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Biography▹'.$artist_uri.'∙'.escapeQuery($results[1]).'▹'."\"'"); + } else { + displayNotificationWithArtwork($w, 'No artist is playing', './images/warning.png'); + } +} + +/** + * playCurrentArtist function. + * + * @param mixed $w + */ +function playCurrentArtist($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $country_code = $settings->country_code; + $use_artworks = $settings->use_artworks; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + $artist_uri = getArtistUriFromSearch($w, $results[1]); + } else { + $artist_uri = getArtistUriFromTrack($w, $results[4]); + } + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $artist_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$artist_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $artist_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addArtistToPlayQueue($w, $artist_uri, escapeQuery($results[1]), $country_code); + displayNotificationWithArtwork($w, '🔈 Artist '.escapeQuery($results[1]), getArtistArtwork($w, $artist_uri, $results[1], true, false, false, $use_artworks), 'Play Current Artist'); + } else { + displayNotificationWithArtwork($w, 'No artist is playing', './images/warning.png'); + } +} + +/** + * playCurrentAlbum function. + * + * @param mixed $w + */ +function playCurrentAlbum($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $use_artworks = $settings->use_artworks; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + $album_uri = getAlbumUriFromTrack($w, $results[4]); + if ($album_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current album', './images/warning.png', 'Error!'); + + return; + } + + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $album_uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$album_uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $album_uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addAlbumToPlayQueue($w, $album_uri, escapeQuery($results[2])); + displayNotificationWithArtwork($w, '🔈 Album '.escapeQuery($results[2]), getTrackOrAlbumArtwork($w, $results[4], true, false, false, $use_artworks), 'Play Current Album', $use_artworks); + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * addCurrentTrackTo function. + * + * @param mixed $w + */ +function addCurrentTrackTo($w,$playlist_uri='') +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $use_artworks = $settings->use_artworks; + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + // local track, look it up online + + $query = 'track:'.escapeQuery($results[0]).' artist:'.escapeQuery($results[1]); + $searchResults = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($searchResults) > 0) { + // only one track returned + $track = $searchResults[0]; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + logMsg("Info(addCurrentTrackTo): Unknown track $results[4] / $results[0] / $results[1] replaced by track: $track->uri / $track->name / $artist->name / $album->uri"); + $results[4] = $track->uri; + } else { + logMsg("Error(addCurrentTrackTo): Could not find track: $results[4] / $results[0] / $results[1] "); + displayNotificationWithArtwork($w, 'Local track '.escapeQuery($results[0]).' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + if($playlist_uri == '' ) { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Add▹'.$results[4].'∙'.escapeQuery($results[0]).'▹'."\"'"); + } else { + $tmp = explode(':', $results[4]); + $playlist_name = getPlaylistName($w, $playlist_uri); + + if($playlist_name == '') { + displayNotificationWithArtwork($w, 'Cannot get playlist name using playlist uri <'.$playlist_uri.'>', './images/warning.png', 'Error!'); + return; + } + $ret = addTracksToPlaylist($w, $tmp[2], $playlist_uri, $playlist_name, false); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' added to Playlist '.$playlist_name, getTrackOrAlbumArtwork($w, $results[4], true, false, false, $use_artworks), 'Add Current Track to Playlist'); + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' is already in Alfred Playlist '.$playlist_name, './images/warning.png', 'Error!'); + } + } + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * removeCurrentTrackFrom function. + * + * @param mixed $w + */ +function removeCurrentTrackFrom($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Remove▹'.$results[4].'∙'.escapeQuery($results[0]).'▹'."\"'"); + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png'); + } +} + +/** + * addCurrentTrackToAlfredPlaylistOrYourMusic function. + * + * @param mixed $w + */ +function addCurrentTrackToAlfredPlaylistOrYourMusic($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + + if ($is_alfred_playlist_active == true) { + addCurrentTrackToAlfredPlaylist($w); + } else { + addCurrentTrackToYourMusic($w); + } +} + +/** + * addCurrentTrackToAlfredPlaylist function. + * + * @param mixed $w + */ +function addCurrentTrackToAlfredPlaylist($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + + // Read settings from JSON + + $settings = getSettings($w); + + $is_alfred_playlist_active = $settings->is_alfred_playlist_active; + $alfred_playlist_uri = $settings->alfred_playlist_uri; + $alfred_playlist_name = $settings->alfred_playlist_name; + $country_code = $settings->country_code; + $use_artworks = $settings->use_artworks; + + if ($alfred_playlist_uri == '' || $alfred_playlist_name == '') { + displayNotificationWithArtwork($w, 'Alfred Playlist is not set', './images/warning.png'); + + return; + } + + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + // local track, look it up online + + $query = 'track:'.escapeQuery($results[0]).' artist:'.escapeQuery($results[1]); + $searchResults = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($searchResults) > 0) { + // only one track returned + $track = $searchResults[0]; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + logMsg("Info(addCurrentTrackToAlfredPlaylist): Unknown track $results[4] / $results[0] / $results[1] replaced by track: $track->uri / $track->name / $artist->name / $album->uri"); + $results[4] = $track->uri; + } else { + logMsg("Error(addCurrentTrackToAlfredPlaylist): Could not find track: $results[4] / $results[0] / $results[1] "); + displayNotificationWithArtwork($w, 'Local track '.escapeQuery($results[0]).' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + + $tmp = explode(':', $results[4]); + $ret = addTracksToPlaylist($w, $tmp[2], $alfred_playlist_uri, $alfred_playlist_name, false); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' added to Alfred Playlist '.$alfred_playlist_name, getTrackOrAlbumArtwork($w, $results[4], true, false, false, $use_artworks), 'Add Current Track to Alfred Playlist'); + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' is already in Alfred Playlist '.$alfred_playlist_name, './images/warning.png', 'Error!'); + } + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png', 'Error!'); + } +} + +/** + * addCurrentTrackToYourMusic function. + * + * @param mixed $w + */ +function addCurrentTrackToYourMusic($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $use_artworks = $settings->use_artworks; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + // local track, look it up online + + $query = 'track:'.escapeQuery($results[0]).' artist:'.escapeQuery($results[1]); + $searchResults = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($searchResults) > 0) { + // only one track returned + $track = $searchResults[0]; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + logMsg("Info(addCurrentTrackToYourMusic): Unknown track $results[4] / $results[0] / $results[1] replaced by track: $track->uri / $track->name / $artist->name / $album->uri"); + $results[4] = $track->uri; + } else { + logMsg("Error(addCurrentTrackToYourMusic): Could not find track: $results[4] / $results[0] / $results[1] "); + displayNotificationWithArtwork($w, 'Local track '.escapeQuery($results[0]).' has not online match', './images/warning.png', 'Error!'); + + return; + } + } + $tmp = explode(':', $results[4]); + $ret = addTracksToYourMusic($w, $tmp[2], false); + if (is_numeric($ret) && $ret > 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' added to Your Music', getTrackOrAlbumArtwork($w, $results[4], true, false, false, $use_artworks), 'Add Current Track to Your Music'); + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, ''.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' is already in Your Music', './images/warning.png'); + } + } else { + displayNotificationWithArtwork($w, 'No track is playing', './images/warning.png', 'Error!'); + } +} + +/** + * addTracksToYourMusic function. + * + * @param mixed $w + * @param mixed $tracks + * @param bool $allow_duplicate (default: true) + */ +function addTracksToYourMusic($w, $tracks, $allow_duplicate = true) +{ + $tracks = (array) $tracks; + $tracks_with_no_dup = array(); + $tracks_contain = array(); + if (!$allow_duplicate) { + try { + $api = getSpotifyWebAPI($w); + // Note: max 50 Ids + $offset = 0; + do { + $output = array_slice($tracks, $offset, 50); + $offset += 50; + + if (count($output)) { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $tracks_contain = $api->myTracksContains($output); + for ($i = 0; $i < count($output); ++$i) { + if (!$tracks_contain[$i]) { + $tracks_with_no_dup[] = $output[$i]; + } + } + } + } while (count($output) > 0); + + $tracks = $tracks_with_no_dup; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(addTracksToYourMusic): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + } + + if (count($tracks) != 0) { + try { + $api = getSpotifyWebAPI($w); + $offset = 0; + do { + $output = array_slice($tracks, $offset, 50); + $offset += 50; + + if (count($output)) { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $api->addMyTracks($output); + } + } while (count($output) > 0); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(addTracksToYourMusic): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + // refresh library + refreshLibrary($w); + } + + return count($tracks); +} + +/** + * addTracksToPlaylist function. + * + * @param mixed $w + * @param mixed $tracks + * @param mixed $playlist_uri + * @param mixed $playlist_name + * @param bool $allow_duplicate (default: true) + * @param bool $refreshLibrary (default: true) + */ +function addTracksToPlaylist($w, $tracks, $playlist_uri, $playlist_name, $allow_duplicate = true, $refreshLibrary = true) +{ + $tracks_with_no_dup = array(); + if (!$allow_duplicate) { + $playlist_tracks = getThePlaylistTracks($w, $playlist_uri); + foreach ((array) $tracks as $track) { + if (!checkIfDuplicate($playlist_tracks, $track)) { + $tracks_with_no_dup[] = $track; + } + } + $tracks = $tracks_with_no_dup; + } + + if (count($tracks) != 0) { + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $playlist_uri); + + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + + // Note: max 100 Ids + $offset = 0; + $i = 0; + do { + $output = array_slice($tracks, $offset, 100); + $offset += 100; + + if (count($output)) { + // refresh api + $api = getSpotifyWebAPI($w, $api); + + if(getenv('append_to_playlist_when_adding_tracks') == 0) { + $api->addPlaylistTracks($playlist_id, $output, array( + 'position' => 0, + )); + } else { + $api->addPlaylistTracks($playlist_id, $output); + } + ++$i; + } + /* + if($i % 30 === 0) { + sleep(60); + echo "Info: Throttling in addTracksToPlaylist"; + } + */ + } while (count($output) > 0); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(addTracksToPlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + if ($refreshLibrary) { + refreshLibrary($w); + } + } + + return count($tracks); +} + +/** + * removeTrackFromPlaylist function. + * + * @param mixed $w + * @param mixed $track_uri + * @param mixed $playlist_uri + * @param mixed $playlist_name + * @param bool $refreshLibrary (default: true) + */ +function removeTrackFromPlaylist($w, $track_uri, $playlist_uri, $playlist_name, $refreshLibrary = true) +{ + + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $api->deletePlaylistTracks($playlist_id, array( + array( + 'id' => $track_uri, + ), + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(removeTrackFromPlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + if ($refreshLibrary) { + refreshLibrary($w); + } + + return true; +} + +/** + * removeTrackFromYourMusic function. + * + * @param mixed $w + * @param mixed $track_uri + * @param bool $refreshLibrary (default: true) + */ +function removeTrackFromYourMusic($w, $track_uri, $refreshLibrary = true) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $userid = $settings->userid; + + try { + $api = getSpotifyWebAPI($w); + $api->deleteMyTracks($track_uri); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(removeTrackFromYourMusic): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + if ($refreshLibrary) { + refreshLibrary($w); + } + + return true; +} + +/** + * getRandomTrack function. + * + * @param mixed $w + */ +function getRandomTrack($w) +{ + // check for library DB + $dbfile = ''; + if (file_exists($w->data().'/update_library_in_progress')) { + if (file_exists($w->data().'/library_old.db')) { + $dbfile = $w->data().'/library_old.db'; + } + } else { + $dbfile = $w->data().'/library.db'; + } + if ($dbfile == '') { + return false; + } + + // Get random track from DB + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $getTracks = 'select uri,track_name,artist_name,album_name,duration from tracks order by random() limit 1'; + $stmt = $db->prepare($getTracks); + $stmt->execute(); + $track = $stmt->fetch(); + $thetrackuri = $track[0]; + $thetrackname = $track[1]; + $theartistname = $track[2]; + $thealbumname = $track[3]; + $theduration = $track[4]; + } catch (PDOException $e) { + handleDbIssuePdoEcho($db, $w); + } + + return array($thetrackuri, $thetrackname, $theartistname, $thealbumname, $theduration); +} + +/** + * getRandomAlbum function. + * + * @param mixed $w + */ +function getRandomAlbum($w) +{ + // check for library DB + $dbfile = ''; + if (file_exists($w->data().'/update_library_in_progress')) { + if (file_exists($w->data().'/library_old.db')) { + $dbfile = $w->data().'/library_old.db'; + } + } else { + $dbfile = $w->data().'/library.db'; + } + if ($dbfile == '') { + return false; + } + + // Get random album from DB + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $getTracks = 'select album_uri,album_name,artist_name from tracks where yourmusic=1 order by random() limit 1'; + $stmt = $db->prepare($getTracks); + $stmt->execute(); + $track = $stmt->fetch(); + $thealbumuri = $track[0]; + $thealbumname = $track[1]; + $theartistname = $track[2]; + } catch (PDOException $e) { + handleDbIssuePdoEcho($db, $w); + } + + return array($thealbumuri, $thealbumname, $theartistname); +} + +/** + * getArtistUriFromTrack function. + * + * @param mixed $w + * @param mixed $track_uri + */ +function getArtistUriFromTrack($w, $track_uri) +{ + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + + try { + $tmp = explode(':', $track_uri); + + if (isset($tmp[1]) && $tmp[1] == 'ad') { + return false; + } + + if (isset($tmp[1]) && $tmp[1] == 'local') { + // local track, look it up online + // spotify:local:The+D%c3%b8:On+My+Shoulders+-+Single:On+My+Shoulders:318 + // spotify:local:Damien+Rice:B-Sides:Woman+Like+a+Man+%28Live%2c+Unplugged%29:284 + + $query = 'track:'.urldecode($tmp[4]).' artist:'.urldecode($tmp[2]); + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $artists = $track->artists; + $artist = $artists[0]; + + return $artist->uri; + } else { + logMsg("Error(getArtistUriFromTrack): Could not find artist from uri: $track_uri"); + + return false; + } + } + $api = getSpotifyWebAPI($w); + $track = $api->getTrack($tmp[2]); + $artists = $track->artists; + $artist = $artists[0]; + + return $artist->uri; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + // do nothing + } + + return false; +} + +/** + * getArtistUriFromSearch function. + * + * @param mixed $w + * @param mixed $artist_name + * @param mixed $country_code + */ +function getArtistUriFromSearch($w, $artist_name, $country_code = '') +{ + if ($artist_name == '') { + return false; + } + if ($country_code == '') { + + // Read settings from JSON + + $settings = getSettings($w); + + $country_code = $settings->country_code; + } + $searchResults = searchWebApi($w, $country_code, $artist_name, 'artist', 1); + + if (count($searchResults) > 0) { + // only one artist returned + $artist = $searchResults[0]; + } else { + return false; + } + + return $artist->uri; +} + +/** + * getAlbumUriFromTrack function. + * + * @param mixed $w + * @param mixed $track_uri + */ +function getAlbumUriFromTrack($w, $track_uri) +{ + try { + $tmp = explode(':', $track_uri); + + if (isset($tmp[1]) && $tmp[1] == 'local') { + + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + // local track, look it up online + // spotify:local:The+D%c3%b8:On+My+Shoulders+-+Single:On+My+Shoulders:318 + // spotify:local:Damien+Rice:B-Sides:Woman+Like+a+Man+%28Live%2c+Unplugged%29:284 + + $query = 'track:'.urldecode($tmp[4]).' artist:'.urldecode($tmp[2]); + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $album = $track->album; + + return $album->uri; + } else { + logMsg("Error(getAlbumUriFromTrack): Could not find album from uri: $track_uri"); + + return false; + } + } + $api = getSpotifyWebAPI($w); + $track = $api->getTrack($tmp[2]); + $album = $track->album; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getAlbumUriFromTrack): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return $album->uri; +} + +/** + * clearPlaylist function. + * + * @param mixed $w + * @param mixed $playlist_uri + * @param mixed $playlist_name + */ +function clearPlaylist($w, $playlist_uri, $playlist_name) +{ + try { + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $emptytracks = array(); + $api = getSpotifyWebAPI($w); + $api->replacePlaylistTracks($playlist_id, $emptytracks); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(clearPlaylist): playlist uri '.$playlist_uri.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + // refresh library + refreshLibrary($w); + + return true; +} + +/** + * createTheUserPlaylist function. + * + * @param mixed $w + * @param mixed $playlist_name + */ +function createTheUserPlaylist($w, $playlist_name) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $is_public_playlists = $settings->is_public_playlists; + + $public = false; + if ($is_public_playlists) { + $public = true; + } + try { + $api = getSpotifyWebAPI($w); + $json = $api->createPlaylist(array( + 'name' => $playlist_name, + 'public' => $public, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(createPlaylist): createPlaylist '.$playlist_name.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return $json->uri; +} + +/** + * createRadioArtistPlaylistForCurrentArtist function. + * + * @param mixed $w + */ +function createRadioArtistPlaylistForCurrentArtist($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + $tmp = explode(':', $results[4]); + if (isset($tmp[1]) && $tmp[1] == 'local') { + $artist_uri = getArtistUriFromSearch($w, $results[1]); + } else { + $artist_uri = getArtistUriFromTrack($w, $results[4]); + } + + if ($artist_uri == false) { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + + return; + } + createRadioArtistPlaylist($w, $results[1], $artist_uri); + } else { + displayNotificationWithArtwork($w, 'Cannot get current artist', './images/warning.png', 'Error!'); + } +} + +/** + * createRadioArtistPlaylist function. + * + * @param mixed $w + * @param mixed $artist_name + * @param mixed $artist_uri + */ +function createRadioArtistPlaylist($w, $artist_name, $artist_uri) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $radio_number_tracks = $settings->radio_number_tracks; + $userid = $settings->userid; + $is_public_playlists = $settings->is_public_playlists; + $is_autoplay_playlist = $settings->is_autoplay_playlist; + $country_code = $settings->country_code; + $use_artworks = $settings->use_artworks; + $output_application = $settings->output_application; + + $public = false; + if ($is_public_playlists) { + $public = true; + } + + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $artist_uri); + $recommendations = $api->getRecommendations(array( + 'seed_artists' => array($tmp[2]), + 'market' => $country_code, + 'limit' => $radio_number_tracks, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(createRadioArtistPlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + exit; + } + + $newplaylisttracks = array(); + foreach ($recommendations->tracks as $track) { + $newplaylisttracks[] = $track->id; + } + + if (count($newplaylisttracks) > 0) { + try { + $api = getSpotifyWebAPI($w); + $json = $api->createPlaylist(array( + 'name' => 'Artist radio for '.escapeQuery($artist_name), + 'public' => $public, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(createPlaylist): radio artist '.$artist_name.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + $ret = addTracksToPlaylist($w, $newplaylisttracks, $json->uri, $json->name, false, false); + if (is_numeric($ret) && $ret > 0) { + if ($is_autoplay_playlist) { + sleep(2); + + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $json->uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$json->uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $json->uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addPlaylistToPlayQueue($w, $json->uri, $json->name); + $playlist_artwork_path = getPlaylistArtwork($w, $json->uri, true, false, $use_artworks); + displayNotificationWithArtwork($w, '🔈 Playlist '.$json->name, $playlist_artwork_path, 'Launch Artist Radio Playlist'); + } + if(getenv('add_created_radio_playlist_to_library') == 0) { + // do not add the playlist to the library + unfollowThePlaylist($w, $json->uri); + } else { + refreshLibrary($w); + } + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Playlist '.$json->name.' cannot be added', './images/warning.png', 'Error!'); + + return; + } + } else { + displayNotificationWithArtwork($w, 'Artist was not found with Spotify API', './images/warning.png', 'Error!'); + + return false; + } + + return true; +} + +/** + * createCompleteCollectionArtistPlaylist function. + * + * @param mixed $w + * @param mixed $artist_name + */ +function createCompleteCollectionArtistPlaylist($w, $artist_name, $artist_uri) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $userid = $settings->userid; + $country_code = $settings->country_code; + $is_public_playlists = $settings->is_public_playlists; + $is_autoplay_playlist = $settings->is_autoplay_playlist; + $use_artworks = $settings->use_artworks; + $output_application = $settings->output_application; + + $public = false; + if ($is_public_playlists) { + $public = true; + } + + $newplaylisttracks = array(); + // call to web api, if it fails, + // it displays an error in main window + $albums = getTheArtistAlbums($w, $artist_uri, $country_code, true, false); + + foreach ($albums as $album) { + // call to web api, if it fails, + // it displays an error in main window + $tracks = getTheAlbumFullTracks($w, $album->uri, true); + foreach ($tracks as $track) { + $tmp = explode(':', $track->uri); + $newplaylisttracks[] = $tmp[2]; + } + } + + if (count($newplaylisttracks) > 0) { + try { + $api = getSpotifyWebAPI($w); + $json = $api->createPlaylist(array( + 'name' => 'CC for '.escapeQuery($artist_name), + 'public' => $public, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(createCompleteCollectionArtistPlaylist): Complete Collection '.$artist_name.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + $ret = addTracksToPlaylist($w, $newplaylisttracks, $json->uri, $json->name, false, false); + if (is_numeric($ret) && $ret > 0) { + if ($is_autoplay_playlist) { + sleep(2); + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $json->uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$json->uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $json->uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addPlaylistToPlayQueue($w, $json->uri, $json->name); + $playlist_artwork_path = getPlaylistArtwork($w, $json->uri, true, false, $use_artworks); + displayNotificationWithArtwork($w, '🔈 Playlist '.$json->name, $playlist_artwork_path, 'Launch Complete Collection Playlist'); + } + refreshLibrary($w); + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Playlist '.$json->name.' cannot be added', './images/warning.png', 'Error!'); + + return; + } + } else { + displayNotificationWithArtwork($w, 'No track was found for artist '.$artist_name, './images/warning.png', 'Error!'); + + return false; + } + + return true; +} + +/** + * createRadioSongPlaylistForCurrentTrack function. + * + * @param mixed $w + */ +function createRadioSongPlaylistForCurrentTrack($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + createRadioSongPlaylist($w, $results[0], $results[4], $results[1]); + } else { + displayNotificationWithArtwork($w, 'There is not track currently playing', './images/warning.png', 'Error!'); + } +} + +/** + * createRadioSongPlaylist function. + * + * @param mixed $w + * @param mixed $track_name + * @param mixed $track_uri + * @param mixed $artist_name + */ +function createRadioSongPlaylist($w, $track_name, $track_uri, $artist_name) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $radio_number_tracks = $settings->radio_number_tracks; + $userid = $settings->userid; + $country_code = $settings->country_code; + $is_public_playlists = $settings->is_public_playlists; + $is_autoplay_playlist = $settings->is_autoplay_playlist; + $use_artworks = $settings->use_artworks; + $output_application = $settings->output_application; + + $public = false; + if ($is_public_playlists) { + $public = true; + } + + $tmp = explode(':', $track_uri); + if (isset($tmp[1]) && $tmp[1] == 'local') { + // local track, look it up online + // spotify:local:The+D%c3%b8:On+My+Shoulders+-+Single:On+My+Shoulders:318 + // spotify:local:Damien+Rice:B-Sides:Woman+Like+a+Man+%28Live%2c+Unplugged%29:284 + + $query = 'track:'.urldecode($tmp[4]).' artist:'.urldecode($tmp[2]); + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + $track_uri = $track->uri; + } else { + logMsg("Error(createRadioSongPlaylist): Could not find track from uri: $track_uri"); + + return false; + } + } + + $tmp = explode(':', $track_uri); + try { + $api = getSpotifyWebAPI($w); + $recommendations = $api->getRecommendations(array( + 'seed_tracks' => array($tmp[2]), + 'market' => $country_code, + 'limit' => $radio_number_tracks, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg( 'Error(createRadioSongPlaylist): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + exit; + } + + $newplaylisttracks = array(); + foreach ($recommendations->tracks as $track) { + $newplaylisttracks[] = $track->id; + } + + if (count($newplaylisttracks) > 0) { + try { + $api = getSpotifyWebAPI($w); + $json = $api->createPlaylist(array( + 'name' => 'Song radio for '.escapeQuery($track_name).' by '.escapeQuery($artist_name), + 'public' => $public, + )); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(createPlaylist): radio song '.escapeQuery($track_name).' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + $ret = addTracksToPlaylist($w, $newplaylisttracks, $json->uri, $json->name, false, false); + if (is_numeric($ret) && $ret > 0) { + if ($is_autoplay_playlist) { + sleep(2); + + if ($output_application == 'MOPIDY') { + playUriWithMopidy($w, $json->uri); + } else if($output_application == 'APPLESCRIPT') { + exec("osascript -e 'tell application \"Spotify\" to play track \"$json->uri\"'"); + } else { + $device_id = getSpotifyConnectCurrentDeviceId($w); + if($device_id != '') { + playTrackSpotifyConnect($w, $device_id, '', $json->uri); + } else { + displayNotificationWithArtwork($w, 'No Spotify Connect device is available', './images/warning.png', 'Error!'); + return; + } + } + addPlaylistToPlayQueue($w, $json->uri, $json->name); + $playlist_artwork_path = getPlaylistArtwork($w, $json->uri, true, false, $use_artworks); + displayNotificationWithArtwork($w, '🔈 Playlist '.$json->name, $playlist_artwork_path, 'Launch Radio Playlist'); + } + if(getenv('add_created_radio_playlist_to_library') == 0) { + // do not add the playlist to the library + unfollowThePlaylist($w, $json->uri); + } else { + refreshLibrary($w); + } + + return; + } elseif (is_numeric($ret) && $ret == 0) { + displayNotificationWithArtwork($w, 'Playlist '.$json->name.' cannot be added', './images/warning.png', 'Error!'); + + return; + } + } else { + displayNotificationWithArtwork($w, 'Track was not found using Spotify API', './images/warning.png', 'Error!'); + + return false; + } + + return true; +} + +/** + * getThePlaylistTracks function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function getThePlaylistTracks($w, $playlist_uri) +{ + $tracks = array(); + + // Read settings from JSON + + $settings = getSettings($w); + + $country_code = $settings->country_code; + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $offsetGetUserPlaylistTracks = 0; + $limitGetUserPlaylistTracks = 100; + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylistTracks = $api->getPlaylistTracks($playlist_id, array( + 'fields' => array( + 'total', + 'items.track(id,is_playable,linked_from)', + 'items(is_local)', + ), + 'limit' => $limitGetUserPlaylistTracks, + 'offset' => $offsetGetUserPlaylistTracks, + 'market' => $country_code, + )); + + foreach ($userPlaylistTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + if (isset($track->is_playable) && $track->is_playable) { + if (isset($track->linked_from) && isset($track->linked_from->id)) { + $track->id = $track->linked_from->id; + } + $tracks[] = $track->id; + } + if (isset($item->is_local) && $item->is_local) { + $tracks[] = $track->id; + } + } + + $offsetGetUserPlaylistTracks += $limitGetUserPlaylistTracks; + } while ($offsetGetUserPlaylistTracks < $userPlaylistTracks->total); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getThePlaylistTracks): playlist uri '.$playlist_uri.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return array_filter($tracks); +} + +/** + * getTheAlbumTracks function. + * + * @param mixed $w + * @param mixed $album_uri + */ +function getTheAlbumTracks($w, $album_uri) +{ + $tracks = array(); + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $album_uri); + $offsetGetAlbumTracks = 0; + $limitGetAlbumTracks = 50; + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $albumTracks = $api->getAlbumTracks($tmp[2], array( + 'limit' => $limitGetAlbumTracks, + 'offset' => $offsetGetAlbumTracks, + )); + + foreach ($albumTracks->items as $track) { + $tracks[] = $track->id; + } + $offsetGetAlbumTracks += $limitGetAlbumTracks; + } while ($offsetGetAlbumTracks < $albumTracks->total); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getTheAlbumTracks): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return array_filter($tracks); +} + +/** + * getTheArtistAlbums function. + * + * @param mixed $w + * @param mixed $artist_uri + * @param mixed $country_code + * @param bool $actionMode (default: false) + * @param bool $all_type (default: true) + */ +function getTheArtistAlbums($w, $artist_uri, $country_code, $actionMode = false, $all_type = true) +{ + $album_ids = array(); + + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $artist_uri); + $offsetGetArtistAlbums = 0; + $limitGetArtistAlbums = 50; + + if ($all_type) { + $album_type = array( + 'album', + 'single', + 'compilation', + ); + } else { + $album_type = array( + 'album', + 'single', + ); + } + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userArtistAlbums = $api->getArtistAlbums($tmp[2], array( + 'album_type' => $album_type, + 'market' => $country_code, + 'limit' => $limitGetArtistAlbums, + 'offset' => $offsetGetArtistAlbums, + )); + + foreach ($userArtistAlbums->items as $album) { + $album_ids[] = $album->id; + } + + $offsetGetArtistAlbums += $limitGetArtistAlbums; + } while ($offsetGetArtistAlbums < $userArtistAlbums->total); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($actionMode == false) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getArtistAlbums returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } else { + logMsg( 'Error(getTheArtistAlbums): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + } + + $albums = array(); + + try { + // Note: max 20 Ids + $offset = 0; + do { + $output = array_slice($album_ids, $offset, 20); + $offset += 20; + + if (count($output)) { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $resultGetAlbums = $api->getAlbums($output); + foreach ($resultGetAlbums->albums as $album) { + $albums[] = $album; + } + } + } while (count($output) > 0); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getAlbums returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } + + return $albums; +} + +/** + * getTheAlbumFullTracks function. + * + * @param mixed $w + * @param mixed $album_uri + * @param bool $actionMode (default: true) + */ +function getTheAlbumFullTracks($w, $album_uri, $actionMode = false) +{ + $tracks = array(); + + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $album_uri); + $offsetGetAlbumTracks = 0; + $limitGetAlbumTracks = 50; + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $albumTracks = $api->getAlbumTracks($tmp[2], array( + 'limit' => $limitGetAlbumTracks, + 'offset' => $offsetGetAlbumTracks, + 'market' => $country_code, + )); + + foreach ($albumTracks->items as $track) { + $tracks[] = $track; + } + + $offsetGetAlbumTracks += $limitGetAlbumTracks; + } while ($offsetGetAlbumTracks < $albumTracks->total); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($actionMode == false) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getAlbumTracks returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } else { + logMsg( 'Error(getTheAlbumFullTracks): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + } + + return $tracks; +} + +/** + * getThePlaylistFullTracks function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function getThePlaylistFullTracks($w, $playlist_uri) +{ + $tracks = array(); + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $offsetGetUserPlaylistTracks = 0; + $limitGetUserPlaylistTracks = 100; + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylistTracks = $api->getPlaylistTracks($playlist_id, array( + 'fields' => array( + 'total', + 'items(added_at)', + 'items(is_local)', + 'items.track(is_playable,duration_ms,uri,popularity,name,linked_from)', + 'items.track.album(album_type,images,uri,name)', + 'items.track.artists(name,uri)', + ), + 'limit' => $limitGetUserPlaylistTracks, + 'offset' => $offsetGetUserPlaylistTracks, + )); + + foreach ($userPlaylistTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $tracks[] = $item->track; + } + + $offsetGetUserPlaylistTracks += $limitGetUserPlaylistTracks; + } while ($offsetGetUserPlaylistTracks < $userPlaylistTracks->total); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getThePlaylistFullTracks): playlist uri '.$playlist_uri.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return $tracks; +} + +/** + * getTheArtistFullTracks function. + * + * @param mixed $w + * @param mixed $artist_uri + * @param mixed $country_code + */ +function getTheArtistFullTracks($w, $artist_uri, $country_code) +{ + $tracks = array(); + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $artist_uri); + $artistTopTracks = $api->getArtistTopTracks($tmp[2], array( + 'country' => $country_code, + )); + + foreach ($artistTopTracks->tracks as $track) { + $tracks[] = $track; + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getTheArtistFullTracks): artist uri '.$artist_uri.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + return $tracks; +} + +/** + * getTheFullTrack function. + * + * @param mixed $w + * @param mixed $track_uri + * @param mixed $country_code + */ +function getTheFullTrack($w, $track_uri, $country_code) +{ + try { + $tmp = explode(':', $track_uri); + + if (isset($tmp[1]) && $tmp[1] == 'local') { + // local track, look it up online + // spotify:local:The+D%c3%b8:On+My+Shoulders+-+Single:On+My+Shoulders:318 + // spotify:local:Damien+Rice:B-Sides:Woman+Like+a+Man+%28Live%2c+Unplugged%29:284 + + $query = 'track:'.urldecode($tmp[4]).' artist:'.urldecode($tmp[2]); + $results = searchWebApi($w, $country_code, $query, 'track', 1); + + if (count($results) > 0) { + // only one track returned + $track = $results[0]; + + return $track; + } else { + logMsg("Error(getTheFullTrack): Could not find track from uri: $track_uri"); + + return false; + } + } + $api = getSpotifyWebAPI($w); + $track = $api->getTrack($tmp[2]); + + return $track; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg( 'Error(getTheFullTrack): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + } + + return false; +} + +/** + * getTheArtistRelatedArtists function. + * + * @param mixed $w + * @param mixed $artist_uri + */ +function getTheArtistRelatedArtists($w, $artist_uri) +{ + $relateds = array(); + + try { + $api = getSpotifyWebAPI($w); + $tmp = explode(':', $artist_uri); + + $relatedArtists = $api->getArtistRelatedArtists($tmp[2]); + + foreach ($relatedArtists->artists as $related) { + $relateds[] = $related; + } + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getArtistRelatedArtists returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } + + return $relateds; +} + +/** + * getTheNewReleases function. + * + * @param mixed $w + * @param mixed $country_code + * @param mixed $max_results + */ +function getTheNewReleases($w, $country_code, $max_results = 50) +{ + $album_ids = array(); + + try { + $api = getSpotifyWebAPI($w); + $offsetGetNewReleases = 0; + $limitGetNewReleases = 50; + do { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $newReleasesAlbums = $api->getNewReleases(array( + 'country' => $country_code, + 'limit' => $limitGetNewReleases, + 'offset' => $offsetGetNewReleases, + )); + + foreach ($newReleasesAlbums->albums->items as $album) { + $album_ids[] = $album->id; + } + + $offsetGetNewReleases += $limitGetNewReleases; + } while ($offsetGetNewReleases < $max_results); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getNewReleases returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } + + $albums = array(); + + try { + // Note: max 20 Ids + $offset = 0; + do { + $output = array_slice($album_ids, $offset, 20); + $offset += 20; + + if (count($output)) { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $resultGetAlbums = $api->getAlbums($output); + foreach ($resultGetAlbums->albums as $album) { + $albums[] = $album; + } + } + } while (count($output) > 0); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + $w2 = new Workflows('com.vdesabou.spotify.mini.player'); + $w2->result(null, '', 'Error: Spotify WEB API getNewReleases from getNewReleases returned error '.$e->getMessage(), 'Try again or report to author', './images/warning.png', 'no', null, ''); + echo $w2->toxml(); + exit; + } + + return $albums; +} + +/** + * computeTime function. + */ +function computeTime() +{ + list($msec, $sec) = explode(' ', microtime()); + + return (float) $sec + (float) $msec; +} + +/** + * truncateStr function. + * + * @param mixed $input + * @param mixed $length + */ +function truncateStr($input, $length) +{ + // only truncate if input is actually longer than $length + if (strlen($input) > $length) { + // check if there are any spaces at all and if the last one is within + // the given length if so truncate at space else truncate at length. + if (strrchr($input, ' ') && strrchr($input, ' ') < $length) { + return substr($input, 0, strrpos(substr($input, 0, $length), ' ')).'…'; + } else { + return substr($input, 0, $length).'…'; + } + } else { + return $input; + } +} + +/** + * getPlaylistsForTrack function. + * + * @param mixed $db + * @param mixed $track_uri + */ +function getPlaylistsForTrack($db, $track_uri) +{ + $playlistsfortrack = ''; + $getPlaylistsForTrack = 'select distinct playlist_name from tracks where uri=:uri'; + try { + $stmt = $db->prepare($getPlaylistsForTrack); + $stmt->bindValue(':uri', ''.$track_uri.''); + $stmt->execute(); + + $noresult = true; + while ($playlist = $stmt->fetch()) { + if ($noresult == true) { + if ($playlist[0] == '') { + $playlistsfortrack = $playlistsfortrack.' ● ♫ : '.'Your Music'; + } else { + $playlistsfortrack = $playlistsfortrack.' ● ♫ : '.truncateStr($playlist[0], 30); + } + } else { + if ($playlist[0] == '') { + $playlistsfortrack = $playlistsfortrack.' ○ '.'Your Music'; + } else { + $playlistsfortrack = $playlistsfortrack.' ○ '.truncateStr($playlist[0], 30); + } + } + $noresult = false; + } + } catch (PDOException $e) { + return ''; + } + + return $playlistsfortrack; +} + +/** + * getNumberOfTracksForAlbum function. + * + * @param mixed $db + * @param mixed $album_uri + */ +function getNumberOfTracksForAlbum($db, $album_uri, $yourmusiconly = false) +{ + if ($yourmusiconly == false) { + $getNumberOfTracksForAlbum = 'select count(distinct track_name) from tracks where album_uri=:album_uri'; + } else { + $getNumberOfTracksForAlbum = 'select count(distinct track_name) from tracks where yourmusic=1 and album_uri=:album_uri'; + } + try { + $stmt = $db->prepare($getNumberOfTracksForAlbum); + $stmt->bindValue(':album_uri', ''.$album_uri.''); + $stmt->execute(); + $nb = $stmt->fetch(); + } catch (PDOException $e) { + return 0; + } + + return $nb[0]; +} + +/** + * getNumberOfTracksForArtist function. + * + * @param mixed $db + * @param mixed $artist_name + */ +function getNumberOfTracksForArtist($db, $artist_name, $yourmusiconly = false) +{ + if ($yourmusiconly == false) { + $getNumberOfTracksForArtist = 'select count(distinct track_name) from tracks where artist_name=:artist_name'; + } else { + $getNumberOfTracksForArtist = 'select count(distinct track_name) from tracks where yourmusic=1 and artist_name=:artist_name'; + } + + try { + $stmt = $db->prepare($getNumberOfTracksForArtist); + $stmt->bindValue(':artist_name', ''.$artist_name.''); + $stmt->execute(); + $nb = $stmt->fetch(); + } catch (PDOException $e) { + return 0; + } + + return $nb[0]; +} + +/** + * escapeQuery function. + * + * @param mixed $text + */ +function escapeQuery($text) +{ + $text = str_replace("'", '’', $text); + $text = str_replace('"', '', $text); + $text = str_replace(''', '’', $text); + $text = str_replace('`', '’', $text); + $text = str_replace('&', 'and', $text); + $text = str_replace('&', 'and', $text); + $text = str_replace('\\', ' ', $text); + $text = str_replace('$', '\$', $text); + + if (startswith($text, '’')) { + $text = ltrim($text, '’'); + } + + return $text; +} + +/** + * checkIfResultAlreadyThere function. + * + * @param mixed $results + * @param mixed $title + */ +function checkIfResultAlreadyThere($results, $title) +{ + foreach ($results as $result) { + if ($result['title']) { + if (strtolower($result['title']) == strtolower($title)) { + return true; + } + } + } + + return false; +} + +/** + * checkIfDuplicate function. + * + * @param mixed $track_ids + * @param mixed $id + */ +function checkIfDuplicate($track_ids, $id) +{ + foreach ($track_ids as $track_id) { + if ($track_id == $id) { + return true; + } + } + + return false; +} + +/** + * displayNotificationWithArtwork function. + * + * @param mixed $w + * @param mixed $subtitle + * @param mixed $artwork + * @param string $title (default: 'Spotify Mini Player') + */ +function displayNotificationWithArtwork($w, $subtitle, $artwork, $title = 'Spotify Mini Player') +{ + + // Read settings from JSON + + $settings = getSettings($w); + $use_growl = $settings->use_growl; + + if (!$use_growl) { + $theme_color = $settings->theme_color; + if (!is_dir('./App/'.$theme_color.'/Spotify Mini Player.app') || (is_dir('./App/'.$theme_color.'/Spotify Mini Player.app') && filesize('./App/'.$theme_color.'/Spotify Mini Player.app') == 0)) { + // reset to default + updateSetting($w, 'theme_color', 'green'); + $theme_color = $settings->theme_color; + } + if ($artwork != '' && file_exists($artwork)) { + copy($artwork, '/tmp/tmp_' . exec("whoami") ); + } + + //exec("./src/alerter.ksh '".$title."' '".$theme_color."' '".$subtitle."' '".getAlfredName()."' 2>&1 & "); + exec("./terminal-notifier.app/Contents/MacOS/terminal-notifier -title '".$title."' -sender 'com.spotify.miniplayer.".$theme_color."' -appIcon '/tmp/tmp' -message '".$subtitle."'"); + } else { + exec('./src/growl_notification.ksh -t "'.$title.'" -s "'.$subtitle.'" >> "'.$w->cache().'/action.log" 2>&1 & '); + } +} + +/** + * displayNotificationForCurrentTrack function. + * + * @param mixed $w + */ +function displayNotificationForCurrentTrack($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $is_display_rating = $settings->is_display_rating; + $use_artworks = $settings->use_artworks; + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + + $tmp = explode(':', $results[4]); + + if (isset($tmp[1]) && $tmp[1] == 'ad') { + return; + } + + // download artwork for current track view + $album_artwork_path = getTrackOrAlbumArtwork($w, $results[4], true, false, false, $use_artworks); + $artist_uri = getArtistUriFromTrack($w, $results[4]); + if ($artist_uri != false) { + $artist_artwork_path = getArtistArtwork($w, $artist_uri, $results[1], true, false, false, $use_artworks); + } + if (isset($results[0]) && $results[0] != '') { + $popularity = ''; + if($is_display_rating) { + $popularity = floatToStars($results[6]/100); + } + displayNotificationWithArtwork($w, '🔈 '.escapeQuery($results[0]).' by '.escapeQuery($results[1]).' in album '.escapeQuery($results[2]), $album_artwork_path, 'Now Playing '.$popularity.' ('.beautifyTime($results[5] / 1000).')'); + } + } +} + +/** + * displayLyricsForCurrentTrack function. + * + * @param mixed $w + */ +function displayLyricsForCurrentTrack($w) +{ + if (!$w->internet()) { + displayNotificationWithArtwork($w, 'No internet connection', './images/warning.png'); + + return; + } + + // Read settings from JSON + + $settings = getSettings($w); + + $output_application = $settings->output_application; + $always_display_lyrics_in_browser = $settings->always_display_lyrics_in_browser; + + + if ($output_application == 'MOPIDY') { + $retArr = array(getCurrentTrackInfoWithMopidy($w)); + } else if($output_application == 'APPLESCRIPT') { + // get info on current song + exec('./src/track_info.ksh 2>&1', $retArr, $retVal); + if ($retVal != 0) { + displayNotificationWithArtwork($w, 'AppleScript Exception: '.htmlspecialchars($retArr[0]).' use spot_mini_debug command', './images/warning.png', 'Error!'); + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' AppleScript Exception: '.htmlspecialchars($retArr[0])."\"'"); + + return; + } + } else { + $retArr = array(getCurrentTrackInfoWithSpotifyConnect($w)); + } + + if(count($retArr) == 0) { + return; + } + if (substr_count($retArr[count($retArr) - 1], '▹') > 0) { + $results = explode('▹', $retArr[count($retArr) - 1]); + + if($always_display_lyrics_in_browser == false) { + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini').' Lyrics▹'.$results[4].'∙'.escapeQuery($results[1]).'∙'.escapeQuery($results[0])."\"'"); + } else { + // display lyrics in default browser + list($lyrics_url, $lyrics) = getLyrics($w, escapeQuery($results[1]), escapeQuery($results[0])); + + if ($lyrics_url != false) { + exec('open '.$lyrics_url); + } else { + displayNotificationWithArtwork($w, 'No lyrics found!', './images/warning.png', 'Error!'); + } + } + + } else { + displayNotificationWithArtwork($w, 'There is not track currently playing', './images/warning.png', 'Error!'); + } +} + +/** + * downloadArtworks function. + * + * @param mixed $w + */ +function downloadArtworks($w) +{ + + // Read settings from JSON + + $settings = getSettings($w); + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + + if (!$use_artworks) { + return; + } + if (!$w->internet()) { + displayNotificationWithArtwork($w, 'Download Artworks, + No internet connection', './images/warning.png'); + + return; + } + + touch($w->data().'/download_artworks_in_progress'); + $w->write('Download Artworks▹'. 0 .'▹'. 0 .'▹'.time(), 'download_artworks_in_progress'); + $in_progress_data = $w->read('download_artworks_in_progress'); + $words = explode('▹', $in_progress_data); + + putenv('LANG=fr_FR.UTF-8'); + + ini_set('memory_limit', '512M'); + + // Get list of artworks to download from DB + + $nb_artworks_total = 0; + $nb_artworks = 0; + + $dbfile = $w->data().'/fetch_artworks.db'; + if (file_exists($dbfile)) { + try { + $dbartworks = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $dbartworks->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $getCount = 'select count(artist_name) from artists where already_fetched=0'; + $stmt = $dbartworks->prepare($getCount); + $stmt->execute(); + $count = $stmt->fetch(); + $nb_artworks_total += intval($count[0]); + + $getCount = 'select count(track_uri) from tracks where already_fetched=0'; + $stmt = $dbartworks->prepare($getCount); + $stmt->execute(); + $count = $stmt->fetch(); + $nb_artworks_total += intval($count[0]); + + $getCount = 'select count(album_uri) from albums where already_fetched=0'; + $stmt = $dbartworks->prepare($getCount); + $stmt->execute(); + $count = $stmt->fetch(); + $nb_artworks_total += intval($count[0]); + + if ($nb_artworks_total != 0) { + if(getenv('reduce_notifications') == 0) { + displayNotificationWithArtwork($w, 'Start downloading '.$nb_artworks_total.' artworks', './images/artworks.png', 'Artworks'); + } + + // artists + $getArtists = 'select artist_uri,artist_name from artists where already_fetched=0'; + $stmtGetArtists = $dbartworks->prepare($getArtists); + + $updateArtist = 'update artists set already_fetched=1 where artist_uri=:artist_uri'; + $stmtUpdateArtist = $dbartworks->prepare($updateArtist); + + // tracks + $getTracks = 'select track_uri from tracks where already_fetched=0'; + $stmtGetTracks = $dbartworks->prepare($getTracks); + + $updateTrack = 'update tracks set already_fetched=1 where track_uri=:track_uri'; + $stmtUpdateTrack = $dbartworks->prepare($updateTrack); + + // albums + $getAlbums = 'select album_uri from albums where already_fetched=0'; + $stmtGetAlbums = $dbartworks->prepare($getAlbums); + + $updateAlbum = 'update albums set already_fetched=1 where album_uri=:album_uri'; + $stmtUpdateAlbum = $dbartworks->prepare($updateAlbum); + + //// + // Artists + + $artists = $stmtGetArtists->execute(); + + while ($artist = $stmtGetArtists->fetch()) { + $ret = getArtistArtwork($w, $artist[0], $artist[1], true, false, true, $use_artworks); + + $stmtUpdateArtist->bindValue(':artist_uri', $artist[0]); + $stmtUpdateArtist->execute(); + + ++$nb_artworks; + if ($nb_artworks % 10 === 0) { + $w->write('Download Artworks▹'.$nb_artworks.'▹'.$nb_artworks_total.'▹'.$words[3], 'download_artworks_in_progress'); + } + } + + //// + // Tracks + + $tracks = $stmtGetTracks->execute(); + + while ($track = $stmtGetTracks->fetch()) { + $ret = getTrackOrAlbumArtwork($w, $track[0], true, false, true, $use_artworks); + + $stmtUpdateTrack->bindValue(':track_uri', $track[0]); + $stmtUpdateTrack->execute(); + + ++$nb_artworks; + if ($nb_artworks % 10 === 0) { + $w->write('Download Artworks▹'.$nb_artworks.'▹'.$nb_artworks_total.'▹'.$words[3], 'download_artworks_in_progress'); + } + } + + //// + // Albums + + $albums = $stmtGetAlbums->execute(); + + while ($album = $stmtGetAlbums->fetch()) { + $ret = getTrackOrAlbumArtwork($w, $album[0], true, false, true, $use_artworks); + + $stmtUpdateAlbum->bindValue(':album_uri', $album[0]); + $stmtUpdateAlbum->execute(); + + ++$nb_artworks; + if ($nb_artworks % 5 === 0) { + $w->write('Download Artworks▹'.$nb_artworks.'▹'.$nb_artworks_total.'▹'.$words[3], 'download_artworks_in_progress'); + } + } + } + } catch (PDOException $e) { + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + + return false; + } + } + deleteTheFile($w->data().'/download_artworks_in_progress'); + if ($nb_artworks_total != 0) { + if(getenv('reduce_notifications') == 0) { + $elapsed_time = time() - $words[3]; + displayNotificationWithArtwork($w, 'All artworks have been downloaded ('.$nb_artworks_total.' artworks) - took '.beautifyTime($elapsed_time, true), './images/artworks.png', 'Artworks'); + } + stathat_ez_count('AlfredSpotifyMiniPlayer', 'artworks', $nb_artworks_total); + } + + return true; +} + +/** + * getTrackOrAlbumArtwork function. + * + * @param mixed $w + * @param mixed $spotifyURL + * @param mixed $fetchIfNotPresent + * @param bool $useArtworks (default: true) + */ +function getTrackOrAlbumArtwork($w, $spotifyURL, $fetchIfNotPresent, $fetchLater = false, $isLaterFetch = false, $useArtworks = true, $forceFetch = false) +{ + $hrefs = explode(':', $spotifyURL); + $isAlbum = false; + if ($hrefs[1] == 'album') { + $isAlbum = true; + } + + if (!$useArtworks) { + if ($isAlbum) { + return './images/albums.png'; + } else { + return './images/tracks.png'; + } + } + + if (!file_exists($w->data().'/artwork')): + exec("mkdir '".$w->data()."/artwork'"); + endif; + + $currentArtwork = $w->data().'/artwork/'.hash('md5', $hrefs[2].'.png').'/'."$hrefs[2].png"; + $artwork = ''; + + if ($fetchLater == true) { + if (!is_file($currentArtwork)) { + return array( + false, + $currentArtwork, + ); + } else { + return array( + true, + $currentArtwork, + ); + } + // always return currentArtwork + return $currentArtwork; + } + + if (!is_file($currentArtwork) || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $hrefs[2] == 'fakeuri' || $forceFetch) { + if ($fetchIfNotPresent == true || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $forceFetch) { + if($forceFetch) { + $artwork = getArtworkURL($w, $hrefs[1], $hrefs[2], true); + } else { + $artwork = getArtworkURL($w, $hrefs[1], $hrefs[2]); + } + + + // if return 0, it is a 404 error, no need to fetch + if (!empty($artwork) || (is_numeric($artwork) && $artwork != 0)) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $hrefs[2].'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $hrefs[2].'.png')."'"); + endif; + $fp = fopen($currentArtwork, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$artwork", $options); + + if ($isLaterFetch == true) { + return true; + } else { + stathat_ez_count('AlfredSpotifyMiniPlayer', 'artworks', 1); + } + } else { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $hrefs[2].'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $hrefs[2].'.png')."'"); + endif; + + if ($isAlbum) { + copy('./images/albums.png', $currentArtwork); + } else { + copy('./images/tracks.png', $currentArtwork); + } + + return false; + } else { + if ($isAlbum) { + return './images/albums.png'; + } else { + return './images/tracks.png'; + } + } + } + } else { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $hrefs[2].'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $hrefs[2].'.png')."'"); + endif; + + if ($isAlbum) { + copy('./images/albums.png', $currentArtwork); + } else { + copy('./images/tracks.png', $currentArtwork); + } + + return false; + } else { + if ($isAlbum) { + return './images/albums.png'; + } else { + return './images/tracks.png'; + } + } + } + } else { + if (filesize($currentArtwork) == 0) { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $hrefs[2].'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $hrefs[2].'.png')."'"); + endif; + + if ($isAlbum) { + copy('./images/albums.png', $currentArtwork); + } else { + copy('./images/tracks.png', $currentArtwork); + } + + return false; + } else { + if ($isAlbum) { + return './images/albums.png'; + } else { + return './images/tracks.png'; + } + } + } + } + + if (is_numeric($artwork) && $artwork == 0) { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $hrefs[2].'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $hrefs[2].'.png')."'"); + endif; + + if ($isAlbum) { + copy('./images/albums.png', $currentArtwork); + } else { + copy('./images/tracks.png', $currentArtwork); + } + + return false; + } else { + if ($isAlbum) { + return './images/albums.png'; + } else { + return './images/tracks.png'; + } + } + } else { + return $currentArtwork; + } +} + +/** + * getPlaylistArtwork function. + * + * @param mixed $w + * @param mixed $playlist_uri + * @param mixed $fetchIfNotPresent + * @param bool $forceFetch (default: false) + * @param bool $useArtworks (default: true) + */ +function getPlaylistArtwork($w, $playlist_uri, $fetchIfNotPresent, $forceFetch = false, $useArtworks = true) +{ + if (!$useArtworks) { + return './images/playlists.png'; + } + + $tmp = explode(':', $playlist_uri); + if(isset($tmp[4])) { + $playlist_id = $tmp[4]; + } else { + $playlist_id = $tmp[2]; + } + $filename = ''.$playlist_id; + $artwork = ''; + + if (!file_exists($w->data().'/artwork')): + exec("mkdir '".$w->data()."/artwork'"); + endif; + + $currentArtwork = $w->data().'/artwork/'.hash('md5', $filename.'.png').'/'."$filename.png"; + + if (!is_file($currentArtwork) || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $forceFetch) { + if ($fetchIfNotPresent == true || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $forceFetch) { + $artwork = getPlaylistArtworkURL($w, $playlist_id); + // if return 0, it is a 404 error, no need to fetch + if (!empty($artwork) || (is_numeric($artwork) && $artwork != 0)) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $filename.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $filename.'.png')."'"); + endif; + $fp = fopen($currentArtwork, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + + $w->request("$artwork", $options); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'artworks', 1); + } else { + return './images/playlists.png'; + } + } else { + return './images/playlists.png'; + } + } else { + if (filesize($currentArtwork) == 0) { + return './images/playlists.png'; + } + } + + if (is_numeric($artwork) && $artwork == 0) { + return './images/playlists.png'; + } else { + return $currentArtwork; + } +} + +/** + * getCategoryArtwork function. + * + * @param mixed $w + * @param mixed $categoryId + * @param mixed $categoryURI + * @param mixed $fetchIfNotPresent + * @param bool $forceFetch (default: false) + * @param bool $useArtworks (default: true) + */ +function getCategoryArtwork($w, $categoryId, $categoryURI, $fetchIfNotPresent, $forceFetch = false, $useArtworks = true) +{ + if (!$useArtworks) { + return './images/browse.png'; + } + + if (!file_exists($w->data().'/artwork')): + exec("mkdir '".$w->data()."/artwork'"); + endif; + + $currentArtwork = $w->data().'/artwork/'.hash('md5', $categoryId.'.jpg').'/'."$categoryId.jpg"; + + if (!is_file($currentArtwork) || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $forceFetch) { + if ($fetchIfNotPresent == true || (is_file($currentArtwork) && filesize($currentArtwork) == 0) || $forceFetch) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $categoryId.'.jpg'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $categoryId.'.jpg')."'"); + endif; + $fp = fopen($currentArtwork, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + $w->request("$categoryURI", $options); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'artworks', 1); + } else { + return './images/browse.png'; + } + } else { + if (filesize($currentArtwork) == 0) { + return './images/browse.png'; + } + } + + return $currentArtwork; +} + +/** + * getArtistArtwork function. + * + * @param mixed $w + * @param mixed $artist_uri + * @param mixed $artist_name + * @param bool $fetchIfNotPresent (default: false) + * @param bool $fetchLater (default: false) + * @param bool $isLaterFetch (default: false) + * @param bool $useArtworks (default: true) + */ +function getArtistArtwork($w, $artist_uri, $artist_name, $fetchIfNotPresent = false, $fetchLater = false, $isLaterFetch = false, $useArtworks = true) +{ + if (!$useArtworks) { + return './images/artists.png'; + } + $parsedArtist = urlencode(escapeQuery($artist_name)); + + if (!file_exists($w->data().'/artwork')): + exec("mkdir '".$w->data()."/artwork'"); + endif; + + $currentArtwork = $w->data().'/artwork/'.hash('md5', $parsedArtist.'.png').'/'."$parsedArtist.png"; + if ($artist_uri == '') { + return './images/artists.png'; + } + + $tmp = explode(':', $artist_uri); + if (isset($tmp[2])) { + $artist_uri = $tmp[2]; + } + $artwork = ''; + + if ($fetchLater == true) { + if (!is_file($currentArtwork)) { + return array( + false, + $currentArtwork, + ); + } else { + return array( + true, + $currentArtwork, + ); + } + // always return currentArtwork + return $currentArtwork; + } + + if (!is_file($currentArtwork) || (is_file($currentArtwork) && filesize($currentArtwork) == 0)) { + if ($fetchIfNotPresent == true || (is_file($currentArtwork) && filesize($currentArtwork) == 0)) { + $artwork = getArtistArtworkURL($w, $artist_uri); + + // if return 0, it is a 404 error, no need to fetch + if (!empty($artwork) || (is_numeric($artwork) && $artwork != 0)) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $parsedArtist.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $parsedArtist.'.png')."'"); + endif; + $fp = fopen($currentArtwork, 'w+'); + $options = array( + CURLOPT_FILE => $fp, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 5, + ); + $w->request("$artwork", $options); + stathat_ez_count('AlfredSpotifyMiniPlayer', 'artworks', 1); + if ($isLaterFetch == true) { + return true; + } + } else { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $parsedArtist.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $parsedArtist.'.png')."'"); + endif; + copy('./images/artists.png', $currentArtwork); + + return false; + } else { + return './images/artists.png'; + } + } + } else { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $parsedArtist.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $parsedArtist.'.png')."'"); + endif; + copy('./images/artists.png', $currentArtwork); + + return false; + } else { + return './images/artists.png'; + } + } + } else { + if (filesize($currentArtwork) == 0) { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $parsedArtist.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $parsedArtist.'.png')."'"); + endif; + copy('./images/artists.png', $currentArtwork); + + return false; + } else { + return './images/artists.png'; + } + } + } + + if (is_numeric($artwork) && $artwork == 0) { + if ($isLaterFetch == true) { + if (!file_exists($w->data().'/artwork/'.hash('md5', $parsedArtist.'.png'))): + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $parsedArtist.'.png')."'"); + endif; + copy('./images/artists.png', $currentArtwork); + + return false; + } else { + return './images/artists.png'; + } + } else { + return $currentArtwork; + } +} + +/** + * getArtworkURL function. + * + * @param mixed $w + * @param mixed $type + * @param mixed $id + * @param boolean $highRes + */ +function getArtworkURL($w, $type, $id, $highRes = false) +{ + $url = ''; + + if (startswith($id, 'fake')) { + return $url; + } + + $retry = true; + $nb_retry = 0; + while ($retry) { + + if ($type == 'track') { + try { + $api = getSpotifyWebAPI($w); + $track = $api->getTrack($id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getCode() != 429) { + logMsg('Error(getArtworkURL track): (exception '.jTraceEx($e).')'); + } + + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return $url; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return $url; + } + } + if (isset($track->album) && isset($track->album->images)) { + + if(!$highRes) { + // 60 px + if (isset($track->album->images[2]) && isset($track->album->images[2]->url)) { + return $track->album->images[2]->url; + } + + // 300 px + if (isset($track->album->images[1]) && isset($track->album->images[1]->url)) { + return $track->album->images[1]->url; + } + + // 600 px + if (isset($track->album->images[0]) && isset($track->album->images[0]->url)) { + return $track->album->images[0]->url; + } + } else { + // 600 px + if (isset($track->album->images[0]) && isset($track->album->images[0]->url)) { + return $track->album->images[0]->url; + } + + // 300 px + if (isset($track->album->images[1]) && isset($track->album->images[1]->url)) { + return $track->album->images[1]->url; + } + } + + + } + } else { + try { + $api = getSpotifyWebAPI($w); + $album = $api->getAlbum($id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getCode() != 429) { + logMsg('Error(getArtworkURL album): (exception '.jTraceEx($e).')'); + } + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return $url; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return $url; + } + } + if (isset($album->images)) { + + if(!$highRes) { + // 60 px + if (isset($album->images[2]) && isset($album->images[2]->url)) { + return $album->images[2]->url; + } + + // 300 px + if (isset($album->images[1]) && isset($album->images[1]->url)) { + return $album->images[1]->url; + } + + // 600 px + if (isset($album->images[0]) && isset($album->images[0]->url)) { + return $album->images[0]->url; + } + } else { + // 600 px + if (isset($album->images[0]) && isset($album->images[0]->url)) { + return $album->images[0]->url; + } + + // 300 px + if (isset($album->images[1]) && isset($album->images[1]->url)) { + return $album->images[1]->url; + } + } + + + } + } + } + + return $url; +} + +/** + * getPlaylistArtworkURL function. + * + * @param mixed $w + * @param mixed $playlist_uri + */ +function getPlaylistArtworkURL($w, $playlist_uri) +{ + $url = ''; + + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $playlist = $api->getPlaylist($playlist_uri, array( + 'fields' => array( + 'images', + ), + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getCode() != 429) { + logMsg('Error(getPlaylistArtworkURL): (exception '.jTraceEx($e).')'); + } + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return $url; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return $url; + } + + return $url; + } + if (isset($playlist->images)) { + + // 60 px + if (isset($playlist->images[2]) && isset($playlist->images[2]->url)) { + return $playlist->images[2]->url; + } + + // 300 px + if (isset($playlist->images[1]) && isset($playlist->images[1]->url)) { + return $playlist->images[1]->url; + } + + // 600 px + if (isset($playlist->images[0]) && isset($playlist->images[0]->url)) { + return $playlist->images[0]->url; + } + } + } + + return $url; +} + +/** + * getArtistArtworkURL function. + * + * @param mixed $w + * @param mixed $artist_id + */ +function getArtistArtworkURL($w, $artist_id) +{ + $url = ''; + if (startswith($artist_id, 'fake')) { + return $url; + } + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + $api = getSpotifyWebAPI($w); + $artist = $api->getArtist($artist_id); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + if ($e->getCode() != 429) { + logMsg('Error(getArtistArtworkURL): (exception '.jTraceEx($e).')'); + } + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + $retry = false; + + return $url; + } + ++$nb_retry; + sleep(5); + } else { + $retry = false; + + return $url; + } + + return $url; + } + + if (isset($artist->images)) { + + // 60 px + if (isset($artist->images[2]) && isset($artist->images[2]->url)) { + return $artist->images[2]->url; + } + + // 300 px + if (isset($artist->images[1]) && isset($artist->images[1]->url)) { + return $artist->images[1]->url; + } + + // 600 px + if (isset($artist->images[0]) && isset($artist->images[0]->url)) { + return $artist->images[0]->url; + } + } + } + return $url; +} + +/** + * updateLibrary function. + * + * @param mixed $w + */ +function updateLibrary($w) +{ + touch($w->data().'/update_library_in_progress'); + $w->write('InitLibrary▹'. 0 .'▹'. 0 .'▹'.time().'▹'.'starting', 'update_library_in_progress'); + $in_progress_data = $w->read('update_library_in_progress'); + + // Read settings from JSON + + $settings = getSettings($w); + $country_code = $settings->country_code; + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + + $words = explode('▹', $in_progress_data); + + // move legacy artwork files in hash directories if needed + + if (file_exists($w->data().'/artwork')) { + $folder = $w->data().'/artwork'; + if ($handle = opendir($folder)) { + while (false !== ($file = readdir($handle))) { + if (stristr($file, '.png')) { + exec("mkdir '".$w->data().'/artwork/'.hash('md5', $file)."'"); + rename($folder.'/'.$file, $folder.'/'.hash('md5', $file).'/'.$file); + } + } + closedir($handle); + } + } + + putenv('LANG=fr_FR.UTF-8'); + ini_set('memory_limit', '512M'); + if (file_exists($w->data().'/library.db')) { + rename($w->data().'/library.db', $w->data().'/library_old.db'); + } + deleteTheFile($w->data().'/library_new.db'); + $dbfile = $w->data().'/library_new.db'; + touch($dbfile); + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $db->query('PRAGMA synchronous = OFF'); + $db->query('PRAGMA journal_mode = OFF'); + $db->query('PRAGMA temp_store = MEMORY'); + $db->query('PRAGMA count_changes = OFF'); + $db->query('PRAGMA PAGE_SIZE = 4096'); + $db->query('PRAGMA default_cache_size=700000'); + $db->query('PRAGMA cache_size=700000'); + $db->query('PRAGMA compile_options'); + // Problems with search on russian language #210 + // thanks to https://blog.amartynov.ru/php-sqlite-case-insensitive-like-utf8/ + $db->sqliteCreateFunction('like', "lexa_ci_utf8_like", 2); + } catch (PDOException $e) { + logMsg( 'Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return false; + } + + if ($use_artworks) { + // db for fetch artworks + // kill previous process if running + $pid = exec("ps -efx | grep \"php\" | egrep \"DOWNLOAD_ARTWORKS\" | grep -v grep | awk '{print $2}'"); + if ($pid != '') { + $ret = exec("kill -9 \"$pid\""); + } + $dbfile = $w->data().'/fetch_artworks.db'; + if (file_exists($dbfile)) { + deleteTheFile($dbfile); + touch($dbfile); + } + if (file_exists($w->data().'/download_artworks_in_progress')) { + deleteTheFile($w->data().'/download_artworks_in_progress'); + } + try { + $dbartworks = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $dbartworks->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + // DB artowrks + try { + $dbartworks->exec('create table artists (artist_uri text PRIMARY KEY NOT NULL, artist_name text, already_fetched boolean)'); + $dbartworks->exec('create table tracks (track_uri text PRIMARY KEY NOT NULL, already_fetched boolean)'); + $dbartworks->exec('create table albums (album_uri text PRIMARY KEY NOT NULL, already_fetched boolean)'); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + } + + // get the total number of tracks + $nb_tracktotal = 0; + $nb_skipped = 0; + $savedListPlaylist = array(); + $savedListAlbums = array(); + try { + $api = getSpotifyWebAPI($w); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getPlaylists): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + $offsetGetUserPlaylists = 0; + $limitGetUserPlaylists = 50; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylists = $api->getUserPlaylists(urlencode($userid), array( + 'limit' => $limitGetUserPlaylists, + 'offset' => $offsetGetUserPlaylists, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getUserPlaylists): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userPlaylists->items as $playlist) { + $tracks = $playlist->tracks; + $nb_tracktotal += $tracks->total; + if ($playlist->name != '') { + $savedListPlaylist[] = $playlist; + } + } + $offsetGetUserPlaylists += $limitGetUserPlaylists; + } while ($offsetGetUserPlaylists < $userPlaylists->total); + + $savedMySavedTracks = array(); + $offsetGetMySavedTracks = 0; + $limitGetMySavedTracks = 50; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userMySavedTracks = $api->getMySavedTracks(array( + 'limit' => $limitGetMySavedTracks, + 'offset' => $offsetGetMySavedTracks, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getMySavedTracks): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userMySavedTracks->items as $track) { + $savedMySavedTracks[] = $track; + $nb_tracktotal += 1; + } + + $offsetGetMySavedTracks += $limitGetMySavedTracks; + } while ($offsetGetMySavedTracks < $userMySavedTracks->total); + + $savedListAlbums = array(); + $offsetGetMySavedAlbums = 0; + $limitGetMySavedAlbums = 50; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userMySavedAlbums = $api->getMySavedAlbums(array( + 'limit' => $limitGetMySavedAlbums, + 'offset' => $offsetGetMySavedAlbums, + 'market' => $country_code, + )); + logMsg('Error(getMySavedAlbums): (got '. print_r($userMySavedAlbums).')'); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getMySavedAlbums): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userMySavedAlbums->items as $album) { + $tracks = $album->tracks; + $nb_tracktotal += $tracks->total; + if ($album->name != '') { + $savedListAlbums[] = $album; + logMsg('Error(savedListAlbums): (adding '.$album.')'); + } + } + + $offsetGetMySavedAlbums += $limitGetMySavedAlbums; + } while ($offsetGetMySavedAlbums < $userMySavedAlbums->total); + + // Handle playlists + $w->write('Create Library▹0▹'.$nb_tracktotal.'▹'.$words[3].'▹'.'starting', 'update_library_in_progress'); + + $nb_track = 0; + + try { + $db->exec('create table tracks (yourmusic boolean, popularity int, uri text, album_uri text, artist_uri text, track_name text, album_name text, artist_name text, album_type text, track_artwork_path text, artist_artwork_path text, album_artwork_path text, playlist_name text, playlist_uri text, playable boolean, added_at text, duration text, nb_times_played int, local_track boolean)'); + $db->exec('CREATE INDEX IndexPlaylistUri ON tracks (playlist_uri)'); + $db->exec('CREATE INDEX IndexArtistName ON tracks (artist_name)'); + $db->exec('CREATE INDEX IndexAlbumName ON tracks (album_name)'); + $db->exec('create table counters (all_tracks int, yourmusic_tracks int, all_artists int, yourmusic_artists int, all_albums int, yourmusic_albums int, playlists int)'); + $db->exec('create table playlists (uri text PRIMARY KEY NOT NULL, name text, nb_tracks int, author text, username text, playlist_artwork_path text, ownedbyuser boolean, nb_playable_tracks int, duration_playlist text, nb_times_played int, collaborative boolean, public boolean)'); + + $insertPlaylist = 'insert into playlists values (:uri,:name,:nb_tracks,:owner,:username,:playlist_artwork_path,:ownedbyuser,:nb_playable_tracks,:duration_playlist,:nb_times_played,:collaborative,:public)'; + $stmtPlaylist = $db->prepare($insertPlaylist); + + $insertTrack = 'insert into tracks values (:yourmusic,:popularity,:uri,:album_uri,:artist_uri,:track_name,:album_name,:artist_name,:album_type,:track_artwork_path,:artist_artwork_path,:album_artwork_path,:playlist_name,:playlist_uri,:playable,:added_at,:duration,:nb_times_played,:local_track)'; + $stmtTrack = $db->prepare($insertTrack); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + + if ($use_artworks) { + try { + // artworks + $insertArtistArtwork = 'insert or ignore into artists values (:artist_uri, :artist_name,:already_fetched)'; + $stmtArtistArtwork = $dbartworks->prepare($insertArtistArtwork); + + $insertTrackArtwork = 'insert or ignore into tracks values (:track_uri,:already_fetched)'; + $stmtTrackArtwork = $dbartworks->prepare($insertTrackArtwork); + + $insertAlbumArtwork = 'insert or ignore into albums values (:album_uri,:already_fetched)'; + $stmtAlbumArtwork = $dbartworks->prepare($insertAlbumArtwork); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + $artworksToDownload = false; + } + + foreach ($savedListPlaylist as $playlist) { + $duration_playlist = 0; + $nb_track_playlist = 0; + $tracks = $playlist->tracks; + $owner = $playlist->owner; + + $playlist_artwork_path = getPlaylistArtwork($w, $playlist->uri, true, true, $use_artworks); + + if ('-'.$owner->id.'-' == '-'.$userid.'-') { + $ownedbyuser = 1; + } else { + $ownedbyuser = 0; + } + + try { + $api = getSpotifyWebAPI($w); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getPlaylistTracks): playlist id '.$playlist->id.' (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + $offsetGetUserPlaylistTracks = 0; + $limitGetUserPlaylistTracks = 100; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylistTracks = $api->getPlaylistTracks($playlist->id, array( + 'fields' => array( + 'total', + 'items(added_at)', + 'items(is_local)', + 'items.track(is_playable,duration_ms,uri,popularity,name,linked_from)', + 'items.track.album(album_type,images,uri,name)', + 'items.track.artists(name,uri)', + ), + 'limit' => $limitGetUserPlaylistTracks, + 'offset' => $offsetGetUserPlaylistTracks, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getUserPlaylists): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userPlaylistTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + $duration_playlist += $track->duration_ms; + + try { + $stmtTrack->bindValue(':yourmusic', 0); + $stmtTrack->bindValue(':popularity', $track->popularity); + $stmtTrack->bindValue(':uri', $track->uri); + $stmtTrack->bindValue(':album_uri', $album->uri); + $stmtTrack->bindValue(':artist_uri', $artist->uri); + $stmtTrack->bindValue(':track_name', escapeQuery($track->name)); + $stmtTrack->bindValue(':album_name', escapeQuery($album->name)); + $stmtTrack->bindValue(':artist_name', escapeQuery($artist->name)); + $stmtTrack->bindValue(':album_type', $album->album_type); + $stmtTrack->bindValue(':track_artwork_path', $track_artwork_path); + $stmtTrack->bindValue(':artist_artwork_path', $artist_artwork_path); + $stmtTrack->bindValue(':album_artwork_path', $album_artwork_path); + $stmtTrack->bindValue(':playlist_name', escapeQuery($playlist->name)); + $stmtTrack->bindValue(':playlist_uri', $playlist->uri); + $stmtTrack->bindValue(':playable', $playable); + $stmtTrack->bindValue(':added_at', $item->added_at); + $stmtTrack->bindValue(':duration', beautifyTime($track->duration_ms / 1000)); + $stmtTrack->bindValue(':nb_times_played', 0); + $stmtTrack->bindValue(':local_track', $local_track); + $stmtTrack->execute(); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + ++$nb_track; + ++$nb_track_playlist; + if ($nb_track % 10 === 0) { + $w->write('Create Library▹'.$nb_track.'▹'.$nb_tracktotal.'▹'.$words[3].'▹'.escapeQuery($playlist->name), 'update_library_in_progress'); + } + } + + $offsetGetUserPlaylistTracks += $limitGetUserPlaylistTracks; + } while ($offsetGetUserPlaylistTracks < $userPlaylistTracks->total); + + try { + $stmtPlaylist->bindValue(':uri', $playlist->uri); + $stmtPlaylist->bindValue(':name', escapeQuery($playlist->name)); + $stmtPlaylist->bindValue(':nb_tracks', $playlist->tracks->total); + $stmtPlaylist->bindValue(':owner', $owner->id); + $stmtPlaylist->bindValue(':username', $owner->id); + $stmtPlaylist->bindValue(':playlist_artwork_path', $playlist_artwork_path); + $stmtPlaylist->bindValue(':ownedbyuser', $ownedbyuser); + $stmtPlaylist->bindValue(':nb_playable_tracks', $nb_track_playlist); + $stmtPlaylist->bindValue(':duration_playlist', beautifyTime($duration_playlist / 1000, true)); + $stmtPlaylist->bindValue(':nb_times_played', 0); + $stmtPlaylist->bindValue(':collaborative', $playlist->collaborative); + $stmtPlaylist->bindValue(':public', $playlist->public); + $stmtPlaylist->execute(); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + } + + // Handle Your Music + foreach ($savedMySavedTracks as $track) { + $track = $track->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + try { + $stmtTrack->bindValue(':yourmusic', 1); + $stmtTrack->bindValue(':popularity', $track->popularity); + $stmtTrack->bindValue(':uri', $track->uri); + $stmtTrack->bindValue(':album_uri', $album->uri); + $stmtTrack->bindValue(':artist_uri', $artist->uri); + $stmtTrack->bindValue(':track_name', escapeQuery($track->name)); + $stmtTrack->bindValue(':album_name', escapeQuery($album->name)); + $stmtTrack->bindValue(':artist_name', escapeQuery($artist->name)); + $stmtTrack->bindValue(':album_type', $album->album_type); + $stmtTrack->bindValue(':track_artwork_path', $track_artwork_path); + $stmtTrack->bindValue(':artist_artwork_path', $artist_artwork_path); + $stmtTrack->bindValue(':album_artwork_path', $album_artwork_path); + $stmtTrack->bindValue(':playlist_name', ''); + $stmtTrack->bindValue(':playlist_uri', ''); + $stmtTrack->bindValue(':playable', $playable); + $stmtTrack->bindValue(':added_at', $item->added_at); + $stmtTrack->bindValue(':duration', beautifyTime($track->duration_ms / 1000)); + $stmtTrack->bindValue(':nb_times_played', 0); + $stmtTrack->bindValue(':local_track', $local_track); + $stmtTrack->execute(); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + + + foreach ($savedListAlbums as $album) { + + logMsg('Error(savedListAlbums): (looping '.$album.')'); + foreach ($album->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + } + } + + ++$nb_track; + if ($nb_track % 10 === 0) { + $w->write('Create Library▹'.$nb_track.'▹'.$nb_tracktotal.'▹'.$words[3].'▹'.'Your Music', 'update_library_in_progress'); + } + } + + // update counters + try { + $getCount = 'select count(distinct uri) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_tracks = $stmt->fetch(); + + $getCount = 'select count(distinct uri) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_tracks = $stmt->fetch(); + + $getCount = 'select count(distinct artist_name) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_artists = $stmt->fetch(); + + $getCount = 'select count(distinct artist_name) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_artists = $stmt->fetch(); + + $getCount = 'select count(distinct album_name) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_albums = $stmt->fetch(); + + $getCount = 'select count(distinct album_name) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_albums = $stmt->fetch(); + + $getCount = 'select count(*) from playlists'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $playlists_count = $stmt->fetch(); + + $insertCounter = 'insert into counters values (:all_tracks,:yourmusic_tracks,:all_artists,:yourmusic_artists,:all_albums,:yourmusic_albums,:playlists)'; + $stmt = $db->prepare($insertCounter); + + $stmt->bindValue(':all_tracks', $all_tracks[0]); + $stmt->bindValue(':yourmusic_tracks', $yourmusic_tracks[0]); + $stmt->bindValue(':all_artists', $all_artists[0]); + $stmt->bindValue(':yourmusic_artists', $yourmusic_artists[0]); + $stmt->bindValue(':all_albums', $all_albums[0]); + $stmt->bindValue(':yourmusic_albums', $yourmusic_albums[0]); + $stmt->bindValue(':playlists', $playlists_count[0]); + $stmt->execute(); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + + $elapsed_time = time() - $words[3]; + if ($nb_skipped == 0) { + displayNotificationWithArtwork($w, ' '.$nb_track.' tracks - took '.beautifyTime($elapsed_time, true), './images/recreate.png', 'Library (re-)created'); + } else { + displayNotificationWithArtwork($w, ' '.$nb_track.' tracks / '.$nb_skipped.' skipped - took '.beautifyTime($elapsed_time, true), './images/recreate.png', 'Library (re-)created'); + } + + if (file_exists($w->data().'/library_old.db')) { + deleteTheFile($w->data().'/library_old.db'); + } + rename($w->data().'/library_new.db', $w->data().'/library.db'); + + // remove legacy spotify app if needed + if (file_exists(exec('printf $HOME').'/Spotify/spotify-app-miniplayer')) { + exec('rm -rf '.exec('printf $HOME').'/Spotify/spotify-app-miniplayer'); + } + // remove legacy settings.db if needed + if (file_exists($w->data().'/settings.db')) { + deleteTheFile($w->data().'/settings.db'); + } + + // Download artworks in background + if ($use_artworks) { + if ($artworksToDownload == true) { + exec('php -f ./src/action.php -- "" "DOWNLOAD_ARTWORKS" "DOWNLOAD_ARTWORKS" >> "'.$w->cache().'/action.log" 2>&1 & '); + } + } + deleteTheFile($w->data().'/update_library_in_progress'); + + // in case of new user, force creation of links and current_user.json + getCurrentUser($w); +} + +/** + * refreshLibrary function. + * + * @param mixed $w + */ +function refreshLibrary($w) +{ + if (!file_exists($w->data().'/library.db')) { + displayNotificationWithArtwork($w, 'Refresh library called while library does not exist', './images/warning.png'); + + return; + } + + touch($w->data().'/update_library_in_progress'); + $w->write('InitRefreshLibrary▹'. 0 .'▹'. 0 .'▹'.time().'▹'.'starting', 'update_library_in_progress'); + + $in_progress_data = $w->read('update_library_in_progress'); + + // Read settings from JSON + + $settings = getSettings($w); + + $country_code = $settings->country_code; + $userid = $settings->userid; + $use_artworks = $settings->use_artworks; + + $words = explode('▹', $in_progress_data); + + putenv('LANG=fr_FR.UTF-8'); + + ini_set('memory_limit', '512M'); + + $nb_playlist = 0; + + if ($use_artworks) { + // db for fetch artworks + $fetch_artworks_existed = true; + $dbfile = $w->data().'/fetch_artworks.db'; + if (!file_exists($dbfile)) { + touch($dbfile); + $fetch_artworks_existed = false; + } + // kill previous process if running + $pid = exec("ps -efx | grep \"php\" | egrep \"DOWNLOAD_ARTWORKS\" | grep -v grep | awk '{print $2}'"); + if ($pid != '') { + $ret = exec("kill -9 \"$pid\""); + } + if (file_exists($w->data().'/download_artworks_in_progress')) { + deleteTheFile($w->data().'/download_artworks_in_progress'); + } + + try { + $dbartworks = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $dbartworks->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + // DB artowrks + if ($fetch_artworks_existed == false) { + try { + $dbartworks->exec('create table artists (artist_uri text PRIMARY KEY NOT NULL, artist_name text, already_fetched boolean)'); + $dbartworks->exec('create table tracks (track_uri text PRIMARY KEY NOT NULL, already_fetched boolean)'); + $dbartworks->exec('create table albums (album_uri text PRIMARY KEY NOT NULL, already_fetched boolean)'); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + } + + try { + // artworks + $insertArtistArtwork = 'insert or ignore into artists values (:artist_uri,:artist_name,:already_fetched)'; + $stmtArtistArtwork = $dbartworks->prepare($insertArtistArtwork); + + $insertTrackArtwork = 'insert or ignore into tracks values (:track_uri,:already_fetched)'; + $stmtTrackArtwork = $dbartworks->prepare($insertTrackArtwork); + + $insertAlbumArtwork = 'insert or ignore into albums values (:album_uri,:already_fetched)'; + $stmtAlbumArtwork = $dbartworks->prepare($insertAlbumArtwork); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + $artworksToDownload = false; + } + + rename($w->data().'/library.db', $w->data().'/library_old.db'); + copy($w->data().'/library_old.db', $w->data().'/library_new.db'); + $dbfile = $w->data().'/library_new.db'; + + $nb_added_playlists = 0; + $nb_removed_playlists = 0; + $nb_updated_playlists = 0; + + try { + $db = new PDO("sqlite:$dbfile", '', '', array( + PDO::ATTR_PERSISTENT => true, + )); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $db->exec('drop table counters'); + $db->exec('create table counters (all_tracks int, yourmusic_tracks int, all_artists int, yourmusic_artists int, all_albums int, yourmusic_albums int, playlists int)'); + + $getPlaylists = 'select * from playlists where uri=:uri'; + $stmtGetPlaylists = $db->prepare($getPlaylists); + + $insertPlaylist = 'insert into playlists values (:uri,:name,:nb_tracks,:owner,:username,:playlist_artwork_path,:ownedbyuser,:nb_playable_tracks,:duration_playlist,:nb_times_played,:collaborative,:public)'; + $stmtPlaylist = $db->prepare($insertPlaylist); + + $insertTrack = 'insert into tracks values (:yourmusic,:popularity,:uri,:album_uri,:artist_uri,:track_name,:album_name,:artist_name,:album_type,:track_artwork_path,:artist_artwork_path,:album_artwork_path,:playlist_name,:playlist_uri,:playable,:added_at,:duration,:nb_times_played,:local_track)'; + $stmtTrack = $db->prepare($insertTrack); + + $deleteFromTracks = 'delete from tracks where playlist_uri=:playlist_uri'; + $stmtDeleteFromTracks = $db->prepare($deleteFromTracks); + + $updatePlaylistsNbTracks = 'update playlists set nb_tracks=:nb_tracks,nb_playable_tracks=:nb_playable_tracks,duration_playlist=:duration_playlist,public=:public where uri=:uri'; + $stmtUpdatePlaylistsNbTracks = $db->prepare($updatePlaylistsNbTracks); + + $deleteFromTracksYourMusic = 'delete from tracks where yourmusic=:yourmusic'; + $stmtDeleteFromTracksYourMusic = $db->prepare($deleteFromTracksYourMusic); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + + $savedListPlaylist = array(); + $offsetGetUserPlaylists = 0; + $limitGetUserPlaylists = 50; + do { + $retry = true; + $nb_retry = 0; + try { + $api = getSpotifyWebAPI($w); + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleSpotifyWebAPIException($w, $e); + + return false; + } + + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylists = $api->getUserPlaylists(urlencode($userid), array( + 'limit' => $limitGetUserPlaylists, + 'offset' => $offsetGetUserPlaylists, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getUserPlaylists): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + $nb_playlist_total = $userPlaylists->total; + + foreach ($userPlaylists->items as $playlist) { + if ($playlist->name != '') { + $savedListPlaylist[] = $playlist; + } + } + $offsetGetUserPlaylists += $limitGetUserPlaylists; + } while ($offsetGetUserPlaylists < $userPlaylists->total); + + // consider Your Music as a playlist for progress bar + ++$nb_playlist_total; + + foreach ($savedListPlaylist as $playlist) { + $tracks = $playlist->tracks; + $owner = $playlist->owner; + + ++$nb_playlist; + $w->write('Refresh Library▹'.$nb_playlist.'▹'.$nb_playlist_total.'▹'.$words[3].'▹'.escapeQuery($playlist->name), 'update_library_in_progress'); + + try { + // Loop on existing playlists in library + $stmtGetPlaylists->bindValue(':uri', $playlist->uri); + $stmtGetPlaylists->execute(); + + $noresult = true; + while ($playlists = $stmtGetPlaylists->fetch()) { + $noresult = false; + break; + } + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + + // Playlist does not exist, add it + if ($noresult == true) { + ++$nb_added_playlists; + $playlist_artwork_path = getPlaylistArtwork($w, $playlist->uri, true, true, $use_artworks); + + if ('-'.$owner->id.'-' == '-'.$userid.'-') { + $ownedbyuser = 1; + } else { + $ownedbyuser = 0; + } + + $nb_track_playlist = 0; + $duration_playlist = 0; + $offsetGetUserPlaylistTracks = 0; + $limitGetUserPlaylistTracks = 100; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylistTracks = $api->getPlaylistTracks($playlist->id, array( + 'fields' => array( + 'total', + 'items(added_at)', + 'items(is_local)', + 'items.track(is_playable,duration_ms,uri,popularity,name,linked_from)', + 'items.track.album(album_type,images,uri,name)', + 'items.track.artists(name,uri)', + ), + 'limit' => $limitGetUserPlaylistTracks, + 'offset' => $offsetGetUserPlaylistTracks, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getPlaylistTracks): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userPlaylistTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + $duration_playlist += $track->duration_ms; + + try { + $stmtTrack->bindValue(':yourmusic', 0); + $stmtTrack->bindValue(':popularity', $track->popularity); + $stmtTrack->bindValue(':uri', $track->uri); + $stmtTrack->bindValue(':album_uri', $album->uri); + $stmtTrack->bindValue(':artist_uri', $artist->uri); + $stmtTrack->bindValue(':track_name', escapeQuery($track->name)); + $stmtTrack->bindValue(':album_name', escapeQuery($album->name)); + $stmtTrack->bindValue(':artist_name', escapeQuery($artist->name)); + $stmtTrack->bindValue(':album_type', $album->album_type); + $stmtTrack->bindValue(':track_artwork_path', $track_artwork_path); + $stmtTrack->bindValue(':artist_artwork_path', $artist_artwork_path); + $stmtTrack->bindValue(':album_artwork_path', $album_artwork_path); + $stmtTrack->bindValue(':playlist_name', escapeQuery($playlist->name)); + $stmtTrack->bindValue(':playlist_uri', $playlist->uri); + $stmtTrack->bindValue(':playable', $playable); + $stmtTrack->bindValue(':added_at', $item->added_at); + $stmtTrack->bindValue(':duration', beautifyTime($track->duration_ms / 1000)); + $stmtTrack->bindValue(':nb_times_played', 0); + $stmtTrack->bindValue(':local_track', $local_track); + $stmtTrack->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + ++$nb_track_playlist; + } + + $offsetGetUserPlaylistTracks += $limitGetUserPlaylistTracks; + } while ($offsetGetUserPlaylistTracks < $userPlaylistTracks->total); + + try { + $stmtPlaylist->bindValue(':uri', $playlist->uri); + $stmtPlaylist->bindValue(':name', escapeQuery($playlist->name)); + $stmtPlaylist->bindValue(':nb_tracks', $tracks->total); + $stmtPlaylist->bindValue(':owner', $owner->id); + $stmtPlaylist->bindValue(':username', $owner->id); + $stmtPlaylist->bindValue(':playlist_artwork_path', $playlist_artwork_path); + $stmtPlaylist->bindValue(':ownedbyuser', $ownedbyuser); + $stmtPlaylist->bindValue(':nb_playable_tracks', $nb_track_playlist); + $stmtPlaylist->bindValue(':duration_playlist', beautifyTime($duration_playlist / 1000, true)); + $stmtPlaylist->bindValue(':nb_times_played', 0); + $stmtPlaylist->bindValue(':collaborative', $playlist->collaborative); + $stmtPlaylist->bindValue(':public', $playlist->public); + $stmtPlaylist->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + + displayNotificationWithArtwork($w, 'Added playlist '.escapeQuery($playlist->name), $playlist_artwork_path, 'Refresh Library'); + } else { + + // check if this is a self-updated playlist (spotify and 30 tracks) + $selfUpdatedPlaylistUpdated = false; + + $owner = getPlaylistOwner($w,$playlists[0]); + + if($owner == 'spotify' && $tracks->total == 30) { + + try { + $getOneTrack = 'select added_at from tracks where playlist_uri=:theplaylisturi order by added_at desc limit 1'; + $stmtGetOneTrack = $db->prepare($getOneTrack); + $stmtGetOneTrack->bindValue(':theplaylisturi', $playlists[0]); + $stmtGetOneTrack->execute(); + $theOneTrack = $stmtGetOneTrack->fetch(); + date_default_timezone_set('UTC'); + $today = date("c"); + $last_updated = $theOneTrack[0]; + $today_time = strtotime($today); + $last_updated_time = strtotime($last_updated); + + if( ($today_time - $last_updated_time) > 7*24*3600) { + $selfUpdatedPlaylistUpdated = true; + } + } catch (PDOException $e) { + logMsg('Error(refreshLibrary - self-updated playlist): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + } + + // number of tracks has changed or playlist name has changed or the privacy has changed, or spotify playlist (Release Radar, Discover Weekly) + // update the playlist + if ($selfUpdatedPlaylistUpdated || $playlists[2] != $tracks->total || $playlists[1] != escapeQuery($playlist->name) || + (($playlists[11] == '' && $playlist->public == true) || ($playlists[11] == true && $playlist->public == ''))) { + ++$nb_updated_playlists; + + // force refresh of playlist artwork + getPlaylistArtwork($w, $playlist->uri, true, true, $use_artworks); + + try { + if ($playlists[1] != escapeQuery($playlist->name)) { + $updatePlaylistsName = 'update playlists set name=:name where uri=:uri'; + $stmtUpdatePlaylistsName = $db->prepare($updatePlaylistsName); + + $stmtUpdatePlaylistsName->bindValue(':name', escapeQuery($playlist->name)); + $stmtUpdatePlaylistsName->bindValue(':uri', $playlist->uri); + $stmtUpdatePlaylistsName->execute(); + } + + $stmtDeleteFromTracks->bindValue(':playlist_uri', $playlist->uri); + $stmtDeleteFromTracks->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + + $duration_playlist = 0; + $nb_track_playlist = 0; + $offsetGetUserPlaylistTracks = 0; + $limitGetUserPlaylistTracks = 100; + $owner = $playlist->owner; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userPlaylistTracks = $api->getPlaylistTracks($playlist->id, array( + 'fields' => array( + 'total', + 'items(added_at)', + 'items(is_local)', + 'items.track(is_playable,duration_ms,uri,popularity,name,linked_from)', + 'items.track.album(album_type,images,uri,name)', + 'items.track.artists(name,uri)', + ), + 'limit' => $limitGetUserPlaylistTracks, + 'offset' => $offsetGetUserPlaylistTracks, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getPlaylistTracks): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userPlaylistTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + $duration_playlist += $track->duration_ms; + try { + $stmtTrack->bindValue(':yourmusic', 0); + $stmtTrack->bindValue(':popularity', $track->popularity); + $stmtTrack->bindValue(':uri', $track->uri); + $stmtTrack->bindValue(':album_uri', $album->uri); + $stmtTrack->bindValue(':artist_uri', $artist->uri); + $stmtTrack->bindValue(':track_name', escapeQuery($track->name)); + $stmtTrack->bindValue(':album_name', escapeQuery($album->name)); + $stmtTrack->bindValue(':artist_name', escapeQuery($artist->name)); + $stmtTrack->bindValue(':album_type', $album->album_type); + $stmtTrack->bindValue(':track_artwork_path', $track_artwork_path); + $stmtTrack->bindValue(':artist_artwork_path', $artist_artwork_path); + $stmtTrack->bindValue(':album_artwork_path', $album_artwork_path); + $stmtTrack->bindValue(':playlist_name', escapeQuery($playlist->name)); + $stmtTrack->bindValue(':playlist_uri', $playlist->uri); + $stmtTrack->bindValue(':playable', $playable); + $stmtTrack->bindValue(':added_at', $item->added_at); + $stmtTrack->bindValue(':duration', beautifyTime($track->duration_ms / 1000)); + $stmtTrack->bindValue(':nb_times_played', 0); + $stmtTrack->bindValue(':local_track', $local_track); + $stmtTrack->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + ++$nb_track_playlist; + } + + $offsetGetUserPlaylistTracks += $limitGetUserPlaylistTracks; + } while ($offsetGetUserPlaylistTracks < $userPlaylistTracks->total); + + try { + $stmtUpdatePlaylistsNbTracks->bindValue(':nb_tracks', $userPlaylistTracks->total); + $stmtUpdatePlaylistsNbTracks->bindValue(':nb_playable_tracks', $nb_track_playlist); + $stmtUpdatePlaylistsNbTracks->bindValue(':duration_playlist', beautifyTime($duration_playlist / 1000, true)); + $stmtUpdatePlaylistsNbTracks->bindValue(':uri', $playlist->uri); + $stmtUpdatePlaylistsNbTracks->bindValue(':public', $playlist->public); + $stmtUpdatePlaylistsNbTracks->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + displayNotificationWithArtwork($w, 'Updated playlist '.escapeQuery($playlist->name), getPlaylistArtwork($w, $playlist->uri, true, false, $use_artworks), 'Refresh Library'); + } else { + continue; + } + } + } + + try { + // check for deleted playlists + $getPlaylists = 'select * from playlists'; + $stmt = $db->prepare($getPlaylists); + $stmt->execute(); + + while ($playlist_in_db = $stmt->fetch()) { + $found = false; + foreach ($savedListPlaylist as $playlist) { + if ($playlist->uri == $playlist_in_db[0]) { + $found = true; + break; + } + } + if ($found == false) { + ++$nb_removed_playlists; + + $deleteFromPlaylist = 'delete from playlists where uri=:uri'; + $stmtDelete = $db->prepare($deleteFromPlaylist); + $stmtDelete->bindValue(':uri', $playlist_in_db[0]); + $stmtDelete->execute(); + + $deleteFromTracks = 'delete from tracks where playlist_uri=:uri'; + $stmtDelete = $db->prepare($deleteFromTracks); + $stmtDelete->bindValue(':uri', $playlist_in_db[0]); + $stmtDelete->execute(); + displayNotificationWithArtwork($w, 'Removed playlist '.$playlist_in_db[1], getPlaylistArtwork($w, $playlist_in_db[0], false, false, $use_artworks), 'Refresh Library'); + } + } + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return; + } + + // check for update to Your Music + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + + // get only one, we just want to check total for now + $userMySavedTracks = $api->getMySavedTracks(array( + 'limit' => 1, + 'offset' => 0, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getMySavedTracks): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503) { + // retry + if ($nb_retry > 20) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(15); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + try { + // get current number of track in Your Music + $getCount = 'select count(distinct uri) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_tracks = $stmt->fetch(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return; + } + + $your_music_updated = false; + if ($yourmusic_tracks[0] != $userMySavedTracks->total) { + $your_music_updated = true; + // Your Music has changed, update it + ++$nb_playlist; + $w->write('Refresh Library▹'.$nb_playlist.'▹'.$nb_playlist_total.'▹'.$words[3].'▹'.'Your Music', 'update_library_in_progress'); + + // delete tracks + try { + $stmtDeleteFromTracksYourMusic->bindValue(':yourmusic', 1); + $stmtDeleteFromTracksYourMusic->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return; + } + + $offsetGetMySavedTracks = 0; + $limitGetMySavedTracks = 50; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userMySavedTracks = $api->getMySavedTracks(array( + 'limit' => $limitGetMySavedTracks, + 'offset' => $offsetGetMySavedTracks, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getMySavedTracks): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userMySavedTracks->items as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + + try { + $stmtTrack->bindValue(':yourmusic', 1); + $stmtTrack->bindValue(':popularity', $track->popularity); + $stmtTrack->bindValue(':uri', $track->uri); + $stmtTrack->bindValue(':album_uri', $album->uri); + $stmtTrack->bindValue(':artist_uri', $artist->uri); + $stmtTrack->bindValue(':track_name', escapeQuery($track->name)); + $stmtTrack->bindValue(':album_name', escapeQuery($album->name)); + $stmtTrack->bindValue(':artist_name', escapeQuery($artist->name)); + $stmtTrack->bindValue(':album_type', $album->album_type); + $stmtTrack->bindValue(':track_artwork_path', $track_artwork_path); + $stmtTrack->bindValue(':artist_artwork_path', $artist_artwork_path); + $stmtTrack->bindValue(':album_artwork_path', $album_artwork_path); + $stmtTrack->bindValue(':playlist_name', ''); + $stmtTrack->bindValue(':playlist_uri', ''); + $stmtTrack->bindValue(':playable', $playable); + $stmtTrack->bindValue(':added_at', $item->added_at); + $stmtTrack->bindValue(':duration', beautifyTime($track->duration_ms / 1000)); + $stmtTrack->bindValue(':nb_times_played', 0); + $stmtTrack->bindValue(':local_track', $local_track); + $stmtTrack->execute(); + } catch (PDOException $e) { + logMsg('Error(refreshLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $db = null; + + return; + } + } + + $offsetGetMySavedTracks += $limitGetMySavedTracks; + } while ($offsetGetMySavedTracks < $userMySavedTracks->total); + + + $savedListAlbums = array(); + $offsetGetMySavedAlbums = 0; + $limitGetMySavedAlbums = 50; + do { + $retry = true; + $nb_retry = 0; + while ($retry) { + try { + // refresh api + $api = getSpotifyWebAPI($w, $api); + $userMySavedAlbums = $api->getMySavedAlbums(array( + 'limit' => $limitGetMySavedAlbums, + 'offset' => $offsetGetMySavedAlbums, + 'market' => $country_code, + )); + $retry = false; + } catch (SpotifyWebAPI\SpotifyWebAPIException $e) { + logMsg('Error(getMySavedAlbums): retry '.$nb_retry.' (exception '.jTraceEx($e).')'); + + if ($e->getCode() == 429) { // 429 is Too Many Requests + $lastResponse = $api->getRequest()->getLastResponse(); + $retryAfter = $lastResponse['headers']['Retry-After']; + sleep($retryAfter); + } else if ($e->getCode() == 404) { + // skip + break; + } else if (strpos(strtolower($e->getMessage()), 'ssl') !== false) { + // cURL transport error: 35 LibreSSL SSL_connect: SSL_ERROR_SYSCALL error #251 + // https://github.com/vdesabou/alfred-spotify-mini-player/issues/251 + // retry any SSL error + ++$nb_retry; + } else if ($e->getCode() == 500 + || $e->getCode() == 502 || $e->getCode() == 503 || $e->getCode() == 202) { + // retry + if ($nb_retry > 2) { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + ++$nb_retry; + sleep(5); + } else { + handleSpotifyWebAPIException($w, $e); + $retry = false; + + return false; + } + } + } + + foreach ($userMySavedAlbums->items->album as $album) { + $tracks = $album->tracks; + $nb_tracktotal += $tracks->total; + if ($album->name != '') { + $savedListAlbums[] = $album; + logMsg('Error(savedListAlbums): (adding '.$album.')'); + } + } + + $offsetGetMySavedAlbums += $limitGetMySavedAlbums; + } while ($offsetGetMySavedAlbums < $userMySavedAlbums->total); + + + foreach ($savedListAlbums as $album) { + + logMsg('Error(savedListAlbums): (looping '.$album.')'); + foreach ($album as $item) { + if(!isset($item->track)) { + continue; + } + $track = $item->track; + $artists = $track->artists; + $artist = $artists[0]; + $album = $track->album; + + $playable = 0; + $local_track = 0; + if (isset($track->is_playable) && $track->is_playable) { + $playable = 1; + if (isset($track->linked_from) && isset($track->linked_from->uri)) { + $track->uri = $track->linked_from->uri; + } + } + if (isset($item->is_local) && $item->is_local) { + $playable = 1; + $local_track = 1; + } + + try { + + // Download artworks in Fetch later mode + $thetrackuri = 'spotify:track:faketrackuri'; + if ($local_track == 0 && isset($track->uri)) { + $thetrackuri = $track->uri; + } + if ($use_artworks) { + list($already_present, $track_artwork_path) = getTrackOrAlbumArtwork($w, $thetrackuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtTrackArtwork->bindValue(':track_uri', $thetrackuri); + $stmtTrackArtwork->bindValue(':already_fetched', 0); + $stmtTrackArtwork->execute(); + } + } else { + $track_artwork_path = getTrackOrAlbumArtwork($w, $thetrackuri, false, false, false, $use_artworks); + } + + $theartistname = 'fakeartist'; + if (isset($artist->name)) { + $theartistname = $artist->name; + } + $theartisturi = 'spotify:artist:fakeartisturi'; + if (isset($artist->uri)) { + $theartisturi = $artist->uri; + } + if ($use_artworks) { + list($already_present, $artist_artwork_path) = getArtistArtwork($w, $theartisturi, $theartistname, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtArtistArtwork->bindValue(':artist_uri', $artist->uri); + $stmtArtistArtwork->bindValue(':artist_name', $theartistname); + $stmtArtistArtwork->bindValue(':already_fetched', 0); + $stmtArtistArtwork->execute(); + } + } else { + $artist_artwork_path = getArtistArtwork($w, $theartisturi, $theartistname, false, false, false, $use_artworks); + } + + $thealbumuri = 'spotify:album:fakealbumuri'; + if (isset($album->uri)) { + $thealbumuri = $album->uri; + } + if ($use_artworks) { + list($already_present, $album_artwork_path) = getTrackOrAlbumArtwork($w, $thealbumuri, true, true, false, $use_artworks); + if ($already_present == false) { + $artworksToDownload = true; + $stmtAlbumArtwork->bindValue(':album_uri', $thealbumuri); + $stmtAlbumArtwork->bindValue(':already_fetched', 0); + $stmtAlbumArtwork->execute(); + } + } else { + $album_artwork_path = getTrackOrAlbumArtwork($w, $thealbumuri, false, false, false, $use_artworks); + } + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($dbartworks, $w); + $dbartworks = null; + $db = null; + + return false; + } + } + } + } + + // update counters + try { + $getCount = 'select count(distinct uri) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_tracks = $stmt->fetch(); + + $getCount = 'select count(distinct uri) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_tracks = $stmt->fetch(); + + $getCount = 'select count(distinct artist_name) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_artists = $stmt->fetch(); + + $getCount = 'select count(distinct artist_name) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_artists = $stmt->fetch(); + + $getCount = 'select count(distinct album_name) from tracks'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $all_albums = $stmt->fetch(); + + $getCount = 'select count(distinct album_name) from tracks where yourmusic=1'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $yourmusic_albums = $stmt->fetch(); + + $getCount = 'select count(*) from playlists'; + $stmt = $db->prepare($getCount); + $stmt->execute(); + $playlists_count = $stmt->fetch(); + + $insertCounter = 'insert into counters values (:all_tracks,:yourmusic_tracks,:all_artists,:yourmusic_artists,:all_albums,:yourmusic_albums,:playlists)'; + $stmt = $db->prepare($insertCounter); + + $stmt->bindValue(':all_tracks', $all_tracks[0]); + $stmt->bindValue(':yourmusic_tracks', $yourmusic_tracks[0]); + $stmt->bindValue(':all_artists', $all_artists[0]); + $stmt->bindValue(':yourmusic_artists', $yourmusic_artists[0]); + $stmt->bindValue(':all_albums', $all_albums[0]); + $stmt->bindValue(':yourmusic_albums', $yourmusic_albums[0]); + $stmt->bindValue(':playlists', $playlists_count[0]); + $stmt->execute(); + } catch (PDOException $e) { + logMsg('Error(updateLibrary): (exception '.jTraceEx($e).')'); + handleDbIssuePdoEcho($db, $w); + $dbartworks = null; + $db = null; + + return false; + } + + $elapsed_time = time() - $words[3]; + $changedPlaylists = false; + $changedYourMusic = false; + $addedMsg = ''; + $removedMsg = ''; + $updatedMsg = ''; + $yourMusicMsg = ''; + if ($nb_added_playlists > 0) { + $addedMsg = $nb_added_playlists.' added'; + $changedPlaylists = true; + } + + if ($nb_removed_playlists > 0) { + $removedMsg = $nb_removed_playlists.' removed'; + $changedPlaylists = true; + } + + if ($nb_updated_playlists > 0) { + $updatedMsg = $nb_updated_playlists.' updated'; + $changedPlaylists = true; + } + + if ($your_music_updated) { + $yourMusicMsg = ' - Your Music: updated'; + $changedYourMusic = true; + } + + if ($changedPlaylists && $changedYourMusic) { + $message = 'Playlists: '.$addedMsg.' '.$removedMsg.' '.$updatedMsg.' '.$yourMusicMsg; + } elseif ($changedPlaylists) { + $message = 'Playlists: '.$addedMsg.' '.$removedMsg.' '.$updatedMsg; + } elseif ($changedYourMusic) { + $message = $yourMusicMsg; + } else { + $message = 'No change'; + } + + if(getenv('reduce_notifications') == 0) { + displayNotificationWithArtwork($w, $message.' - took '.beautifyTime($elapsed_time, true), './images/update.png', 'Library refreshed'); + } + + if (file_exists($w->data().'/library_old.db')) { + deleteTheFile($w->data().'/library_old.db'); + } + rename($w->data().'/library_new.db', $w->data().'/library.db'); + + if ($use_artworks) { + // Download artworks in background + exec('php -f ./src/action.php -- "" "DOWNLOAD_ARTWORKS" "DOWNLOAD_ARTWORKS" >> "'.$w->cache().'/action.log" 2>&1 & '); + } + + deleteTheFile($w->data().'/update_library_in_progress'); +} + +/** + * handleDbIssuePdoXml function. + * + * @param mixed $dbhandle + */ +function handleDbIssuePdoXml($dbhandle) +{ + $errorInfo = $dbhandle->errorInfo(); + $w = new Workflows('com.vdesabou.spotify.mini.player'); + $w->result(null, '', 'Database Error: '.$errorInfo[0].' '.$errorInfo[1].' '.$errorInfo[2],array( + '', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, '', 'There is a problem with the library, try to re-create it.',array( + 'Select Re-Create Library library below', + 'alt' => 'Not Available', + 'cmd' => 'Not Available', + 'shift' => 'Not Available', + 'fn' => 'Not Available', + 'ctrl' => 'Not Available', + ), './images/warning.png', 'no', null, ''); + $w->result(null, serialize(array( + '' /*track_uri*/, + '' /* album_uri */, + '' /* artist_uri */, + '' /* playlist_uri */, + '' /* spotify_command */, + '' /* query */, + '' /* other_settings*/, + 'update_library' /* other_action */, + '' /* alfred_playlist_uri */, + '' /* artist_name */, + '' /* track_name */, + '' /* album_name */, + '' /* track_artwork_path */, + '' /* artist_artwork_path */, + '' /* album_artwork_path */, + '' /* playlist_name */, + '' /* playlist_artwork_path */, + '', + /* $alfred_playlist_name */ + )), 'Re-Create Library', "when done you'll receive a notification. you can check progress by invoking the workflow again", './images/update.png', 'yes', null, ''); + echo $w->tojson(); +} + +/** + * handleDbIssuePdoEcho function. + * + * @param mixed $dbhandle + * @param mixed $w + */ +function handleDbIssuePdoEcho($dbhandle, $w) +{ + $errorInfo = $dbhandle->errorInfo(); + logMsg('Error(DB Exception): '.$errorInfo[0].' '.$errorInfo[1].' '.$errorInfo[2]); + + if (file_exists($w->data().'/update_library_in_progress')) { + deleteTheFile($w->data().'/update_library_in_progress'); + } + + // set back old library + if (file_exists($w->data().'/library_new.db')) { + rename($w->data().'/library_new.db', $w->data().'/library.db'); + } + + if (file_exists($w->data().'/library_old.db')) { + deleteTheFile($w->data().'/library_old.db'); + } + + displayNotificationWithArtwork($w, 'DB Exception: '.$errorInfo[2], './images/warning.png'); + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' DB Exception: '.escapeQuery($errorInfo[2])."\"'"); + + exit; +} + +/** + * handleSpotifyWebAPIException function. + * + * @param mixed $w + * @param mixed $e + */ +function handleSpotifyWebAPIException($w, $e) +{ + if (file_exists($w->data().'/update_library_in_progress')) { + deleteTheFile($w->data().'/update_library_in_progress'); + } + + // remove the new library (it failed) + if (file_exists($w->data().'/library_new.db')) { + deleteTheFile($w->data().'/library_new.db'); + } + + // set back old library + if (file_exists($w->data().'/library_old.db')) { + rename($w->data().'/library_old.db', $w->data().'/library.db'); + } + + displayNotificationWithArtwork($w, 'Web API Exception: '.$e->getCode().' - '.$e->getMessage().' use spot_mini_debug command', './images/warning.png', 'Error!'); + + exec("osascript -e 'tell application id \"".getAlfredName()."\" to search \"".getenv('c_spot_mini_debug').' Web API Exception: '.escapeQuery($e->getMessage())."\"'"); + + exit; +} + +/** + * floatToCircles function. + * + * @param mixed $decimal + */ + function floatToCircles($decimal) + { + $squares = ($decimal < 1) ? floor($decimal * 10) : 10; + + return str_repeat('●', $squares).str_repeat('○︎', 10 - $squares); + } + +/** + * floatToSquares function. + * + * @param mixed $decimal + */ +function floatToSquares($decimal, $numSquares = 10) +{ + $squares = ($decimal < 1) ? floor($decimal * $numSquares) : $numSquares; + + return str_repeat('◼︎', $squares).str_repeat('◻︎', $numSquares - $squares); +} + +/** + * floatToStars function. + * + * @param mixed $decimal + */ +function floatToStars($decimal) +{ + if ($decimal == 0) { + return ''; + } + $squares = ($decimal < 1) ? floor($decimal * 5) : 5; + + return str_repeat('★', $squares).str_repeat('☆', 5 - $squares); +} + +/** + * Mulit-byte Unserialize. + * + * UTF-8 will screw up a serialized string + * Thanks to http://stackoverflow.com/questions/2853454/php-unserialize-fails-with-non-encoded-characters + * + * @param string + * + * @return string + */ +function mb_unserialize($string) +{ + $string2 = preg_replace_callback( + '!s:(\d+):"(.*?)";!s', + function ($m) { + $len = strlen($m[2]); + $result = "s:$len:\"{$m[2]}\";"; + + return $result; + }, + $string); + + return unserialize($string2); +} + +/** + * cleanupTrackName function. + * + * @param mixed $track_name + */ +function cleanupTrackName($track_name) +{ + return str_ireplace(array( + 'acoustic version', + 'new album version', + 'original album version', + 'album version', + 'bonus track', + 'clean version', + 'club mix', + 'demo version', + 'extended mix', + 'extended outro', + 'extended version', + 'extended', + 'explicit version', + 'explicit', + '(live)', + '- live', + 'live version', + 'lp mix', + '(original)', + 'original edit', + 'original mix edit', + 'original version', + '(radio)', + 'radio edit', + 'remix edit', + 'radio mix', + 'remastered version', + 're-mastered version', + 'remastered digital version', + 're-mastered digital version', + 'remastered', + 'remaster', + 'remixed version', + 'remix', + 'single version', + 'studio version', + 'version acustica', + 'versión acústica', + 'vocal edit', + ), '', $track_name); +} + +/** + * cleanupArtistName function. + * + * @param mixed $artist_name + */ +function cleanupArtistName($artist_name) +{ + $query_artist = $artist_name; + if (stristr($query_artist, 'feat.')) { + $query_artist = stristr($query_artist, 'feat.', true); + } elseif (stristr($query_artist, 'featuring')) { + $query_artist = stristr($query_artist, 'featuring', true); + } elseif (stristr($query_artist, ' & ')) { + $query_artist = stristr($query_artist, ' & ', true); + } + + $query_artist = str_replace('&', 'and', $query_artist); + $query_artist = str_replace('$', 's', $query_artist); + $query_artist = strip_string(trim($query_artist)); + $query_artist = str_replace(' - ', '-', $query_artist); + $query_artist = str_replace(' ', '-', $query_artist); + + return $query_artist; +} + +/* + +This function was mostly taken from SpotCommander. + +SpotCommander is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +SpotCommander is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with SpotCommander. If not, see . + +Copyright 2013 Ole Jon Bjørkum + +* getLyrics function. +* +* @access public +* @param mixed $w +* @param mixed $artist +* @param mixed $title +* @return lyrics +*/ +function getLyrics($w, $artist, $title) +{ + $query_artist = $artist; + $query_title = $title; + + $query_artist = cleanupArtistName($query_artist); + $query_title = cleanupTrackName($query_title); + + if (stristr($query_title, 'feat.')) { + $query_title = stristr($query_title, 'feat.', true); + } elseif (stristr($query_title, 'featuring')) { + $query_title = stristr($query_title, 'featuring', true); + } elseif (stristr($query_title, ' con ')) { + $query_title = stristr($query_title, ' con ', true); + } elseif (stristr($query_title, '(includes')) { + $query_title = stristr($query_title, '(includes', true); + } elseif (stristr($query_title, '(live at')) { + $query_title = stristr($query_title, '(live at', true); + } elseif (stristr($query_title, 'revised')) { + $query_title = stristr($query_title, 'revised', true); + } elseif (stristr($query_title, '(19')) { + $query_title = stristr($query_title, '(19', true); + } elseif (stristr($query_title, '(20')) { + $query_title = stristr($query_title, '(20', true); + } elseif (stristr($query_title, '- 19')) { + $query_title = stristr($query_title, '- 19', true); + } elseif (stristr($query_title, '- 20')) { + $query_title = stristr($query_title, '- 20', true); + } + + $query_title = str_replace('&', 'and', $query_title); + $query_title = str_replace('$', 's', $query_title); + $query_title = strip_string(trim($query_title)); + $query_title = str_replace(' - ', '-', $query_title); + $query_title = str_replace(' ', '-', $query_title); + $query_title = rtrim($query_title, '-'); + + $uri = strtolower('https://www.musixmatch.com/lyrics/'.$query_artist.'/'.$query_title); + $error = false; + $no_match = false; + + $options = array( + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_TIMEOUT => 10, + CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13', + ); + $file = $w->request($uri, $options); + + preg_match('/