| 'use strict'; |
| |
| // Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed) |
| |
| /** |
| * Module dependencies. |
| */ |
| |
| const spawn = require('child_process').spawn; |
| const fs = require('fs'); |
| const path = require('path'); |
| const os = require('os'); |
| |
| const exists = fs.existsSync || path.existsSync; |
| let cmd; |
| |
| function which(name) { |
| const paths = process.env.PATH.split(':'); |
| let loc; |
| |
| for (let i = 0, len = paths.length; i < len; i += 1) { |
| loc = path.join(paths[i], name); |
| if (exists(loc)) return loc; |
| } |
| return false; |
| } |
| |
| function setupCmd() { |
| switch (os.type()) { |
| case 'Darwin': |
| if (which('terminal-notifier')) { |
| cmd = { |
| type: 'Darwin-NotificationCenter', |
| pkg: 'terminal-notifier', |
| msg: '-message', |
| title: '-title', |
| subtitle: '-subtitle', |
| icon: '-appIcon', |
| sound: '-sound', |
| url: '-open', |
| priority: { |
| cmd: '-execute', |
| range: [], |
| }, |
| }; |
| } else { |
| cmd = { |
| type: 'Darwin-Growl', |
| pkg: 'growlnotify', |
| msg: '-m', |
| sticky: '--sticky', |
| url: '--url', |
| priority: { |
| cmd: '--priority', |
| range: [ |
| -2, |
| -1, |
| 0, |
| 1, |
| 2, |
| 'Very Low', |
| 'Moderate', |
| 'Normal', |
| 'High', |
| 'Emergency', |
| ], |
| }, |
| }; |
| } |
| break; |
| case 'Linux': |
| if (which('growl')) { |
| cmd = { |
| type: 'Linux-Growl', |
| pkg: 'growl', |
| msg: '-m', |
| title: '-title', |
| subtitle: '-subtitle', |
| host: { |
| cmd: '-H', |
| hostname: '192.168.33.1', |
| }, |
| }; |
| } else { |
| cmd = { |
| type: 'Linux', |
| pkg: 'notify-send', |
| msg: '', |
| sticky: '-t', |
| icon: '-i', |
| priority: { |
| cmd: '-u', |
| range: [ |
| 'low', |
| 'normal', |
| 'critical', |
| ], |
| }, |
| }; |
| } |
| break; |
| case 'Windows_NT': |
| cmd = { |
| type: 'Windows', |
| pkg: 'growlnotify', |
| msg: '', |
| sticky: '/s:true', |
| title: '/t:', |
| icon: '/i:', |
| url: '/cu:', |
| priority: { |
| cmd: '/p:', |
| range: [ |
| -2, |
| -1, |
| 0, |
| 1, |
| 2, |
| ], |
| }, |
| }; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| |
| /** |
| * Send growl notification _msg_ with _options_. |
| * |
| * Options: |
| * |
| * - title Notification title |
| * - sticky Make the notification stick (defaults to false) |
| * - priority Specify an int or named key (default is 0) |
| * - name Application name (defaults to growlnotify) |
| * - sound Sound efect ( in OSx defined in preferences -> sound -> effects) |
| * works only in OSX > 10.8x |
| * - image |
| * - path to an icon sets --iconpath |
| * - path to an image sets --image |
| * - capitalized word sets --appIcon |
| * - filename uses extname as --icon |
| * - otherwise treated as --icon |
| * |
| * Examples: |
| * |
| * growl('New email') |
| * growl('5 new emails', { title: 'Thunderbird' }) |
| * growl('5 new emails', { title: 'Thunderbird', sound: 'Purr' }) |
| * growl('Email sent', function(){ |
| * // ... notification sent |
| * }) |
| * |
| * @param {string} msg |
| * @param {object} opts |
| * @param {function} callback |
| * @api public |
| */ |
| |
| function growl(msg, opts, callback) { |
| let image; |
| const options = opts || {}; |
| const fn = callback || function noop() {}; |
| |
| setupCmd(); |
| |
| if (options.exec) { |
| cmd = { |
| type: 'Custom', |
| pkg: options.exec, |
| range: [], |
| }; |
| } |
| |
| // noop |
| if (!cmd) { |
| fn(new Error('growl not supported on this platform')); |
| return; |
| } |
| const args = [cmd.pkg]; |
| |
| // image |
| if (image || options.image) { |
| image = options.image; |
| switch (cmd.type) { |
| case 'Darwin-Growl': { |
| let flag; |
| const ext = path.extname(image).substr(1); |
| flag = ext === 'icns' && 'iconpath'; |
| flag = flag || (/^[A-Z]/.test(image) && 'appIcon'); |
| flag = flag || (/^png|gif|jpe?g$/.test(ext) && 'image'); |
| flag = flag || (ext && (image = ext) && 'icon'); |
| flag = flag || 'icon'; |
| args.push(`--${flag}`, image); |
| break; |
| } |
| case 'Darwin-NotificationCenter': |
| args.push(cmd.icon, image); |
| break; |
| case 'Linux': |
| args.push(cmd.icon, image); |
| // libnotify defaults to sticky, set a hint for transient notifications |
| if (!options.sticky) args.push('--hint=int:transient:1'); |
| break; |
| case 'Windows': |
| args.push(cmd.icon + image); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // sticky |
| if (options.sticky) args.push(cmd.sticky); |
| if (options.sticky && cmd.type === 'Linux') args.push('0'); |
| |
| // priority |
| if (options.priority) { |
| const priority = `${options.priority}`; |
| const checkindexOf = cmd.priority.range.indexOf(priority); |
| if (checkindexOf > -1) { |
| args.push(cmd.priority, options.priority); |
| } |
| } |
| |
| // sound |
| if (options.sound && cmd.type === 'Darwin-NotificationCenter') { |
| args.push(cmd.sound, options.sound); |
| } |
| |
| // name |
| if (options.name && cmd.type === 'Darwin-Growl') { |
| args.push('--name', options.name); |
| } |
| |
| switch (cmd.type) { |
| case 'Darwin-Growl': |
| args.push(cmd.msg); |
| args.push(msg.replace(/\\n/g, '\n')); |
| if (options.title) args.push(options.title); |
| if (options.url) { |
| args.push(cmd.url); |
| args.push(options.url); |
| } |
| break; |
| case 'Darwin-NotificationCenter': { |
| args.push(cmd.msg); |
| const stringifiedMsg = msg; |
| const escapedMsg = stringifiedMsg.replace(/\\n/g, '\n'); |
| args.push(escapedMsg); |
| if (options.title) { |
| args.push(cmd.title); |
| args.push(options.title); |
| } |
| if (options.subtitle) { |
| args.push(cmd.subtitle); |
| args.push(options.subtitle); |
| } |
| if (options.url) { |
| args.push(cmd.url); |
| args.push(options.url); |
| } |
| break; |
| } |
| case 'Linux-Growl': |
| args.push(cmd.msg); |
| args.push(msg.replace(/\\n/g, '\n')); |
| if (options.title) args.push(options.title); |
| if (cmd.host) { |
| args.push(cmd.host.cmd, cmd.host.hostname); |
| } |
| break; |
| case 'Linux': |
| if (options.title) args.push(options.title); |
| args.push(msg.replace(/\\n/g, '\n')); |
| break; |
| case 'Windows': |
| args.push(msg.replace(/\\n/g, '\n')); |
| if (options.title) args.push(cmd.title + options.title); |
| if (options.url) args.push(cmd.url + options.url); |
| break; |
| case 'Custom': { |
| const customCmd = args[0]; |
| const message = options.title |
| ? `${options.title}: ${msg}` |
| : msg; |
| let command = customCmd.replace(/(^|[^%])%s/g, `$1${message}`); |
| const splitCmd = command.split(' '); |
| if (splitCmd.length > 1) { |
| command = splitCmd.shift(); |
| Array.prototype.push.apply(args, splitCmd); |
| } |
| if (customCmd.indexOf('%s') < 0) { |
| args.push(message); |
| } |
| args[0] = command; |
| break; |
| } |
| default: |
| break; |
| } |
| const cmdToExec = args.shift(); |
| |
| const child = spawn(cmdToExec, args); |
| let stdout = ''; |
| let stderr = ''; |
| let error; |
| |
| const now = new Date(); |
| const timestamp = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}` |
| |
| stderr += `[${timestamp}][node-growl] : Executed command '${cmdToExec}' with arguments '${args}'\n[stderr] : `; |
| |
| child.on('error', (err) => { |
| console.error('An error occured.', err); |
| error = err; |
| }); |
| |
| child.stdout.on('data', (data) => { |
| stdout += data; |
| }); |
| |
| child.stderr.on('data', (data) => { |
| stderr += data; |
| }); |
| |
| child.on('close', () => { |
| if (typeof fn === 'function') { |
| fn(error, stdout, stderr); |
| } |
| }); |
| } |
| |
| /** |
| * Expose `growl`. |
| */ |
| |
| module.exports = growl; |