Compare commits

...

9 Commits
0.2.2 ... main

Author SHA1 Message Date
Jonathan Bernard
68692bdc83 Update for Nim 0.18 2018-04-02 14:48:18 -05:00
Jonathan Bernard
f3d4421af2 Fix <cfgFile> option handling. 2017-10-02 12:12:33 -05:00
Jonathan Bernard
efe856c0fe Clean up debug statements (logger already adds the level). 2016-11-05 08:20:22 -05:00
Jonathan Bernard
3e430f8ff2 Workaround for Nim bug 4996
As of Nim 0.15.2 there exists a conflict the compiler cannot reconcile between
`sequtils.toSeq` and `nre.toSeq`. The workaround is to be explicit about which
`toSeq` you want (see https://github.com/nim-lang/Nim/issues/4996).
2016-11-05 08:20:03 -05:00
Jonathan Bernard
ddf9ab7fd1 Finished work to enable navi sounds. 2016-11-05 00:35:18 -05:00
Jonathan Bernard
0e1b8fe987 Added dependency on cliutils. 2016-11-04 16:33:30 -05:00
Jonathan Bernard
1861a2fcd7 Started working on making the daemonize functionality a little more robust. 2016-11-04 16:29:32 -05:00
Jonathan Bernard
c717e7eeb4 Rename navi sounds folder. 2016-11-04 09:05:14 -05:00
b2d1007c09 Added Navi sounds. 2016-11-03 18:29:00 -05:00
7 changed files with 45 additions and 32 deletions

View File

@ -1,5 +1,7 @@
import daemonize, docopt, json, os, nre, sequtils, times, timeutils import cliutils, docopt, json, logging, os, nre, random, sequtils,
from posix import SIGTERM, SIGHUP, signal, kill times, timeutils
from posix import SIGTERM, SIGHUP, signal, kill, Pid
import strutils except toUpper import strutils except toUpper
from unicode import toUpper from unicode import toUpper
@ -9,30 +11,21 @@ type
DPConfig = tuple[planDir, dateFmt, pidfile, logfile, errfile: string, DPConfig = tuple[planDir, dateFmt, pidfile, logfile, errfile: string,
notificationSecs: int] notificationSecs: int]
CombinedConfig = object const VERSION = "0.3.3"
docopt: Table[string, Value] const NOTE_TITLE = "Daily Notifier v" & VERSION
json: JsonNode
proc getVal(cfg: CombinedConfig, key, default: string): string =
let argKey = "--" & key
let envKey = key.replace('-', '_').toUpper
let jsonKey = key.replace(re"(-\w)", proc (m: RegexMatch): string = ($m)[1..1].toUpper)
if cfg.docopt[argKey]: return $cfg.docopt[argKey]
elif existsEnv(envKey): return getEnv(envKey)
elif cfg.json.hasKey(jsonKey): return cfg.json[jsonKey].getStr
else: return default
const VERSION = "0.2.2"
const timeFmt = "HH:mm" const timeFmt = "HH:mm"
var args: Table[string, Value] var args: Table[string, Value]
var cfg: DPConfig var cfg: DPConfig
let appName = getAppFilename() let appName = getAppFilename()
let soundFile = appName[0..(appName.len-15)] & "sounds/notify1.ogg" let soundsDir: string = appName[0..(appName.len-15)] & "sounds/navi"
let soundFiles = seqUtils.toSeq(walkFiles(soundsDir & "/*"))
randomize()
proc parseDailyPlan(filename: string): seq[PlanItem] = proc parseDailyPlan(filename: string): seq[PlanItem] =
debug "Parsing daily plan file: " & filename
result = @[] result = @[]
var parseState = BeforeHeading var parseState = BeforeHeading
@ -56,18 +49,27 @@ proc parseDailyPlan(filename: string): seq[PlanItem] =
of AfterPlans: break of AfterPlans: break
else: break else: break
debug "Found " & $result.len & " items."
proc doAndLog(cmd: string): void =
debug "Executing '" & cmd & "'"
discard execShellCmd(cmd)
proc notifyDailyPlanItem(item: PlanItem): void = proc notifyDailyPlanItem(item: PlanItem): void =
let desc = item.time.format(timeFmt) & " - " & item.note
debug "Notifying: " & desc
let soundFile = soundFiles[random(soundFiles.len)]
case hostOS case hostOS
of "macosx": of "macosx":
discard execShellCmd("osascript -e 'display notification \"" & doAndLog "osascript -e 'display notification \"" &
item.time.format(timeFmt) & " - " & item.note & desc & "\" with title \"" & NOTE_TITLE & "\"'"
"\" with title \"Daily Notifier v" & VERSION & doAndLog "ogg123 \"" & soundFile & "\""
"\" sound name \"default\"'")
of "linux": of "linux":
discard execShellCmd("notify-send 'Daily Notifier v" & VERSION & "' '" & item.note & "'") doAndLog "notify-send '" & NOTE_TITLE & "' '" & desc & "'"
discard execShellCmd("paplay \"" & soundFile & "\"") doAndLog "paplay \"" & soundFile & "\""
echo "paplay \"" & soundFile & "\""
else: quit("Unsupported host OS: '" & hostOS & "'.") else: quit("Unsupported host OS: '" & hostOS & "'.")
@ -75,13 +77,15 @@ proc loadConfig(s: cint): void {. exportc, noconv .} =
# Find and parse the .dailynotificationrc file # Find and parse the .dailynotificationrc file
let rcLocations = @[ let rcLocations = @[
if args["--config"]: $args["<cfgFile>"] else:"", if args["--config"]: $args["--config"] else:"",
".dailynotificationrc", $getEnv("DAILY_NOTIFICATION_RC"), ".dailynotificationrc", $getEnv("DAILY_NOTIFICATION_RC"),
$getEnv("HOME") & "/.dailynotificationrc"] $getEnv("HOME") & "/.dailynotificationrc"]
var rcFilename: string = var rcFilename: string =
foldl(rcLocations, if len(a) > 0: a elif existsFile(b): b else: "") foldl(rcLocations, if len(a) > 0: a elif existsFile(b): b else: "")
debug "Reloading config file from " & rcFilename
var jsonCfg: JsonNode var jsonCfg: JsonNode
try: jsonCfg = parseFile(rcFilename) try: jsonCfg = parseFile(rcFilename)
except: jsonCfg = newJObject() except: jsonCfg = newJObject()
@ -102,6 +106,7 @@ proc loadConfig(s: cint): void {. exportc, noconv .} =
proc mainLoop(args: Table[string, Value]): void = proc mainLoop(args: Table[string, Value]): void =
debug "Started daemon main loop."
loadConfig(0) loadConfig(0)
signal(SIGHUP, loadConfig) signal(SIGHUP, loadConfig)
var curDay: TimeInfo = getLocalTime(fromSeconds(0)) var curDay: TimeInfo = getLocalTime(fromSeconds(0))
@ -169,6 +174,7 @@ Options:
-h --help Print this usage information. -h --help Print this usage information.
-s --notification-seconds <sec> -s --notification-seconds <sec>
-v --verbose Enable verbose output.
Notification period for plan items. Notification period for plan items.
@ -182,18 +188,25 @@ Options:
loadConfig(0) loadConfig(0)
addHandler(newConsoleLogger(
if args["--verbose"]: lvlAll
else: lvlInfo))
if args["start"]: if args["start"]:
# Start our daemon process (if needed) # Start our daemon process (if needed)
daemonize(cfg.pidfile, "/dev/null", cfg.logfile, cfg.errfile): info "daily_notifier: Starting daemon."
mainLoop(args) let childPid = daemonize(cfg.pidfile, "/dev/null", cfg.logfile, cfg.errfile, proc(): void = mainLoop(args))
if childPid == 0: quit(QuitSuccess) # We are the child... don't need to do anything else.
info "daily_notifier: Started, pid: " & $childPid
elif args["stop"] or args["reconfigure"]: elif args["stop"] or args["reconfigure"]:
if not fileExists(cfg.pidfile): if not fileExists(cfg.pidfile):
echo "daily_notifier is not running" info "daily_notifier: not running"
quit(QuitSuccess) quit(QuitSuccess)
let pid = parseInt(readFile(cfg.pidfile).strip) let pid: Pid = cast[Pid] (parseInt(readFile(cfg.pidfile).strip))
info "daily_notifier: Killing process " & $pid
if args["stop"]: discard kill(pid, SIGTERM) if args["stop"]: discard kill(pid, SIGTERM)
else: discard kill(pid, SIGHUP) else: discard kill(pid, SIGHUP)

View File

@ -1,6 +1,6 @@
# Package # Package
version = "0.2.2" version = "0.3.3"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Little programs that reads my daily plan and notifies me of upcoming events." description = "Little programs that reads my daily plan and notifies me of upcoming events."
license = "MIT" license = "MIT"
@ -8,5 +8,5 @@ bin = @["daily_notifier", "deploy_plans_via_ftp"]
# Dependencies # Dependencies
requires @["nim >= 0.15.0", "docopt", "timeutils", "tempfile", "daemonize"] requires @["nim >= 0.18.0", "docopt", "timeutils", "tempfile", "cliutils"]

BIN
sounds/navi/hello.ogg Normal file

Binary file not shown.

BIN
sounds/navi/hey.ogg Normal file

Binary file not shown.

BIN
sounds/navi/listen.ogg Normal file

Binary file not shown.

BIN
sounds/navi/look.ogg Normal file

Binary file not shown.

BIN
sounds/navi/watch-out.ogg Normal file

Binary file not shown.