Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Commit

Permalink
Merge pull request #30 from spences10/improve-user-blacklist
Browse files Browse the repository at this point in the history
Improve user blacklist
  • Loading branch information
spences10 committed Feb 14, 2017
2 parents a0bc0c1 + 6c63295 commit 37d24ca
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 66 deletions.
13 changes: 8 additions & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
CONSUMER_KEY=
CONSUMER_SECRET=
ACCESS_TOKEN=
ACCESS_TOKEN_SECRET=
SENTIMENT_KEY=
TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
TWITTER_ACCESS_TOKEN=
TWITTER_ACCESS_TOKEN_SECRET=
SENTIMENT_KEY=
TWITTER_USERNAME=
TWITTER_RETWEET_RATE=
TWITTER_FAVORITE_RATE=
52 changes: 43 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@

[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](http://standardjs.com/) [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](http://opensource.org/licenses/MIT)

<!-- TOC -->

- [Twitter bot bootstrap](#twitter-bot-bootstrap)
- [What you'll need](#what-youll-need)
- [Setup twitter](#setup-twitter)
- [Setup development environment](#setup-development-environment)
- [Set up the bot](#set-up-the-bot)
- [Project structure](#project-structure)
- [Node dependencies](#node-dependencies)
- [Heroku](#heroku)
- [Heroku CLI](#heroku-cli)
- [Heroku variables](#heroku-variables)
- [Heroku deployment via GitHub](#heroku-deployment-via-github)
- [Heroku troubleshooting](#heroku-troubleshooting)
- [Handy tip](#handy-tip)
- [Contributing](#contributing)
- [Links](#links)
- [License](#license)

<!-- /TOC -->

This is a bootstrap for setting up a Twitter bot with Node.js using the `twit` library. The bot will favorite and retweet what you specify when configuring it. It will also reply to followers with a selection of canned responses.

As a primer for this, there is a great post by [@amanhimself](https://twitter.com/amanhimself) on making your own twitter bot. This is an expansion on that with further detail on configuration on Heroku.

Before starting the clock you'll need to set up some accounts if you don't have them already.

## What you'll need

- Twitter account
Expand All @@ -31,6 +54,8 @@ You should now be in the 'Application Management' section where you will need to

For this I'm just going to say use [Cloud9](https://c9.io/) as you can be up and running in minutes with one of the pre made Node.js environments.

Note that if you choose to use Heroku and/or Cloud9 IDE in building this (like I do in this guide) in some regions you will be prompted to give a credit card number to create these accounts.

![](/src/images/c9-node-env.png)

## Set up the bot
Expand Down Expand Up @@ -91,7 +116,7 @@ Now you'll need to add your Twitter keys to the `.env` file. Just input the keys

If you can not find the `.env` file in the file structure of your c9 project then you will need to enable the **`Show Hidden Files`** option. In the file view select the settings cog then tick the `Show Hidden Files` option if it is not already checked.

![](/src/images/c9-hidden-files-check.png)
![](/src/images/c9-hidden-files-check.gif)

The `SENTIMENT_KEY` you can get a new API key at https://market.mashape.com/vivekn/sentiment-3 your key is in the `REQUEST EXAMPLE`

Expand All @@ -101,12 +126,19 @@ Take a look at the gif, click the link, sign up for or sing into `mashape`, clic

Add your API key to the `.env` file along with your Twitter API keys :key:

Here you should add your Twitter account name, and how often you want the bot to run the retweet and favorite functions in minutes.

>NOTE none of the `.env` items have quotes `''` round them.
```
CONSUMER_KEY=Fw***********P9
CONSUMER_SECRET=TD************Cq
ACCESS_TOKEN=31**************UC
ACCESS_TOKEN_SECRET=r0************S2
SENTIMENT_KEY=Gj************lF
TWITTER_USERNAME=DroidScott
TWITTER_RETWEET_RATE=5
TWITTER_FAVORITE_RATE=5
```

You can then add some keywords into the `strings.js` file for what you want to search for as well as sub-queries.
Expand All @@ -118,12 +150,6 @@ You can then add some keywords into the `strings.js` file for what you want to s

When adding sub-query strings make sure you leave a space at the beginning of the string so `' handy tip'` gets concatenated onto `'node.js'` as `node.js handy tip` and not `node.jshandy tip`.

Then add the username of the Twitter account you are using to the `tweetNow` function in the `bot.js` file. This will ensure your bot doesn't reply to itself when it has been followed by a user.

![](/src/images/c9-strings-config1.png)

This step isn't strictly necessary if this account isn’t going to be following any users.

That should be it. Go to the terminal, enter `npm start` and you should get some output:

![](/src/images/bot-output.png)
Expand Down Expand Up @@ -230,7 +256,6 @@ Go to the ‘Deploy’ dashboard on Heroku, select GitHub as the deployment meth

![](/src/images/heroku-connect-github.png)


## Heroku troubleshooting

What do you mean it crashed!?
Expand All @@ -246,7 +271,7 @@ $ heroku ps:scale worker=1

If that still crashes out then try setting the `Resources` on the Heroku dashboard, I found if you toggle between the `web`, `heroku` and `worker` it usually settles down. Basically you need to be set to the **`worker`** Dyno this is what causes the `Error R10 (Boot timeout)` crashes because it's trying to use one of the other resources when it should be using the **`worker`** Dyno.

![](/src/images/heroku-app-resources.png)
![](/src/images/heroku-app-resources.gif)

Other useful Heroku commands I use:

Expand All @@ -260,6 +285,15 @@ By default you can only push your master branch if you are working on a developm
$ git push heroku dev:master
```

## Handy tip
If you want to add this to your own GitHub repo and don't want to share your API keys :key: with the world then you should turn off tracking on the `.env` file. From the terminal enter this git command:

```
$ git update-index --assume-unchanged .env
```

I have added my most used git command I use in this [gist](https://gist.github.com/spences10/5c492e197e95158809a83650ff97fc3a)

## Contributing
Please fork this repository and contribute back using pull requests.

Expand Down
105 changes: 57 additions & 48 deletions src/bot.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
// Dependencies =========================
var Twit = require('twit')
var ura = require('unique-random-array')
var config = require('./config')
var strings = require('./helpers/strings')
var sentiment = require('./helpers/sentiment')

var Twitter = new Twit(config)

// Frequency in minutes
var retweetFrequency = 5
var favoriteFrequency = 5
const Twit = require('twit')
const ura = require('unique-random-array')
const config = require('./config')
const strings = require('./helpers/strings')
const sentiment = require('./helpers/sentiment')

const Twitter = new Twit({
consumer_key: config.twitter.consumerKey,
consumer_secret: config.twitter.consumerSecret,
access_token: config.twitter.accessToken,
access_token_secret: config.twitter.accessTokenSecret
})

// Frequency
const retweetFrequency = config.twitter.retweet
const favoriteFrequency = config.twitter.favorite
// username
const username = config.twitter.username

// RANDOM QUERY STRING =========================

var qs = ura(strings.queryString)
var qsSq = ura(strings.queryStringSubQuery)
var rt = ura(strings.resultType)
var rs = ura(strings.responseString)
let qs = ura(strings.queryString)
let qsSq = ura(strings.queryStringSubQuery)
let rt = ura(strings.resultType)
let rs = ura(strings.responseString)

// https://dev.twitter.com/rest/reference/get/search/tweets
// A UTF-8, URL-encoded search query of 500 characters maximum, including operators.
Expand All @@ -31,7 +38,7 @@ var rs = ura(strings.responseString)
// * recent : return only the most recent results in the response
// * popular : return only the most popular results in the response.

var retweet = function () {
let retweet = function () {
var paramQS = qs()
paramQS += qsSq()
var paramRT = rt()
Expand All @@ -42,15 +49,14 @@ var retweet = function () {
}

Twitter.get('search/tweets', params, function (err, data) {
// if there no errors
if (!err) {
// grab ID of tweet to retweet
if (!err) { // if there no errors
try {
// run sentiment check ==========
// grab ID of tweet to retweet
// run sentiment check ==========
var retweetId = data.statuses[0].id_str
var retweetText = data.statuses[0].text

// setup http call
// setup http call
var httpCall = sentiment.init()

httpCall.send('txt=' + retweetText).end(function (result) {
Expand Down Expand Up @@ -85,7 +91,7 @@ var retweet = function () {

// retweet on bot start
retweet()
// retweet in every x minutes
// retweet in every x minutes
setInterval(retweet, 1000 * 60 * retweetFrequency)

// FAVORITE BOT====================
Expand All @@ -103,39 +109,43 @@ var favoriteTweet = function () {

// find the tweet
Twitter.get('search/tweets', params, function (err, data) {
if (err) {
console.log(`ERR CAN'T FIND TWEET:`, err)
} else {
// find tweets
var tweet = data.statuses
var randomTweet = ranDom(tweet) // pick a random tweet
var tweet = data.statuses
var randomTweet = ranDom(tweet) // pick a random tweet

// if random tweet exists
if (typeof randomTweet !== 'undefined') {
if (typeof randomTweet !== 'undefined') {
// run sentiment check ==========
// setup http call
var httpCall = sentiment.init()
var favoriteText = randomTweet['text']
var httpCall = sentiment.init()
var favoriteText = randomTweet['text']

httpCall.send('txt=' + favoriteText).end(function (result) {
var sentim = result.body.result.sentiment
var confidence = parseFloat(result.body.result.confidence)
console.log(confidence, sentim)
httpCall.send('txt=' + favoriteText).end(function (result) {
var sentim = result.body.result.sentiment
var confidence = parseFloat(result.body.result.confidence)
console.log(confidence, sentim)
// if sentiment is Negative and the confidence is above 75%
if (sentim === 'Negative' && confidence >= 75) {
console.log('FAVORITE NEG NEG NEG', sentim, favoriteText)
return
}
})
if (sentim === 'Negative' && confidence >= 75) {
console.log('FAVORITE NEG NEG NEG', sentim, favoriteText)
return
}
})

// Tell TWITTER to 'favorite'
Twitter.post('favorites/create', {
id: randomTweet.id_str
}, function (err, response) {
Twitter.post('favorites/create', {
id: randomTweet.id_str
}, function (err, response) {
// if there was an error while 'favorite'
if (err) {
console.log('CANNOT BE FAVORITE... Error: ', err, ' Query String: ' + paramQS)
} else {
console.log('FAVORITED... Success!!!', ' Query String: ' + paramQS)
}
})
if (err) {
console.log('CANNOT BE FAVORITE... Error: ', err, ' Query String: ' + paramQS)
} else {
console.log('FAVORITED... Success!!!', ' Query String: ' + paramQS)
}
})
}
}
})
}
Expand Down Expand Up @@ -177,10 +187,9 @@ function tweetNow (tweetTxt) {
status: tweetTxt
}

// HARCODE user name in and check before RT
var n = tweetTxt.search(/@UserNameHere/i)
const screenName = tweetTxt.search(username)

if (n !== -1) {
if (screenName !== -1) {
console.log('TWEET SELF! Skipped!!')
} else {
Twitter.post('statuses/update', tweet, function (err, data, response) {
Expand Down
17 changes: 13 additions & 4 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
/** TWITTER APP CONFIGURATION
* Add your keys to the `.env` file
* consumer_key
* consumer_secret
* access_token
* access_token_secret
* Add your account user username
* Add your sentiment API key
*/
require('dotenv').config()

module.exports = {
consumer_key: process.env.CONSUMER_KEY,
consumer_secret: process.env.CONSUMER_SECRET,
access_token: process.env.ACCESS_TOKEN,
access_token_secret: process.env.ACCESS_TOKEN_SECRET
twitter: {
username: process.env.TWITTER_USERNAME,
consumerKey: process.env.TWITTER_CONSUMER_KEY,
consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessTokenSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
retweet: process.env.TWITTER_RETWEET_RATE,
favorite: process.env.TWITTER_FAVORITE_RATE
},
sentiment: process.env.SENTIMENT_KEY
}
Binary file added src/images/c9-hidden-files-check.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/images/c9-strings-config1.png
Binary file not shown.
Binary file added src/images/heroku-app-resources.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/images/heroku-app-resources.png
Binary file not shown.

0 comments on commit 37d24ca

Please sign in to comment.