A bot program for Twitter, written in simple Bash script
MIT License
This bot watches events around the related your Twitter account, and will react to them.
You need to prepare API keys at first. Go to the front page, create a new app, and generate a new access token.
If you want to use DMs to control the running bot, you have to permit the app to access direct messages.
There are installer and uninstaller for systemd. Run sudo path/to/tweetbot.sh/systemd/install.sh
or sudo path/to/tweetbot.sh/systemd/uninstall.sh
.
$ ./watch.sh
You don't have to specify any option. This program automatically detects required data files from the base directory, it is same to the working (current) directory by default.
The base directory can be supplied via an environment variable TWEET_BASE_DIR
, like:
$ env TWEET_BASE_DIR=/home/username/data /path/to/watch.sh
This script detects data files and directories from the base directory (the current directory or the directory specified via an environment variable TWEET_BASE_DIR
).
The base directory should have them:
$TWEET_BASE_DIR/tweet.client.key
: the definition of API keys. This is always required.$TWEET_BASE_DIR/personality.txt
(optional): configures the strategy of the bot.$TWEET_BASE_DIR/responses
(optional): a directory to put response messages.$TWEET_BASE_DIR/monologues
(optional): a directory to put monologue messages.If you permit accessing to direct messages for the app, you'll prepare following files also:
$TWEET_BASE_DIR/on_response_modified.*
(optional): a callback script to be executed when any response message is changed dynamically.$TWEET_BASE_DIR/on_monologue_modified.*
(optional): a callback script to be executed when any monologue message is changed dynamically.$TWEET_BASE_DIR/on_command.*
(optional): a callback script providing user-defined commands via DMs.And, after you start the watch.sh
, following files and directories will be saved under the base directory automatically:
$TWEET_BASE_DIR/responder.sh
: a script to output one of response message by the given input.$TWEET_BASE_DIR/monologue_selector.sh
: a script to output one of monologue message by the given time (or the current time).$TWEET_BASE_DIR/logs
: a directory to store logs.$TWEET_BASE_DIR/.status
: a directory to store caches and status files.tweet.client.key
Put informations of a generated API key, with the format:
MY_SCREEN_NAME=xxxxxxxxxxx
MY_LANGUAGE=xx
CONSUMER_KEY=xxxxxxxxxxxxxxxxxxx
CONSUMER_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACCESS_TOKEN_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
personality.txt
This file defines behaviors of the bot. The default configurations are:
WATCH_KEYWORDS=''
FOLLOW_ON_FOLLOWED=true
FOLLOW_ON_MENTIONED=true
FOLLOW_ON_QUOTED=true
FOLLOW_ON_RETWEETED=false
SPAM_USER_PATTERN='follow *(back|me)'
FAVORITE_MENTIONS=true
FAVORITE_QUOTATIONS=true
FAVORITE_SEARCH_RESULTS=true
RETWEET_MENTIONS=false
RETWEET_QUOTATIONS=true
RETWEET_SEARCH_RESULTS=true
RESPOND_TO_MENTIONS=true
RESPOND_TO_MULTIPLE_TARGETS_MENTIONS=false
RESPOND_TO_QUOTATIONS=true
RESPOND_TO_SEARCH_RESULTS=true
FREQUENCY_OF_CAPRICES=66
NEW_TOPIC=66
CONVERSATION_PERSISTENCE=40
MONOLOGUE_INTERVAL_MINUTES=60
MONOLOGUE_TIME_RANGE_GROUPS="morning/06:00-07:00 \
noon/12:00-13:00 \
afternoon/15:00-15:30 \
evening/17:30-18:30 \
night/19:00-21:00 \
midnight/23:00-24:00,00:00-03:00"
ADMINISTRATORS=''
This file must be encoded in UTF-8.
WATCH_KEYWORDS
defines keywords to be watched with the format:
WATCH_KEYWORDS='Bash, ShellScript, Twitter'
It is a string of a comma-separated list.
Keywords are treated like conditions with the OR
logical operator.
Any tweet matched to one of given terms will be detected and treated as "mention" (including "reply"), "quotation", "retweet", or "search result".
These parameters define the strategy to follow other users. By these configurations, this bot will follow the follower back or follow the author of detedted tweets (mentions, quotations, or RTs).
FOLLOW_ON_FOLLOWED=true
FOLLOW_ON_MENTIONED=true
FOLLOW_ON_QUOTED=true
FOLLOW_ON_RETWEETED=false
And, you can define blacklist filter to ignore spam accounts. The pattern is evaluated as an extended regular expression.
SPAM_USER_PATTERN='follow *(back|me)'
These parameters define the strategy to favorite tweets by other users. By these configurations, this bot will favorite detected tweets (mentions, quotations, or search results).
FAVORITE_MENTIONS=true
FAVORITE_QUOTATIONS=true
FAVORITE_SEARCH_RESULTS=true
These parameters define the strategy to retweet tweets by other users. By these configurations, this bot will retweet detected tweets (mentions, quotations, or search results).
RETWEET_MENTIONS=false
RETWEET_QUOTATIONS=true
RETWEET_SEARCH_RESULTS=true
These parameters define the strategy to reply for tweets by other users.
RESPOND_TO_MENTIONS=true
RESPOND_TO_SIDE_MENTIONS=false
RESPOND_TO_MULTIPLE_TARGETS_REPLY=false
RESPOND_TO_QUOTATIONS=true
RESPOND_TO_SEARCH_RESULTS=true
For mentions, this bot always respond to it as a reply.
Otherwise, if the tweet is not a mention (including @username
for your account), this bot will post an independent tweet including the URL of the detected tweet - in other words, retweet it with a comment.
If you want to reply a mention not starting with @username
, set RESPOND_TO_SIDE_MENTIONS
to true
.
By default, the bot doesn't respond to replied mentions with other people like @username1 @username2 @username3 message body
to prevent unexpected spamming.
If you want to reply to such mentions aggressively, set RESPOND_TO_MULTIPLE_TARGETS_REPLY
to true
.
If someone mentions to the bot, it will replies to the mention always. However, the length of a conversation is undetermined and the bot continues to talk with any luck.
FREQUENCY_OF_CAPRICES=66
The parameter FREQUENCY_OF_CAPRICES
defines how often become tired on the current topic, between 0
(never tired forever) and 100
(tired just with a response).
If the parameter has a large value, the bot seems to be restless.
NEW_TOPIC=66
The parameter NEW_TOPIC
defines how often start new topic after tired, between 0
(never start new topic) and 100
(always start new topic).
If the parameter has a large value, the bot seems to have much curiosity.
CONVERSATION_PERSISTENCE=40
The parameter CONVERSATION_PERSISTENCE
defines how often continue the current topic without tired, between 0
(never continue to talk) and 100
(continue to talk forever).
If the parameter has a large value, the bot seems to be inquisitive.
This bot can post monologue tweets with intervals without any cronjob.
The timer counts up from 00:00
and the bot tries to post a monologue for every N minutes specified by the parameter MONOLOGUE_INTERVAL_MINUTES
(minimum interval = 10 minutes).
MONOLOGUE_INTERVAL_MINUTES=60
However, the actual timing of the monologue tweet has a margin.
The shorter one of "10 minutes" or "the 1/3 of the interval" is the margin, and this bot will post a monologue based on calculated probabilities.
For example, if you specify the interval as 60
, then the probabilities of the timing when the monologue will be actually posted is:
Monologue messages are loaded from definition files, and you can define some special time range with the MONOLOGUE_TIME_RANGE_GROUPS
parameter.
MONOLOGUE_TIME_RANGE_GROUPS="morning/06:00-07:00 \
noon/12:00-13:00 \
afternoon/15:00-15:30 \
evening/17:30-18:30 \
night/19:00-21:00 \
midnight/23:00-24:00,00:00-03:00"
It is space-separated list of time range definitions with the format: (name-of-the-range)/(beginning-1)-(end-1),(beginning-2)-(end-2),...,(beginning-N)-(end-N)
You can define special monologue messages for each special time range.
The parameter ADMINISTRATORS
defines a comma-separated list of administrators who permitted to control the bot via DMs.
ADMINISTRATORS='your_account, your_project_partner'
For more details, see following sections.
All files in the responses
directory are response message definition files.
They have same format described below.
A definition file has two sections: keywords and messages.
Lines starting with #
define keywords.
Others define messages.
Typical contents of a definition file are here:
(002-good-afternoon.txt)
# hello
# hi|hey
# good afternoon
# yo
Hi!
Hello!
Aloha!
Ola!
A keyword can be an extended regular expression. A definition file with no keyword definition line will be simply ignored.
When the bot detects a mention or reply from another user, it finds a definition file which has a keyword definition matches to the body of the tweet. Then, one of defined messages are posted as a reply for the mention.
This file must be encoded in UTF-8.
A definition file with no message definition line will become a "block list". For example:
(000-blocklist.txt)
# f(xx|uc)k
# shit
# suck
If the body of a mention matches one of keywords in blokc lists, then the bot never follow, favorite, retweet, and replies to the mention.
The bot scans all definition files with the order sorted by their filename.
You must put block list files before other regular definition files.
For example, 000-blocklist
and 100-greeting.txt
.
For a mention which is not matched to any keyword, this bot generates a random message from sources. These special definition files are used to generate those default responses:
watch.sh
scans all existing definition files on its startup, however, new keywords and definition files added after the watch.sh
is started won't be loaded.
If you modify keyword definitions while the bot is running, you have to regenerate responder.sh
manually, by running the script generate_responder.sh
as:
$ cd $TWEET_BASE_DIR
$ /path/to/tweetbot.sh/generate_responder.sh
or
$ env TWEET_BASE_DIR=/path/to/data/directory /path/to/tweetbot.sh/generate_responder.sh
All files in the monologues
directory are monologue message definition files.
They have same format described below.
A definition file contains messages. All lines define messages. Typical contents of a definition file are here:
(all-greeting.txt)
# comment
Hi! I'm a chatterbot. Please talk with me!
Yeah! I'm a chatterbot. Please talk with me!
Did you know? I'm a chatterbot!
All comment lines starting with #
are ignored.
If you want to post multiple tweets sequentially, write them in one line delimiting with \t
(\u0009
, hard tab).
This file must be encoded in UTF-8.
You can specify activation dates for each definition file, like:
# date: 2016.01.01-2016.01.10
Happy new year!
Hi, happy new year!
Wildcard is also available. For example:
# date: *.01.01-*.01.10
will be useful for messages like "happy new year" for every year.# date: *.*.01-*.*.03
will be useful for messages like "hey, don't forget to do the monthly task!" for every month.The bot will choose one of messages from all files which have same prefix like all
.
There is no order.
All definition files are used by the order:
timely
group. It will be used with the probability 20%.MONOLOGUE_TIME_RANGE_GROUPS
for the time range.all
group.watch.sh
scans all existing definition files on its startup, however, new messages and definition files added after the watch.sh
is started won't be loaded.
If you modify definitions while the bot is running, you have to regenerate monologue_selector.sh
manually, by running the script generate_monologue_selector.sh
as:
$ cd $TWEET_BASE_DIR
$ /path/to/tweetbot.sh/generate_monologue_selector.sh
or
$ env TWEET_BASE_DIR=/path/to/data/directory /path/to/tweetbot.sh/generate_monologue_selector.sh
If your screen name is listed in the ADMINISTRATORS
, you can control the bot via DMs dynamically.
You simply have to send DMs like following:
+res greeting Good morning!
post @friend Thank you!
echo
: returns an echo of the given message.test
: returns a response for the given message.+res
/ -res
: adds/removes keyword and message definitions for responses.+(name of a time range group)
/ -(name of a time range group)
: adds/removes message definitions for monologue.tweet
/ post
: posts the given message as a regular tweet of the bot.reply
: posts the given message as a reply by the bot.del
/ delete
/ rem
/ remove
: removes the specified tweet of the bot.rt
/ retweet
: retweets the given tweet by the bot.fav
/ favorite
: add favorite to the given tweet by the bot.follow
: follow the user.search-result
: treats the given tweet as a search result.run
: executes user defined commands.echo
: returns an echo of the given message.echo Hello
echo OK?
Simply returns the given message (except the command name echo
).
test
: returns a response for the given message.echo Hello
echo OK?
Treats the given message as a fake mention and returns actual response message.
+res
: adds keyword and message definitions for responses.+res Hello > Ola Hi! I'm fine!
Hello
Ola
Hi! I'm fine!
+res Hello > Ola
Hello
Ola
+res Hello Hi! I'm fine!
Hello
Hi! I'm fine!
This command registers new keyword, valiation of the keyword, and a response message. Both valiation and message are optional.
-res
: removes keyword and message definitions for responses.-res Hello > Ola Hi! I'm fine!
Hello
Ola
Hi! I'm fine!
-res Hello > Ola
Hello
Ola
-res Hello Hi! I'm fine!
Hello
Hi! I'm fine!
-res Hello 10
Hello
10
, so, the tenth message in the definition file will be removed.This command unregisters an existing keyword, valiation of the keyword, and a response message. Both valiation and message are optional.
+(name of a time range group)
: adds message definitions for monologue.+all > everytime Did you know? I'm a chatterbot!
all
everytime
Did you know? I'm a chatterbot!
+all > everytime
all
everytime
+morning Good morning!
morning
Good morning!
This command registers new monologue and alias of the time range group. Both alias and message are optional.
-(name of a time range group)
: removes message definitions for monologue.-all > everytime Did you know? I'm a chatterbot!
all
everytime
Did you know? I'm a chatterbot!
-all > everytime
all
everytime
-morning Good morning!
morning
Good morning!
-morning 10
morning
10
, so, the tenth message in the definition file will be removed.This command unregisters an existing monologue and alias of the time range group. Both alias and message are optional.
tweet
/ post
: posts the given message as a regular tweet of the bot.tweet Thank you, my friends!
reply
: posts the given message as a reply by the bot.reply 0123456 @friend Sorry, that's a bug of this chatterbot...
del
/ delete
/ rem
/ remove
: removes the specified tweet of the bot.del 0123456
rt
/ retweet
: retweets the given tweet by the bot.rt 0123456
follow
: follows the user by the bot.follow piro_or
follow https://twitter.com/piro_or/status/838626584663748608
unfollow
: unfollows the user by the bot.unfollow piro_or
unfollow https://twitter.com/piro_or/status/838626584663748608
search-result
: treats the given tweet as a search result.search-result 0123456
When you realized that there is a tweet which should be tracked as a search result but actually not processed, you'll want to add new response keywords and the existing tweet is processed as a new search result. This command just does it. Note that the feature possibly process the tweet multiple times.
run
: executes user defined commands.run list
run update
If there is any executable file named with the prefix on_command
(like on_command.sh
, on_command.rb
, etc.), it is kicked by the DM command run
with two arguments: the screen name of the sender, and the message body.
This is a sample script to implement run list
command to return all file names in the responses
directory:
#!/usr/bin/env bash
sender="$1"
command="$2"
tweet_sh='tweetbot.sh/tweet.sh/tweet.sh'
list_responses() {
list="$(cd responses &&
ls * |
sort |
sed 's/.txt$//' |
paste -s -d ',')"
echo "list: $list"
"$tweet_sh" dm $sender "$list" > /dev/null
}
case "$command" in
list* )
list_responses
;;
esac
If there is any executable file named with the prefix on_response_modified
(like on_response_modified.sh
, on_response_modified.rb
, etc.), it is kicked by DM commands +res
and -res
.
For example, this is a sample script to do following:
300_
.#!/usr/bin/env bash
find responses -name "autoadd_*" | while read path
do
mv "$path" "$(echo "$path" | sed 's/autoadd_/300_/')"
done
git add responses
git commit -m "Add new response"
git push
If there is any executable file named with the prefix on_monologue_modified
(like on_monologue_modified.sh
, on_monologue_modified.rb
, etc.), it is kicked by DM commands +(tine range)
and -(tine range)
.
For example, this is a sample script to do following:
#!/usr/bin/env bash
git add scheduled
git commit -m "Add new monologue"
git push