5

I use the calendar and scheduling application calcurse. This is a fine command-line program.

For example, with calcurse -a you can display the events for the day.

How i can send this info to notify-send, to show a notification on the desktop?

$ calcurse -a | notify-send

will not work ...

  • Both. But, this is not the problem. For example, you can get the infos for earlier events with 'calcurse -d n'. The problem ist not to create the output (this i do with a script), but how can i can put the info to notify-send? – Dino Dec 27 '15 at 10:08
  • calcurse -a gives the following output: 12/27/15: * Weihnachtsferien 2015 Nordrhein-Westfalen – Dino Dec 27 '15 at 10:26
  • Here is a screenshot: ovh.to/8mQGeEu – Dino Dec 27 '15 at 10:35
2

About Calcurse

As often, reverting to a (very) basic, but nevertheless complete functionality feels weird, but in a way refreshing. Not sure if I would use it though.

Although the bottom of Calcurse's window suggests an option to pipe, and Calcurse's website mentions "user-configurable notification system" I couldn't find a way to use it for automatic scheduled notifications of all events.

enter image description here

At the same time: indeed such a reminder functionality would be a useful addition. The script below can be used as a plug- in for calcurse to show reminders. I hope you find it useful.

It is extremely easy to use; simply run the script in the background. All it does is check the events for today (updated twice per minute), and run notifications at an arbitrary time before expiration.

What is needed to create reminders

The output of the command:

calcurse -a 

looks like:

12/29/15:
 * Free today!
 - 12:00 -> ..:..
    See if this script does its job :)

It immediately occurs that the scheduled items start with a "-", while items for all day start with "*". What we need to do is create two groups (lists) of items:

  • the scheduled ones
  • the unscheduled ones

Of the first category, we need to parse out the time, convert it into a format we can calculate with, so we can show reminder at n- minutes before expiration.

Subsequently, we need to "keep an eye on the clock", to compare the set time (of the event) to the current time. If the time span between the two enters the set warning time, simply show the notification.
Finally, to prevent repeated notification, we need to add the item to a "done" list.

Additionally, the script cleans up the "done" list; if an item does not occur in today's items anymore (either if you removed it or the day switched during your session), the items are removed automatically.

The result

On startup (log in)

  • the script shows all today's items, in succession:

    enter image description here enter image description here

On an arbitrary time before expiration (in this case 15 minutes)

  • the scripts reminds you in a notification:

    enter image description here

The script

#!/usr/bin/env python3
import subprocess
import time
import sys

warn = int(sys.argv[1])

def get(command):
    return subprocess.check_output(command).decode("utf-8")

def convert(t):
    # convert set time into a calculate- able time
    return [int(n) for n in t.split(":")]

def calc_diff(t_curr, t_event):
    # calculate time span
    diff_hr = (t_event[0] - t_curr[0])*60
    diff_m = t_event[1] - t_curr[1]
    return diff_hr + diff_m

def cleanup(done, newlist):
    # clean up "done" -lists
    for item in done:
        if not item in newlist:
            done.remove(item)
    return done

def show_time(event, s = ""):
    # show scheduled event
    hrs = str(event[0][0]); mnts = str(event[0][1])
    mnts = "0"+mnts if len(mnts) != 2 else mnts
    subprocess.call(["notify-send", s, "At "+hrs+":"+mnts+" - "+event[1]])

startups = []; times = []

while True:
    currtime = convert(time.strftime("%H:%M"))
    events = [l.strip() for l in get(["calcurse", "-a"]).splitlines()][1:]
    # arrange event data:
    groups = []; sub = []
    for l in events:
        if l.startswith("* "):
            groups.append([l.replace("* ", "")])
        elif l.startswith("- "):
            sub.append(convert(l.split("->")[0].replace("-", "").strip()))
        else:
            groups.append(sub+[l])
            sub = []
    # run notifications
    for item in groups:
        # on startup:
        if not item in startups:
            # all- day events
            if len(item) == 1:
                subprocess.call(["notify-send", "Today - "+item[0]])
            # time- specific events
            elif len(item) == 2:
                show_time(item, "Appointment")
            startups.append(item)
        # as a reminder:
        if all([len(item) == 2, not item in times]):
            span = calc_diff(currtime, item[0])
            if span <= warn:
                show_time(item, "[Reminder]")
                times.append(item)     
    # clean up events
    startups = cleanup(startups, groups); times = cleanup(times, groups)
    time.sleep(30)

How to use

  • Copy the script into an empty file, save it as run_ccursereminders.py
  • Test- run it with the time you'd like to be warned (before expiration time, in minutes) as an argument. An example, to run reminders 30 minutes before your appointment:

    python3 /path/to/run_ccursereminders.py 30
    
  • If it works as you wish, add it to Startup Applications: choose Dash > Startup Applications > Add. Add the command

    /bin/bash -c "sleep 30 && python3 /path/to/run_ccursereminders.py 30"
    

    where the last 30 is the number of minutes to warn you before an appointment expires

  • Many many thanks for the quick and professional response. Now everything works as I would like. – Dino Dec 29 '15 at 14:53
  • @Dino You're welcome, it was fun to do :) – Jacob Vlijm Dec 29 '15 at 14:58
1

I was able to make it working with command substitution:

notify-send "calcurse notification header" "$(calcurse -n)"
0

I no this is old, but if anyone is still interested, the following settings work for me in my ~/.calcurse/conf file:

notification.command=calcurse --next | xargs -0 notify-send "Appointment"
daemon.enable=yes
notification.warning=300

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.