Compare commits

..

No commits in common. "main" and "0.2.1" have entirely different histories.
main ... 0.2.1

7 changed files with 29 additions and 46 deletions

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.