diff --git a/index.js b/index.js index 93cec26..2b384ed 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,13 @@ #!/usr/bin/env node import fs from "fs"; -import { evaluate } from "mathjs"; + import path from "path"; import { program } from "commander"; import logger from "./logger.js"; +import * as math from "./modes/math.js"; +import * as timer from "./modes/timer.js"; import * as utils from "./utils.js"; const { __dirname } = utils.fileDirName(import.meta); @@ -18,23 +20,8 @@ program .version(version) .description(description) .option("-e, --edit", "Edit your choices") - .option( - "-m, --math [expression]", - `Math mode - \n - • Handles numeric seprators - 12,000 + 4,000 => 12,400 - 12_000 + 4_000 => 12_400 - - • Handles unit converstion expressions - 12.7 cm to inch => 5 inch - - • Complex expressions - "sin(45 deg) ^ 2" => 0.5 - "9 / 3 + 2i" => 3 + 2i - "det([-1, 2; 3, 1])" => -7 - ` - ) + .option(math.option, math.optionDef) + .option(timer.option, timer.optionDef) .action(async (cmd) => { if (cmd.edit) { logger.warning("Opening choices file..."); @@ -44,27 +31,9 @@ program logger.error(`An error occurred: ${error}`); } } else if (cmd.math) { - let mathResult; - - try { - let mathString = cmd.math + program.args.join(" "); - const hasCommas = - mathString.replaceAll(",", "").length < mathString.length; - const hasUnderscores = - mathString.replaceAll("_", "").length < mathString.length; - mathString = mathString.replaceAll(",", "").replaceAll("_", ""); - mathResult = evaluate(mathString); - - if (hasUnderscores) { - mathResult = mathResult.toLocaleString().replace(/,/g, "_"); - } else if (hasCommas) { - mathResult = mathResult.toLocaleString(); - } - - logger.branded(`${mathResult}`); - } catch { - logger.error("Unable evaluate the provided equation"); - } + await math.logic([cmd.math, ...program.args]); + } else if (cmd.timer) { + await timer.logic(cmd.timer, program.args[0]); } else { utils.askChoices(); } diff --git a/lib/player.js b/lib/player.js new file mode 100644 index 0000000..17664ec --- /dev/null +++ b/lib/player.js @@ -0,0 +1,43 @@ +import { exec } from "child_process"; +import util from "util"; + +const execPromise = util.promisify(exec); + +/* MAC PLAY COMMAND */ +const macPlayCommand = (path, volume) => `afplay \"${path}\" -v ${volume}`; + +/* WINDOW PLAY COMMANDS */ +const addPresentationCore = `Add-Type -AssemblyName presentationCore;`; +const createMediaPlayer = `$player = New-Object system.windows.media.mediaplayer;`; +const loadAudioFile = (path) => `$player.open('${path}');`; +const playAudio = `$player.Play();`; +const stopAudio = `Start-Sleep 1; Start-Sleep -s $player.NaturalDuration.TimeSpan.TotalSeconds;Exit;`; + +const windowPlayCommand = (path, volume) => + `powershell -c ${addPresentationCore} ${createMediaPlayer} ${loadAudioFile( + path + )} $player.Volume = ${volume}; ${playAudio} ${stopAudio}`; + +const player = { + play: async (path, volume = 0.5) => { + /** + * Window: mediaplayer's volume is from 0 to 1, default is 0.5 + * Mac: afplay's volume is from 0 to 255, default is 1. However, volume > 2 usually result in distortion. + * Therefore, it is better to limit the volume on Mac, and set a common scale of 0 to 1 for simplicity + */ + const volumeAdjustedByOS = + process.platform === "darwin" ? Math.min(2, volume * 2) : volume; + + const playCommand = + process.platform === "darwin" + ? macPlayCommand(path, volumeAdjustedByOS) + : windowPlayCommand(path, volumeAdjustedByOS); + try { + await execPromise(playCommand, { windowsHide: true }); + } catch (err) { + throw err; + } + }, +}; + +export default player; diff --git a/media/bells.mp3 b/media/bells.mp3 new file mode 100644 index 0000000..0223944 Binary files /dev/null and b/media/bells.mp3 differ diff --git a/modes/math.js b/modes/math.js new file mode 100644 index 0000000..0c2d3e9 --- /dev/null +++ b/modes/math.js @@ -0,0 +1,42 @@ +import { evaluate } from "mathjs"; + +import logger from "./../logger.js"; + +export const option = "-m, --math [expression]"; +export const optionDef = `Math mode +\n +• Handles numeric seprators + 12,000 + 4,000 => 12,400 + 12_000 + 4_000 => 12_400 + +• Handles unit converstion expressions + 12.7 cm to inch => 5 inch + +• Complex expressions + "sin(45 deg) ^ 2" => 0.5 + "9 / 3 + 2i" => 3 + 2i + "det([-1, 2; 3, 1])" => -7 +`; + +export const logic = async (args) => { + let mathResult; + + try { + let mathString = args.join(" "); + const hasCommas = mathString.replaceAll(",", "").length < mathString.length; + const hasUnderscores = + mathString.replaceAll("_", "").length < mathString.length; + mathString = mathString.replaceAll(",", "").replaceAll("_", ""); + mathResult = evaluate(mathString); + + if (hasUnderscores) { + mathResult = mathResult.toLocaleString().replace(/,/g, "_"); + } else if (hasCommas) { + mathResult = mathResult.toLocaleString(); + } + + logger.branded(`${mathResult}`); + } catch { + logger.error("Unable evaluate the provided equation"); + } +}; diff --git a/modes/timer.js b/modes/timer.js new file mode 100644 index 0000000..3737513 --- /dev/null +++ b/modes/timer.js @@ -0,0 +1,73 @@ +import player from "./../lib/player.js"; +import logger from "./../logger.js"; + +export const option = "-t, --timer [time unit] [number of units]"; +export const optionDef = `Timer mode +\n +time units available: + s, sec, secs, second, seconds + m, min, mins, minute, minutes + h, hr, hrs, hour, hours + d, day, days +`; + +const soundAlarm = () => { + player + .play("./media/bells.mp3", (err) => { + if (err) console.log(`Could not play sound: ${err}`); + }) + .then(() => { + logger.branded("Time's up!"); + }); +}; + +export const logic = async (unit, num) => { + if (isNaN(Number(num))) { + logger.error("Please enter number of mins for timer"); + return; + } + + let time; + try { + switch (unit) { + case "s": + case "sec": + case "secs": + case "second": + case "seconds": + time = num * 1000; + unit = "seconds"; + break; + case "m": + case "min": + case "mins": + case "minute": + case "minutes": + time = num * 1000 * 60; + unit = "minutes"; + break; + case "h": + case "hr": + case "hrs": + case "hour": + case "hours": + time = num * 1000 * 60 * 60; + unit = "hours"; + break; + case "d": + case "day": + case "days": + time = num * 1000 * 60 * 60 * 24; + unit = "days"; + break; + default: + logger.error("Wrong time unit format was provided"); + break; + } + + setTimeout(soundAlarm, time); + logger.branded(`Setting timer for ${num} ${unit}...`); + } catch { + logger.error("Unable evaluate the provided equation"); + } +}; diff --git a/package-lock.json b/package-lock.json index d3eff76..dc264e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "yall-cli", - "version": "1.2.0", + "version": "2.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "yall-cli", - "version": "1.2.0", + "version": "2.2.0", "license": "MIT", "dependencies": { "chalk": "^5.2.0", @@ -25,7 +25,7 @@ }, "engines": { "node": ">=18", - "npm": ">=8.0.0 <9.0.0" + "npm": ">=8.0.0 <10.0.0" } }, "node_modules/@babel/code-frame": {