Return to the main TTYtter page

TTYtter Advanced Usage: FOR LEGACY VERSIONS ONLY

Version 1.0.x changes backwards compatibility! Do not use this document for current versions of TTYtter! While many extensions will still work, some will need to be updated for 1.0.0's multi-module system, and still others will need updates for future state serialization support. 0.9.12 is the last version to completely support the original TTYtter API in the manner described below. If you want to create extensions for the current version, go to the main page.

Using the TTYtter API, you can considerably customize how the client interacts with you and displays tweets and direct messages, as well as use ttytter as a rapid-deployment engine to construct Twitter bots. ttytter takes care of posting and receiving tweets and DMs, and your application can supersede as much or as little functionality as it needs to. You don't even need to write loops or handle any actual transactions with the Twitter server.

Please note that certain options or API operations are limited to certain minimum versions. The API does not exist in TTYtter versions prior to 0.4. Operations requiring a minimum version of TTYtter later than this will be specified.

Here are the command line options relevant to the API (see the full list of command-line options):

-lib=[library path] (optional)
Specifies the library to use for custom handlers and setup. The library is directly required by ttytter and becomes part of it. Your library must return a true value at the end (an idiom like 1; as the last line will suffice nicely). If the path of the specified library is not guaranteed to be in @INC, a fully qualified filespec would be a good idea.

The actual "methods" and globals you can and must use are discussed below, but I strongly advise reading this whole page first.

-daemon (optional)
Forces ttytter to run as a "detached" process in the background (the PID of the new background process is reported). If no library is given, then this is as if one were running the regular background update process, but without a console process (so updates continue to appear, but you must use a command line incantation like ttytter -status=... or something similar to actually post, as you are in your shell and not TTYtter). You must kill the process manually to shut it down.

If a library is defined, then this is the basis of how to construct a fully automated bot. We'll talk more about this below.

-twarg=[argument] (optional, 0.7.0+)
Specifies a user-defined argument string, allowing you to pass data to your extension library from outside of TTYtter.

-silent might also be handy for independent bots (optional, 0.6.0+).

If your bot is passive and doesn't need to post, it may be helpful and quite a bit faster to run it in anonymous mode with -anonymous (optional, 0.7.0+). This will not work for the examples below that generate tweets.

I have always found it easiest to learn by example, so let's look at three simple but useful examples before we get to the API reference. It will make a lot more sense if this is your first time.

Before getting started: Scripting (0.8+)

Sometimes you don't have to write an extension at all. If you are simply requesting data that you can get with regular TTYtter commands, and you have 0.8.0+, then simply scripting TTYtter would be enough. Suppose you just wanted to find out the last 20 tweets of user twitterapi and then grep it for something:

echo "/again twitterapi" | ttytter -script -anonymous | grep -i banana

Or, maybe you want to find Japanese wannabe poets (0.9.4+):

echo "/search #haiku" | ttytter -script -anonymous

The -script argument, as you will recall, disables automatic updates, sets -silent, and disables ANSI colour and other settings inappropriate for not-a-terminal.

In the above example, if you're simply interested in fetching specific types of tweets or filtering out others, a -filter option and a set of hashtags could be all you require. See Command-line options.

Obviously, you are not limited to single commands; you could have an entire command file if you like, and just pass that in with redirection or as an argument (ttytter -script my_script_file).

Remember that if you want to wait for all processes to finish emitting data before ending the script, you must end your file with /end (or end-of-file will be seen as /quit and all pending queued asynchronous commands will be cancelled). For example, this does not work:

echo "/a" | ttytter -script # THIS DOES NOT WORK

You need to rewrite it like this (here using the printf command):

printf "/a\n/end\n" | ttytter -script

which sends the /again and then makes the console wait until the asynchronous command has finished (/end). In particular, remember that /again (without arguments), /refresh, /dmrefresh and /dmagain are all asynchronous. But you could stack these commands (e.g.

printf "/a\n/dma\n/end\n" | ttytter -script

would fetch both your timeline and your direct messages, in order [tweets first, then DMs], and then wait for both tasks to finish). There is no harm in using /end for synchronous commands: it simply becomes an implied /quit. When in doubt, add it, especially if you are getting no output from a command.

Scripting is limited only to what commands the console understands, since basically you're driving the console. Similarly, it is difficult to hook error responses for any given particular command since the console does not offer this behaviour and thus scripted applications cannot be considered bulletproof. Thus, if you need to change TTYtter's behaviour in a way the console does not support, or need to write custom behaviour for enhanced reliability or fallbacks, you will need to use an extension -- which brings us to our first training-wheels, yet useful, example.

ARE YOU USING AN OLD VERSION? READ ME FIRST!: In the examples below, most of them will print to a filehandle reference $stdout instead of to STDOUT directly. This is the recommended practice starting in version 0.9.0 since $stdout may not directly point to the actual file descriptor for standard output, and may need to pass through filtering to support all the user's options. If you are writing for versions of TTYtter prior to 0.9, however, you should substitute STDOUT for $stdout in the following sections of code.

A first example: Displaying more tweet metadata

TTYtter throws away a lot of (in this context) irrelevant metadata by default when it formats tweets, but suppose you're interested in seeing a little more under the surface. Here is an example of a more florid way of displaying tweets. Place this into a separate file (example name: spammytweets.pl) and invoke it with ttytter -lib=spammytweets.pl or wherever you stored it:

$handle = sub {
        my $ref = shift;
        print $stdout ($ref->{'id'}, " ",
                &descape($ref->{'user'}->{'name'}), " ",
                &descape($ref->{'user'}->{'location'}), " ==> ",
                &descape($ref->{'text'}), "\n");
	return 1;
};

This introduces the general way of writing handlers: rather than having regular Perl subroutines, instead you assign anonymous subroutine references to specific global scalars (listed below). This particular subroutine reference, $handle, is called for every tweet that is to be displayed and is handed a hash reference containing the individual fields of the tweet.

Until 0.9.5, a peculiarity of the way ttytter handled JSON is that it adds certain unambiguous quote-escapes to aid it in interpretation. For those fields that are likely to have quote-escapes (free text fields, particularly), the library function &descape was used to turn ttytter's internal quote-escapes back into regular quotes.

After 0.9.5, changes to the JSON interpreter removed that need, but there are other conversion steps that &descape performs which you will still probably want, so you should still be calling this routine. It is not done automatically for you for reasons of efficiency, since it is not needed for fields you will not be displaying or digesting in your routine.

The handler returns 1 to tell ttytter that one logical tweet was handled. If it had declined to handle it for some reason, it should return zero.

Note that the library just ends. Any other setup that needs to be done should be done by the library before it exits. Because an anonymous subroutine reference is considered a "true" value, this small library does not need the 1; idiom at the end.

With this library running, suddenly ttytter's background updates take a new form:

92780182 Jenny How Malaysia ==> nice cold morning.. feels so lazy.... :)
92780192 Clifford Dog Desierto de Sonora Mexico ==> @ingridipity: huy que mal, espero que sea Cerveza Ligera ;)
92780202 Kelly Sims Torrance, Ca ==> also, the showcase on ee site is cool to see how others are using it

You can also use this with a script to fetch tweets and format them in a particular fashion, suitable for piping to something else; remember, using -script and -lib=... together is completely valid! This exercise is left for the reader.

An "enhanced" first example: A Twitter filter

Suppose you are only interested in one particular subject, let's say, bananas. It should be entirely obvious that you can filter on any term just by using a regular expression search on the relevant JSON field. Yes, you could just grep the output or use the -filter option, but this is another way:

$handle = sub {
        my $ref = shift;
	my $text = &descape($ref->{'text'});
	return 0 if ($text !~ /banana/i);
        print $stdout ($ref->{'id'}, " ",
                &descape($ref->{'user'}->{'name'}), " ",
                &descape($ref->{'user'}->{'location'}), " ==> ",
                $text, "\n");
	return 1;
};

Note that tweets that do not match up are not printed, and a zero is returned to alert TTYtter that the tweet was declined. Only if it actually is accepted (in this case for printing) is one returned.

The idea of "accepting" a tweet is more closely examined in the next example.

A second example: A Twitter logger

Naturally, you are not restricted merely to output. For those inclined towards blackmail, you can create a "logger" that not only displays the tweets it receives, but neatly organizes them into files:

$store->{'master'} = "$ENV{'HOME'}/twt.bookmark";
if(open(S, $store->{'master'})) {
        $last_id = 0+scalar(<S>);
        print $stdout "LIB: init last id: $last_id\n";
        close(S);
}

$handle = sub {
        my $ref = shift;
        return 0 if ($ref->{'user'}->{'protected'} eq 'true');

        my $sn = &descape($ref->{'user'}->{'screen_name'});
        my $string = &descape($ref->{'created_at'}) .
                " \@$sn " .
                &descape($ref->{'user'}->{'name'}) .
                " says: " .
                &descape($ref->{'text'}) . "\n";

	$sn =~ s#/#-#g;
        open(S, ">>", "${sn}.twt") ||
                die("can't open ${sn}.twt for append: $!\n");
        binmode(S, ":utf8") unless ($seven);
        print S $string;
        close(S);
        &defaulthandle($ref);
	return 1;
};

$conclude = sub {
        print $stdout "LIB: writing out: $last_id\n";
        if(open(S, ">".$store->{'master'})) {
                print S $last_id;
                close(S);
        } else {
                print $stdout "LIB: failure to write: $!\n";
        }
	&defaultconclude;
};

This library not only displays the tweets you receive, but it also organizes them into individual [screenname].twt files with date stamps and full names. It will not log users who are protected.

This more elabourate example also illustrates some other standard things:

Make the above into an automated logging bot "instantly"

It should be obvious that this could be made into a background bot simply by turning off the output you don't need to have displayed (i.e., either with the -silent option to suppress everything, or commenting out or deleting unneeded output lines like the LIB: output and &defaulthandle), starting ttytter with -lib=... and -daemon, and then letting the bot just slurp tweets out into files in the background. Presto, instant logging bot! Remember that even though no logical tweets are being displayed, they are still being accepted, so $handle should still return 1.

Make the above into a hashtag logger "instantly" (0.9.4+)

So, let's say you built the automated logging bot above, but you're having a conference or an interview between lots of people on Twitter (like #bigshindig). If you're following all those people, you could filter for the hashtag, and return 0 for tweets that don't contain it.

But say you're not following everyone in the conversation, or there are too many people to follow. In that case, turn off your timeline and then put the hashtag into $track. Then, you'll only see that hashtag. To do this, insert these lines at the very beginning:

$track = '#bigshindig';
$notimeline = 1;

A third example: A Twitter parrot

First, a word of warning: please don't actually run this, you will irritate a lot of people! This is a very silly example, but it will give you a basis on how to create interactive applications. It is intentionally broken so that it can't be used as is, but yet serve an educational purpose.

This library creates a Twitter parrot, which is to say any tweet it can see, it will tweet again. To avoid an endless loop, it determines the user it is running as and won't parrot back something it itself has said. (This example, therefore, will not work in anonymous mode.)

die("I can't run anonymously") if ($anonymous);

$store->{'dontecho'} = $whoami;
# if this fails, or we are prior to 0.7.0, we must split $user
($store->{'dontecho'}, $store->{'crap'}) = split(/:/, $user, 2)
	if (!length($whoami));

$handle = sub {
        my $ref = shift;
        my $sn = &descape($ref->{'user'}->{'screen_name'});
        return if ($sn eq $store->{'dontecho'});

        my $string = "\@$sn " . &descape($ref->{'text'});
        die("broken");
        &updatest($string);
        &defaulthandle($ref);
	return 1;
};

Most of this we have seen before, except for the global $whoami (and/or $user; be nice: the user's password may be there too, so behave please), and the subroutine &updatest, which is used to send a new status for the current user. It should be obvious to the reader that making a more interactive system is just a matter of parsing the text of the tweet, and then tweeting out a smarter or at least less aggravating response.

Third example redux: Making the parrot use direct messages instead

Or, you can make it much, much less aggravating by having it only talk to people who actually directly message it -- hence, surprise surprise, direct messaging support. Direct messaging operation is supported in 0.6 and higher, and is handled almost exactly the same way as regular tweets except that it uses $dmhandle instead. These changes to the above example should suffice:

[...]
$dmhandle = sub {
	[...]
        my $sn = &descape($ref->{'sender'}->{'screen_name'});
	[...]
        my $string = "D $sn " . &descape($ref->{'text'});
	[...]
};

Here, we query the screen name from the sender field, reply using the Twitter D command in a standard post, and return 1 to tell TTYtter that the direct message was accepted and acted upon. Note that only a minimal change in logic is required to make this happen on direct messages instead of public tweets and vice versa. The "anti-loop" logic isn't really needed here, but is nice to account for and won't harm anything either.

To make such bots effective and the communication bidirectional, essentially you must be following everyone who follows you. This can be done with the Twitter API in a programmatic, delayed fashion, but if you are doing this on a large scale you should speak with the Twitter developers (now is a good time to subscribe to twitter-development-talk).

An exercise for the reader: as written, just like in our logger example, every time the bot starts it will go through its most recent 20 DMs all over again, even if it had already processed them previously. Change this example to use a bookmark as well (hint: $dmconclude and $last_dm).

Tying it all together: a publicly-accessible TTYtter-powered application

It is also possible to drive TTYtter as a client instead of as a bot. @funkatron brought up a Gopher twitter interface on the Twitter development list, which being as I am a huge gopher fan (gopher URL) and a Twitter nut, sounded like a logical junction of two obsessions.

The result is Twitpher (gopher URL), a gateway that reads the public timeline or a specified user's timeline and displays it as a formatted gopher menu. If your browser cannot handle gopher URLs, here is a HTTP proxied link to see what it looks like.

 _          _ _        _            
| |___ __ _(_) |_ _ __| |_  ___ _ _ 
|  _\ V  V / |  _| '_ \ ' \/ -_) '_|
 \__|\_/\_/|_|\__| .__/_||_\___|_|  
Gopher-Twitter   |_|   gateway

Reload for most current tweets from the public timeline.  	 	 	
Click a tweet to see more from that user.
<Church_Mouse> I mourn the loss of my old house. It is cold and empty. And I have work to do. -- Wed Jan 09 04:11:21 +0000 2008
<darwinpr> Why won't I stop following Shel? Do I enjoy pain? -- Wed Jan 09 04:11:22 +0000 2008

Here is the source for the library, which will open in a new window so you can refer to it. It requires 0.7.0+. (This has been removed -- the new Twitpher is significantly different. You should really read the current API docs.)

Twitpher uses TTYtter as its client rather than running as a bot. It accomplishes this in the following ways:

Although this all sounds tremendously complex, the whole shooting match is just around 3K, much of which is prompts and text. I think it makes a fine example of how expressive you can be in a small space by using TTYtter as the back end for your Twitter application.

If you've created an application or bot that uses TTYtter, I would love to know about it and possibly include it in a list of TTYtter-powered applications. Please send a description to ckaiser@floodgap.com.

API reference

Superclassable subroutine references

These subroutine references can be used to replace or augment TTYtter behaviour. The default behaviour is always available using the &default* subroutine (e.g., the default $handle routine can be called with &defaulthandle). The default routine expects to be called with the same arguments the "super-routine" was called with.

The API is not available for TTYtter versions prior to 0.4. Subroutine references are specified with minimum supported version; if none is given, it is available in any version from 0.4 higher.

$addaction (argument 1: command line) (0.9.2+)
Called after initial commandline processing by the default console to allow the implementation of custom commands or to override internal commands (except /quit, etc., which obviously probably shouldn't be overridden). If the routine returns 0, then TTYtter assumes that the routine does not want or recognize the command line it was provided, and continues with processing. If the routine returns 1, then TTYtter assumes that the routine accepted (or at least wants to suppress further processing of) the command line for its own internal processing, and no further processing is done. Here is a simple, fairly useless example that implements /fubar and /ls commands:

$addaction = sub {
        my $command = shift;
        if ($command eq '/fubar') {
                print $stdout "You are teh FUBAR.\n";
                return 1;
        }
	if ($command =~ s#^/ls\s*##) {
		# leaving the argument in $command
		system("/bin/ls $command");
		return 1;
	}
        return 0;
};

Default behaviour is to return 0. This routine is one-way, i.e., if you rewrite the command line within $addaction, TTYtter will discard it and resume with its own copy. If you want to actually alter the command line itself and have TTYtter process that (e.g., macro or alias substitution), look at $precommand.

$authenticate (no arguments) (0.9.3+)
AS OF 0.9.4 THE $authenticate METHOD IS OFFICIALLY UNSTABLE AGAIN. Applications using this method may break when OAuth support is added to TTYtter, as this method will be used to handle generating signed OAuth requests. YOU ARE WARNED.

Look at the $user and $anonymous options, along with the selected user agent, and generate authentication credential options to send to that user agent. The &defaultauthenticate subroutine is designed to be a model; this routine checks that a username was specified, asks for a password if one were not specified, and then formats it into a command line option for either Lynx or cURL depending on which one is in use.

This could be used by Mac users, for example, to fetch credentials from the keychain. As reported by Uwe Dauernheim (not tested by me, since I don't routinely use the Mac OS X Keychain), here is one way you could fetch username and password using the security tool:

USER=`security find-internet-password -s "twitter.com" | grep "\"acct\"" | sed "s/.*\"acct\"<blob>=\"\(.*\)\".*/\1/"`
PASS=`security 2>&1 > /dev/null find-internet-password -gs "twitter.com" | sed "s/password: \"\(.*\)\"/\1/"`

Making this into a user $authenticate routine should be straightforward using &defaultauthenticate as a template, and is left as an exercise to the reader (if someone writes a working module, I will be very happy to post it here).

$autocompletion (argument 1: text to be completed, argument 2: state of current command line, argument 3: position within line of text to be completed) (0.9+)
Called, if readline mode is enabled, by the operating Term::ReadLine::* driver whenever TAB completion is needed. An array of fully-qualified likely choices is expected as a return value. For an example of how such a routine would operate, look at &defaultautocompletion. You should be familiar with Term::ReadLine to make the most of this hook.

$conclude (no arguments)
Called at the end of each cycle of tweet processing. Default behaviour is to do nothing additional (except in 0.9.3 and up, where the count from -filter is displayed if requested). Return value, if any, is discarded.
$console (no arguments) (0.6+)
Master loop to manage the console. Default behaviour is to initialize the history, print an initial prompt, and then accept data line by line from standard input until a terminating command is received or the input stream ends. Return value, if any, is discarded, and TTYtter will terminate completely when the routine is exited.

Nothing says your console routine actually has to take user input, by the way -- it can do its own thing and ignore standard input completely (see Twitpher above for an example of using the console for getting background timeouts for free). It can even drive the (real) console itself with its own commands in 0.9.4+ using &ucommand.

This hook can also be used to run code after initialization of the console but prior to accepting user input. If so, your code should end with something like goto &defaultconsole; to transparently return control to the default handler.

$dmconclude (no arguments) (0.6+)
Called at the end of each cycle of direct message processing. Default behaviour is to do nothing additional. Return value, if any, is discarded.
$dmhandle (argument 1: hash reference) (0.6+)
Called when a direct message is to be displayed or otherwise handled in some manner. The keys of the hash reference are based on those specified by the Twitter API. Note that as a side effect of Perl's interpretation of the JSON, logical true and false in Boolean fields are rendered as literal text true and false. The routine, naturally, is not obligated to generate any output if it desires. Default behaviour is to display screen name, time stamp provided by Twitter, and the text of the direct message. For success, the number of "logical DMs" handled (almost always one) should be returned. If the DM was declined for processing, a zero value should be returned.

In 0.8.0+, you can pass your hash reference to &standarddm for the "default" formatting, which will return a string formatted according to whatever standard options are set (such as -timestamp, -wrap, -ansi, etc.)

$exception (argument 1: exception number, argument 2: exception text)
Called when a non-fatal exception is received during processing of tweets. Argument 2 is guaranteed to be human readable text corresponding to argument 1, which comes more or less from this table:

The exception number code is provided simultaneously to facilitate localization or custom notification. Exceptions passed to $exception are designed to be informative only, as TTYtter can recover from these errors and automatically try again. Fatal errors are raised immediately and the library does not receive notification for technical reasons. Default behaviour is to print the error text to standard output. Return value, if any, is discarded.

Twitter is now using a generalized error reporting method to indicate server-based exceptions, including hitting the API rate limit. All of these errors are swallowed up under code 2; to distinguish them, check the error text. Although the old rate-limit trigger message is still parsed for, and can still theoretically generate code 3, this message has been replaced by the new reporting convention in practise.

Code 12 is no longer reported as a null list can be valid in some contexts. However, this is generally transparently intercepted silently for you in contexts that it is not.

$handle (argument 1: hash reference, [optional] argument 2: origination)
Called when a tweet is to be displayed or otherwise handled in some manner. The keys of the hash reference are based on those specified by the Twitter API. Note that as a side effect of Perl's interpretation of the JSON, logical true and false in Boolean fields are rendered as literal text true and false. The routine, naturally, is not obligated to generate any output if it desires. Default behaviour is to display the tweet formatted to standard options (in 0.8.0+, using &standardtweet [below]) with screen name and tweet text, and in 0.9.5+, with the tweet's menu code prepended. For success, the number of "logical tweets" handled (almost always one) should be returned. If the tweet was declined for processing, a zero value should be returned.

In 0.8.0+, you can pass your hash reference to &standardtweet for the "default" formatting, which will return a string formatted according to whatever standard options are set (such as -timestamp, -ansi, -wrap, etc.) In 0.9.5+, if ANSI is enabled, this is also affected by $choosecolour.

In 0.8.1+, an optional origination argument is also passed, giving the command that caused the tweet to be displayed. Origination classes defined currently are a null string, meaning a new tweet; replies meaning tweets from the /replies command; or again meaning old tweets usually from the /again command). The distinction is important; replies does not appear on new replies, but only on replies that you ask for. This is on purpose to ensure that API activity results are consistent and match up. Note that again overrides replies, and since /again can sometimes pull up new tweets, the originator is blanked on purpose for those new ones so they are properly seen as new. The complexity here is mostly intended for those clients who want to distinguish old and new tweets, or tweets that a user requested versus tweets that were automatically fetched, and handle them differently.

$heartbeat (no arguments) (0.6+)
Called at the beginning of each automatic refresh cycle (in either daemon or interactive mode). Default behaviour is to do nothing additional. Return value, if any, is discarded.
$precommand (argument 1: command prior to processing) (0.8.2+)
Called as soon as a command is received for processing, even before history substitution. Allows you to implement your own preprocessing. The new command should be returned as a single response, and is subject to things like % substitution and so on. Default behaviour is to just return the same command without further pre-substitution. Although you could also attempt to intercept and handle custom commands here too, $addaction is a better choice for that purpose.

$prepost (argument 1: tweet prior to posting) (0.8.2+)
$postpost (argument 1: tweet after posting) (0.8.2+)
These two are paired, so they are listed together. $prepost is called when a tweet is about to be URL-encoded and sent, allowing you to implement your own tweet preprocessor (such as, say, a translation or shortening service). The new tweet should be returned as a single response. After the tweet is posted, $postpost is called with the final tweet (which barring an act of God or cosmic radiation should be the same as what $prepost returned), which is useful for tools such as loggers. Default behaviour for the former is to simply return the same tweet without further pre-substitution, and for the latter, to do nothing.

$prompt (0.8.6 and prior, no arguments) (0.9.0 and following, [optional] argument 1: information only) (0.7+)
Called every time a prompt is to be displayed by the console. Default behaviour is to display TTYtter>, followed by a separating space. If ANSI colour is enabled, the prompt is displayed in cyan.

Starting in version 0.9.0, the prompt is only printed by the default handler if -readline is not enabled (otherwise the prompt is maintained by ReadLine). If optional argument 1 is true, then the prompt and its screen width (which may not be the same as its length) are returned as a list for interested subroutines. Starting in version 0.9.3, when the prompt is printed or requested, the wordwrap subroutine is hinted to use it in calculations by setting global $wrapseq to zero.

$tweettype (argument 1: hash reference, argument 2: screen name, argument 3: tweet text) (0.9.7+)
Called to determine what class a tweet should be (which should be returned as a string); DMs are discovered separately (there is no corresponding $dmtype). The four standard tweet classes are me reply search default; you could define other classes for use, say, with the notification framework (discussed below) or with your own custom $handle routine. To fall back on the standard tweet class selection, simply return &defaulttweettype($ref, $sn, $tweet) for ones you don't want to classify yourself.

Writing custom notification drivers (0.9.7+)

Your API extension can define a custom notification driver, which is handled differently from the above. In general, the argument to -notifytype=... is turned into a function name using the notifier_ prefix, e.g., -notifytype=growl indicates that the subroutine notifier_growl should be called for notifications. Thus, if you wanted to define, say, a notifier_email subroutines for E-mail notifications, then you invoke it with -notifytype=email after including it with -lib or -olib.

The notification subroutine is called in two ways: with no arguments (or more accurately, with a single argument of undef) during initialization, and thereafter with three arguments: the class (as determined by $tweettype), the tweet string as processed by &standardtweet as a convenience, and a hash reference to the tweet in case you want to format it yourself. Your routine will then handle the notification, and return. Return value, if any, is discarded.

The default drivers included (&notifier_growl and &notifier_libnotify) are instructive examples. Both are formatted in the same basic way: during initialization they seek out their required utilities (growlnotify and notify-send respectively) and store them in an appropriate global, and then as tweets are passed to the notifier they then pass them off to their dependent utility with the correct command line arguments on standard input.

Neither of the built-in drivers do anything special with the class currently. However, your driver may decide to in fact do special things with each class, and your customized $tweettype method, if you choose to write one, can tag tweets with new classes that your custom notification routine can handle (say, a class peter for tweets from your friend Peter; for those tweets, $tweettype would return 'peter', and you would add peter to your list of classes in -notifies=...). This is entirely supported, and you can of course simply fall through to &defaulttweettype for other tweets that are not from Peter to get default behaviour otherwise.

Note that notification routines are called only for new tweets; tweets identified as old do not get passed to the notifier to avoid ping-ponging.

Library routines

These routines are explicitly designated as available for calling from a user application. Other routines may also be utilized, but are not guaranteed to maintain compatible naming or calling convention in future versions. They are not overridable.

&descape (argument 1: data, [optional] argument 2: Unicode mode)
General text decoding routine. This single entry point is responsible for removing internal quote-escaping for entity data (all versions prior to 0.9.5) and HTML ampersand-entity encoding (0.5.1+), converting escaped UTF-8 characters into their correct/desired form (0.5.1+), and returning the de-escaped data. If the data contains UTF-8 entities and UTF-8 is disabled with -seven, then the entities are rendered as dots ('.'). The processed data is returned.

If optional argument 2 is true, then UTF-8 entities are rendered in HTML "ampersand" form, even if UTF-8 is "off." This is particularly useful for web applications. Starting in version 0.5.1, &descape will also convert many ampersand-escaped entities into ASCII as well, unless argument 2 is true (in which case it assumes that you wish them to remain ampersand-escaped like the UTF-8 entities will be).

&grabjson (argument 1: URL, [optional] argument 2: last ID, [optional] argument 3: don't authenticate)
Asks URL for a JSON data source, attempts to convert it into a Perl variable structure, and returns either a reference to a hash, reference to an array or a scalar, or an undefined reference if there was a problem. Severe or unexpected parsing errors cause an immediate fatal shutdown for security reasons. If optional argument 2 is true, then a since_id= is added to the request for you. Figuring out how to interpret the reference is your problem; however, &grabjson will do some normalization on the reference if it appears to be coming from the Search API to make it look like a regular Twitter API response. Starting with 0.9.4, if argument 3 is true, then authentication headers are not sent with the request.
&screech (argument 1: error text)
Emit error text to standard output (ring the bell if supported), and kill and shutdown immediately. Used as an escape hatch for unsafe situations, or fatal errors. Note that this bypasses $conclude, and as such, no further notification is given to the library that a fatal shutdown has occurred. This routine does not return.
&standardtweet, &standarddm (argument 1: hash reference) (0.8+)
These routines return the default pre-formatted string according to any user-specified arguments for a tweet or DM respectively indicated by the hash reference passed it. See $handle and $dmhandle respectively.
&ucommand (argument 1: console command) (0.9.4+)
Executes a command as if you had typed it at the console, even if you have hooked $console or are not using the console. This is particularly useful for modifying arguments in realtime, because certain command line arguments like $track have a pre-compilation step that is triggered by the /set command, for example.
&updatest (argument 1: status text, [optional] argument 2: interactive mode, [optional] argument 3: in reply to status ID)
Update the current user's status with status. If optional argument 2 is true, any error condition will also be displayed on standard output. If optional argument 3 is specified, then the posted tweet will have its in-reply-to value set to the specified ID (0.9.5+). A status value is returned: zero if the post was successful, or a return code dependent on Lynx or curl if not (see respective documentations). Return code 99 indicates that the subprocess could not even start, possibly due to change in the filesystem or permissions.

Exposed globals

These globals are explicitly designated as available or permissible for user operation and manipulation. Globals specific to the library itself should always use the prefix $Lib_. Manipulating other globals could interfere with normal TTYtter operation, and are not guaranteed to retain the same function or name in future versions.

$TTYtter_VERSION
The current major/minor version of TTYtter (currently a string containing a float value, but was previously a float value [so version 0.7 was represented as 0.7, but now 0.9 is "0.9"]). This doesn't include the patch level; see the next variable for that.
$TTYtter_PATCH_VERSION
The current patch level of this release of TTYtter, loaded into a separate scalar for backwards compatibility; although this was not defined prior to 0.5.1, the patch level of previous versions can be safely assumed to be patchlevel 0, and as such a nice idiom is to use (0+$TTYtter_PATCH_VERSION) which is guaranteed to give zero for old versions and will not bug out on current ones. This is an integer, so $TTYtter_VERSION 0.5 and $TTYtter_PATCH_VERSION 1 indicates version 0.5.1.
$url $lynx $curl $pause $user $seven $lib $daemon $verbose $script $ttytteristas $avatar $leader $noprompt $rc $superverbose $hold $status $update $dmurl $rlurl $frurl $shorturl $queryurl $trendurl $slowpost $verify $dmpause $silent $anonymous $ansi $readline $notimeline $colourprompt $coloursearch $colourdefault $favurl $favsurl $myfavsurl $favdelurl $colourme $colourdm $colourreply $colourwarn $track $filter $track $notrack $noansi $timestamp $uurl $rurl $wurl $maxhist $twarg
These are the manifestations of the valid command line options, set to their respective specified values (or 1 for true Boolean values). For the meanings of these options, see Command-line options.

A few of these options ($filter, $track) compile internal representations for speed, so changing these globals may not necessarily change behaviour.

$twarg is special as it is explicitly designated as user-defined, i.e., it's your way of passing external data or arguments into your code. Don't trust it, do sanitize it if you're not the source. It is available in 0.7+.

$whoami
The current screen name in use. It is populated automatically for you in 0.7+. It is not immediately instantiated, and in 0.9.3+ is in fact not instantiated until the $authenticate method has been executed, so you may still need to rely on $user for early initialization. Changing $whoami does not necessarily change the credentials sent by TTYtter.
$parent $child
The PID of the parent and child processes. In interactive mode, both are defined; in daemon mode, only the latter (the parent ID becomes zero). Neither should be modified, or processes may not get properly terminated.
$last_id
The last/highest tweet ID so far processed. It starts at zero, but may be advanced to skip tweets as $handle (or &defaulthandle where not specified) is only called for new tweets, viz., tweets with an ID higher than $last_id. Even if $handle returns zero for an arbitrary tweet, that tweet's ID is still considered for $last_id.
$last_dm
Analogously, the last/highest direct message ID so far processed. Its behaviour is exactly the same as $last_id, including starting from zero on startup, and even if $dmhandle returns zero for an arbitrary DM, that DM's ID is still considered for $last_dm.
$lasttwit (0.8.1+)
The last successful tweet (empty if no tweets have been made). This is not carried from session to session.
DUPSTDOUT (0.8+)
The DUPSTDOUT filehandle is defined in 0.8+ and allows you to emit to standard output even if everything else is being suppressed with -silent. As its name suggests, it is a simple dup(3) of standard output. -silent forces output to DUPSTDOUT, but only from &defaulthandle and &defaultdmhandle; everything else still goes to STDOUT.
$CCme $CCreply $CCdm $CCsearch $CCprompt $CCwarn (0.9.4+) $CCdefault (0.9.7+)
The surface manifestation of the -colour* command line options, viz., the actual printable terminal sequences. This is preferred rather than specifying exact colours when matching a particular tweet class.
Send comments and six-packs of Mr Pibb to ckaiser@floodgap.com, or return to the main TTYtter page.
Cameron Kaiser