How to build a Twitter Bot that recommends movies
Tags: twitter, node, bot, fun
Published: 2020-04-03 21:05:27

I love films. I love recommending films to watch. I also love when people ask for my recommendations on what to watch. But sometimes this can become a little tedious, so a couple of months ago I started building a bot that recommends random (and good) movies when you mention it on Twitter. That's how [@nosequever](https://www.twitter.com/nosequever) was born.

 This is a simple guide on how to do it:

First let's install all the dependencies we'll use to build our bot. These are:

- **[Twit](https://github.com/ttezel/twit):** it's a Twitter API client for Node.js. We'll use this client to "listen" for mentions in our account, and to tweet a response with our recommendation.
- **[Axios](https://github.com/axios/axios):** an HTTP client for Node.js. This client will allow us to do a GET request to the TMDb API to get our random movie to recommend.

To install these dependencies, run inside your project's directory:

```shell
    $ npm install --save twit axios
```

Once you've all our dependencies installed, we need to get all the credentials for the API's we'll be using: the [Twitter API](https://developer.twitter.com/apps) and the [TMDb API](https://developers.themoviedb.org/3). Let's create a `config.js` file and paste those credentials:

```javascript
    module.exports = {
      // Add your Twitter API Credentials
      twitter_api: {
        consumer_key: '',
        consumer_secret: '',
        access_token: '',
        access_token_secret: ''
      },
      // Add the ID of the user you want to track
      // You can find the ID of a twitter user in http://gettwitterid.com/
      twitter_user_id: '',
      // Add your TMBb API Credentials
      movies_database_api_key: ''
    }
```

Now we're ready to start building our bot! First, let's create an *asynchronous* function that returns the movie we'll recommend. This function will make a GET request to the TMDb API to retrieve a movie based in certain search parameters: a minimum number of votes and a minimum average score. In theory this will allow us to recommend only "good" movies, but it can fail (yes, we're talking to you **Green Book**). This request will return an array with different movies, and our recommendation we'll be a random index of that array.

```javascript
    const config = require('./config')
    const Twit = require('twit')
    const axios = require('axios')
    
    // This will return the string with
    // the recommended movie. If something
    // goes wrong, returns an error message to tweet.
    const getRecommendedMovie = async () => {
      const tmdbApiKey = config.movies_database_api_key 
      const listPage = Math.floor(Math.random() * 234) + 1
      const minimumVotes = 50
      const minimumScore = 7
      const requestURL =
        'https://api.themoviedb.org/3/discover/movie?api_key=' +
        tmdbApiKey +
        '&language=en-US&sort_by=vote_average.desc&include_adult=false&include_video=false&page=' +
        listPage +
        '&vote_count.gte=' +
        minimumVotes +
        '&vote_average.gte=' +
        minimumScore
    
      // Stores the GET request into a variable
    	// that we'll return
      const recommendedMovie = await axios
        .get(requestURL)
        .then((response) => {
          if (response.status === 200) {
            const moviesList = response.data.results
            const listLength = moviesList.length
            const randomIndex = Math.floor(Math.random() * listLength) + 1
    
            // Yayy! We've our random movie to recommend!
            const recommendedMovie = moviesList[randomIndex]
    
            // Now, let's start putting together
            // the string to tweet to the user
            const movieID = recommendedMovie.id
            const movieTitle = recommendedMovie.title
            const movieReleaseYear = recommendedMovie.release_date.split('-')[0] // We just want the year
            const movieURL = 'https://www.themoviedb.org/movie/' + movieID
    
            // We'll tweet this to the user
            const tweet =
              ' today you could watch ' +
              movieTitle +
              ' (' +
              movieReleaseYear +
              '). More info: ' +
              movieURL
            return tweet
          }
        })
        .catch(() => {
          return ' seems like something went wrong 💔. Try again in a few minutes!'
        })
    
      return recommendedMovie
    }
```

Alright! We've our movie recommendation. That was easy, wasn't it?

Now we need to initialize a Twit instance to "listen" for mentions in our account. If we're mentioned, we'll post a tweet in reply with our recommendation. 

If you check Twit's documentation, in order to initialize an instance of it we need to pass our Twitter API credentials as a parameter. Once it's initialized we'll use the `stream()` method to filter Twitter's public stream to search for mentions in our account, by using our Twitter account ID. Then, we can finally reply to that mention with our recommendation ❤️.

```javascript
    const config = require('./config')
    const Twit = require('twit')
    const axios = require('axios')
    
    // This will return the string with
    // the recommended movie. If something
    // goes wrong, returns an error message to tweet.
    const getRecommendedMovie = async () => {
      const tmdbApiKey = config.movies_database_api_key // Your TMDb api key goes here
      const listPage = Math.floor(Math.random() * 234) + 1
      const minimumVotes = 50
      const minimumScore = 7
      const requestURL =
        'https://api.themoviedb.org/3/discover/movie?api_key=' +
        tmdbApiKey +
        '&language=en-US&sort_by=vote_average.desc&include_adult=false&include_video=false&page=' +
        listPage +
        '&vote_count.gte=' +
        minimumVotes +
        '&vote_average.gte=' +
        minimumScore
    
      // Does a GET request to the TMDb API
      // to get the random movie data
      const recommendedMovie = await axios
        .get(requestURL)
        .then((response) => {
          if (response.status === 200) {
            const moviesList = response.data.results
            const listLength = moviesList.length
            const randomIndex = Math.floor(Math.random() * listLength) + 1
    
            // Yayy! We've our random movie to recommend!
            const recommendedMovie = moviesList[randomIndex]
    
            // Now, let's start putting together
            // the string to tweet to the user
            const movieID = recommendedMovie.id
            const movieTitle = recommendedMovie.title
            const movieReleaseYear = recommendedMovie.release_date.split('-')[0] // We just want the year
            const movieURL = 'https://www.themoviedb.org/movie/' + movieID
    
            // We'll tweet this to the user
            const tweet =
              ' today you could watch ' +
              movieTitle +
              ' (' +
              movieReleaseYear +
              '). More info: ' +
              movieURL
            return tweet
          }
        })
        .catch(() => {
          return ' seems like something went wrong 💔. Try again in a few minutes!'
        })
    
      return recommendedMovie
    }
    
    // Our bot object
    const bot = new Twit(config.twitter_api)
    const myAccountId = config.twitter_user_id
    
    // Twitter's public stream
    const stream = bot.stream('statuses/filter', { follow: myAccountId })
    
    // Every time our account receives a tweet,
    // the `stream` object will run a function
    // to verify if the tweet it's a mention
    stream.on('tweet', async (eventMsg) => {
      if (eventMsg.in_reply_to_screen_name === 'nosequever') {
        const userToMention = eventMsg.user.screen_name
        const toTweet = '@' + userToMention + ' ' + (await getRecommendedMovie()) // Remember getRecommendedMovie() it's asynchronous
        const tweetParams = {
          status: toTweet,
          in_reply_to_status_id: eventMsg.id_str,
        }
    
        // 🎉🎉 Tweets the recommendation 🎉🎉
        bot.post('statuses/update', tweetParams)
      }
    })
```

🎉 IT'S ALIVE 🎉

You can test it by running `node app.js` and then mentioning your bot account on Twitter. If you want it to run *forever* (wink, wink) you'll need to start a `forever` process in your `app.js`. You can do this by installing [forever](https://github.com/foreversd/forever) like this:

```shell
    $ npm install --save forever
```

And then running

```shell
    $ forever start app.js
```

✨ That's it! You've successfully created a bot on Twitter ✨

Feel free to [clone this project](https://gitlab.com/tomasperalta/pelibot) and make any improvements you want. You can even make a pull-request to add some features! 

Hope you liked it. If you have any questions, you can ask me for help on Twitter at any time :)

Stay home, stay safe!