Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
68692bdc83 | ||
|
f3d4421af2 | ||
|
efe856c0fe | ||
|
3e430f8ff2 | ||
|
ddf9ab7fd1 | ||
|
0e1b8fe987 | ||
|
1861a2fcd7 | ||
|
c717e7eeb4 | ||
b2d1007c09 |
@ -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)
|
||||||
|
@ -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
BIN
sounds/navi/hello.ogg
Normal file
Binary file not shown.
BIN
sounds/navi/hey.ogg
Normal file
BIN
sounds/navi/hey.ogg
Normal file
Binary file not shown.
BIN
sounds/navi/listen.ogg
Normal file
BIN
sounds/navi/listen.ogg
Normal file
Binary file not shown.
BIN
sounds/navi/look.ogg
Normal file
BIN
sounds/navi/look.ogg
Normal file
Binary file not shown.
BIN
sounds/navi/watch-out.ogg
Normal file
BIN
sounds/navi/watch-out.ogg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user