<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl

use strict;
use WebService::30Boxes::API;
use DateTime;
use DateTime::Duration;
use Term::ANSIColor;

my $VERSION = "1.0";

my $usage = "Usage: -[w|d] n -t n\n";

die $usage if scalar(@ARGV) != 4;

my $date_string;
my $date_length;
my $todo_count;

if ($ARGV[0] eq "-w"){
	$date_string = "week";
	$date_length = $ARGV[1];
}
elsif ($ARGV[0] eq "-d"){
	$date_string = "day";
	$date_length = $ARGV[1];
}
else{
	die $usage;
}

if ($ARGV[2] eq "-t"){
	$todo_count = $ARGV[3];
}
else{
	die $usage;
}

#not the only way to get these
chomp (my $auth_token = &lt;STDIN&gt;);
chomp (my $api_key = &lt;STDIN&gt;);

my $from_date = DateTime-&gt;now;
my $to_date = DateTime-&gt;now;
#create end date
$to_date-&gt;add($date_string . "s" =&gt; $date_length);

my $boxes = WebService::30Boxes::API-&gt;new(api_key =&gt; $api_key);

&amp;print_events;
&amp;print_todos;

sub print_events {
	my $events = $boxes-&gt;call('events.Get', {authorizedUserToken =&gt; $auth_token, start =&gt; $from_date-&gt;ymd, end =&gt; $to_date-&gt;ymd});
	if($events-&gt;{'success'}){
		print color 'red';
		print "The events for the next $date_length $date_string";
		if ($date_length &gt; 1){
			print "s";
		}
		print ":\n";
		print color 'reset';
        
		my %all_events;
		my $found = 0;
        
		while ($events-&gt;nextEventId){
			my $startTime = $events-&gt;get_startTime;
			my $endTime = $events-&gt;get_endTime;
			my $endDate = $events-&gt;get_endDate;
			my $startDate = $events-&gt;get_startDate;
			#the data before ### is just for sorting purposes
			my $event = $startTime . " " . $endTime . "###" . "*\t" . $events-&gt;get_title;
        
			if ($events-&gt;isAllDayEvent){
				$event .= " all day until " . $endDate;
			}
			else{
				$event .= " from " . $startTime;
				$event .= " to " . $endTime;
			}
        
			#if the event spans over multiple days
			if ($startDate ne $endDate &amp;&amp;
				not $events-&gt;isAllDayEvent){
				$event .= " on " . $endDate;
			}
        
			my @notes = $events-&gt;get_notes;
			my $note = "";
			foreach(@notes){
				$note .= "$_" if $_ ne "";
			}
        
			if ($note ne ""){
				$event .= "\nNotes: $note";
			}
        
			my %repeats = (
				daily =&gt; 'days',
				weekly =&gt; 'weeks',
				monthly =&gt; 'months',
				yearly =&gt; 'years'
			);
        
			if ($events-&gt;get_repeatType eq 'no'){
				$all_events{$startDate} = [] if not defined $all_events{$startDate};
				push @{$all_events{$startDate}}, $event;
			}
			else{
				#if repeats
				$startDate =~ /(\d{4})-(\d{2})-(\d{2})/;
        
				my $increment_date = DateTime-&gt;new(
					year =&gt; $1,
					month =&gt; $2,
					day =&gt; $3
				);
        
				#while not at end date
				while (DateTime-&gt;compare($increment_date, $to_date) &lt; 1){
					push @{$all_events{$increment_date-&gt;ymd}}, $event;
					$increment_date-&gt;add($repeats{$events-&gt;get_repeatType} =&gt; $events-&gt;get_repeatInterval);
				}
			}

			$found = 1;
		}

		print "None!\n" if (0 == $found);

		my @dates = sort keys %all_events;
        
		#print them
		foreach (@dates){
			print color 'green';
			print "$_:\n";
			print color 'reset';
			
			foreach (sort @{$all_events{$_}}){
				s/.+###(.+)/$1/;
				if (/birthday/i){
					print color 'blue';
				}
        
				s/\n/\n\t/g;
				print "$_\n\n";
				print color 'reset';
			}
		}
	}
	else{
		print "An error occured (" . $events-&gt;{'error_code'} . ": " .
			$events-&gt;{'error_msg'} . ")\n";
	}
}

sub print_todos {
	my $todos = $boxes-&gt;call('todos.Get', {authorizedUserToken =&gt; $auth_token});

	my $count = 0;
	my %tags;
	print color 'red';
	print "The next " . $todo_count . " todos:\n";
	print color 'reset';
	
	#while there are todos left and while we have displayed under the specified amount
	while ($todos-&gt;nextTodoId &amp;&amp; $count++ &lt;= $todo_count){
		my @temp = $todos-&gt;get_tags;
		foreach (@temp){
			$_ = "none" if $_ eq "";
			$tags{$_} = [] if not defined $tags{$_} and not $todos-&gt;isDone;
			#the following will produce duplicate events if a todo has more than one tag
			push @{$tags{$_}}, $todos-&gt;get_title unless $todos-&gt;isDone;
		}
	}

	#print them
	my $found = 0;
	while (my ($tag, $todo) = each %tags){
		print "\u$tag:\n";
		foreach (@{$todo}){
			print "\t$_\n";
		}
		print "\n";

		$found = 1;
	}

	if (not $found){
		print "None!\n";
	}
}

=head1 NAME

Terminal 30 Boxes

=head1 DESCRIPTION

Uses WebService::30Boxes::API to nicely display events and data on the terminal.

You can use this to display your agenda every time you open the terminal.
Usage: cat /path/to/auth_token /path/to/api_key | perl /path/to/30boxes.pl -w 2 -t 10
This displays the events for the next 2 weeks and the first 10 tasks.
auth_token and api_key both contain only one line with the respective information.

=head1 README

THIS SOFTWARE DOES NOT COME WITH ANY WARRANTY WHATSOEVER. USE AT YOUR OWN RISK.

I wrote this script so that every time I opened a terminal window the 30 Boxes agenda 
and the a number of tasks would be displayed. Please email me at chitoiup@umich.edu with
feature requests and bugs. 
Enjoy!

=head1 PREREQUISITES

This script requires the C&lt;strict&gt; module.  It also requires
C&lt;WebService::30Boxes::API&gt;

=head1 COREQUISITES

CGI
DateTime
DateTime::Duration
Term::ANSIColor

=pod OSNAMES

any

=pod SCRIPT CATEGORIES

Web

=cut

</pre></body></html>