I love todo.txt. It’s a simple task system where pretty much everything lives in a single folder called “todo.txt.” After trying about 15 different task managers, I have found this system to be my favorite, and I’ve been using it for more than a year. Using Gina Trapani’s “todo.sh” script along with a bunch of my own bash scripts, most of my task-related needs are met… except for a calendar. After not finding a suitable existing todo.txt to calendar system, I decided to try writing my own. It took a few hours of tinkering, but it works!

To run this script, you’ll need a web server running php, and of course a todo.txt file somewhere on the same server. Load the script in a browser and it will give you an ics file with any todo items that have a due date. Load the script from an external calendar – like Google Calendar – and your due-dated todo items will appear on the calendar. Hooray!

Here’s the code:

<?php

// CB's Todo.txt to ics script
// goes through todo.txt and generates a calendar
// 2018-06-06
//
// HOW TO USE THIS
// this script parses a file in the todo.txt format and generates an ics file
// the ics file will have "all-day" calendar entries for todo.txt items
// that have due dates
// you can load this calendar into google calendar ("load public calendar") or
// other systems (like Fastmail's calendar)
//
// WHY?
// I love todo.txt but sometimes it's tough to get a picture of what I really
// need to do. Sticking my dated tasks on a calendar really helps me!

// inspiration from here:
// https://gist.github.com/jakebellacera/635416

// hide all errors, we don't want them mucking up our ics output
error_reporting(0);
ini_set('display_errors', 0);

// where does the todo.txt file live?
$todopath = "/path/to/your/todo/txt/file.txt";

// load the todo file, give us an error if we can't open it
$todofile = fopen($todopath, "r") or die("Unable to open todo file!");

// calendar file top stuff
$ical = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN";

// iterate through each line of the file
while(!feof($todofile)) {	  
	$line = fgets($todofile);
	//echo "line: $line <br>";
	// ONLY operate on the line if it contains a due date (due:YYYY-MM-DD)jk
	if (strpos($line, "due:") !== false) {
		//print "line contains DUE! doing stuff <br>";
		// explode the string into an array
		$array = explode(" ", $line);
		// iterate through each word and figure out what it is
		// i.e. a due date, a context, a project, threshold, hidden, etc.
		foreach ($array as &$word){
			//print "value: $value <br>";
			// IF WORD CONTAINS "due:"
			if (strpos($word, "due:") !== false) {
				//echo "--- this word contains DUE! <br>";
				// remove "due:"
				$due = str_replace("due:","",$word);
				// remove newlines
				$due = str_replace("\n","",$due);
				// remove dashes
				//$due = str_replace("-","",$due);
			}
			// IF WORD CONTAINS "@"
			if (strpos($word, "@") !== false) {
				//echo "--- this word has a context! <br>";
				$context = str_replace("\n","",$word);
			}

			// IF WORD CONTAINS "+"
			if (strpos($word, "+") !== false) {
				//echo "--- this word has a project! <br>";
				$project = $word;
			}

			// IF WORD CONTAINS "t:"
			if (strpos($word, "t:") !== false) {
				//echo "--- this word contains t: <br>";
				$threshold = $word;
			}

			// IF WORD CONTAINS "h:"
			if (strpos($word, "h:") !== false) {
				//echo "--- this word contains h: <br>";
				$hide = $word;
			}

			// IS THIS A DATE?
			if (DateTime::createFromFormat('Y-m-d', $word) !== FALSE) {
				//echo "---this word is a date! <br>";
				$dateAdded = $word;
			}

			// IS THIS A URL?
			if (strpos($word, "http") !== false) {
				//echo "--- this word is a URL!<br>";
				$url = $word;
			}
		}

		// put together a summary
		// summary: the name of the calendar event
		// description: more info when you click on the calendar event
		
		// BUILD THE SUMMARY
		// +projectname something something
		// get rid of due date
		$summary = (str_replace("due:".$due,"",$line));
		// remove dashes from the due date
		$due = str_replace("-","",$due);
		// get rid of the added date
		$summary = (str_replace($dateAdded,"",$summary));
		// get rid of the context
		$summary = (str_replace($context,"",$summary));
		// get rid of the threshold
		$summary = (str_replace($threshold,"",$summary));
		// get rid of the URL
		$summary = (str_replace($url,"",$summary));
		// remove project....
		$summary = (str_replace($project,"",$summary));
		//... so we can make it first
		$summary = $project . " " . $summary;
		// remove newlines
		$summary = (str_replace("\n","",$summary));
		// remove double spaces
		$summary = (str_replace("  "," ",$summary));

		//print "summary: $summary <br>";
		// create the ICS entry

$ical = $ical . "
BEGIN:VEVENT
DTSTART:$due
DTEND:$due
SUMMARY:$summary
DESCRIPTION:$line
URL:$url
END:VEVENT";
		
	} 
}

fclose($todofile); // close the todofile

$ical = $ical . "
END:VCALENDAR";

// comment these headers out to load the text in a web browser
// uncomment to generate an ics file when loading this script
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename=invite.ics');

echo $ical;
exit;
?>

 


2 responses

Mentions

  • Life Stack

Leave a Reply

Your email address will not be published. Required fields are marked *