<commit_before>"use strict";

// Local tweet test override.
var canTweetFromLocal = false;

// Load libraries.
var _ = require('underscore');
var wordfilter = require('wordfilter');
var SC = require('node-soundcloud');
var Twit = require('twit');

// Are we on production? Check if an important environment variable exists.
function isProduction () {
  return (typeof(process.env.TWITTER_CONSUMER_KEY) !== 'undefined');
}

// Use environment variables if we're on production, config files if we're local.
if (isProduction()) {
  var yandexKey = process.env.YANDEX_KEY;

  var twitter = new Twit({
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token: process.env.TWITTER_ACCESS_TOKEN,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  });

  SC.init({
    id:     process.env.SOUNDCLOUD_CLIENT_ID,
    secret: process.env.SOUNDCLOUD_SECRET
  });
}
else {
  var yandexConfig = require('./config/yandex-config.js'),
      yandexKey    = yandexConfig.key;

  var twitter = new Twit(require('./config/twitter-config.js'));

  SC.init(require('./config/soundcloud-config.js'));
}

// Load Yandex Translation API library.
var translate = require('yandex-translate')(yandexKey);

// Execute once upon initialization.
makeAndPostTweet();

// The main process. Get a useable comment and tweet it or try again.
function makeAndPostTweet () {

  getComment()
    .then(function (results) {
      postTweet(results);
    })
    .catch(function (error) {
      console.log('ERROR:', error);
      makeAndPostTweet();
    });

}

// Get a random comment and see if it's usable.
function getComment () {

  return new Promise (function (resolve, reject) {

    console.log('\n---\n');

    // Pick a random comment. The API doesn't provide for this, but SoundCloud
    // comment IDs are sequential! There are a lot of missing comments (deleted
    // spam, etc.), but this has about a 40-50% success rate at finding an
    // actual comment, which is pretty good!
    var randomCommentID = String(_.random(100000000, 300000000));

    // Query the SoundCloud API and filter the results.
    SC.get('/comments/' + randomCommentID, function(error, comment) {

      // console.log('\n\nFULL API RESPONSE:\n\n', comment)

      console.log('LOOKING FOR A COMMENT AT ID #' + randomCommentID + '…');

      if (typeof(error) !== 'undefined') {
        reject('Comment does not exist at this ID anymore.');
      }
      else {
        var comment = comment.body.trim();

        console.log('FOUND A COMMENT:', comment);

        console.log('ANALYZING: Checking if too short…');

        if (comment.length < 1) {
          reject('Comment is too short.');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking if too long…');

        if (comment.length > 141) {
          reject('Comment is too long');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking for bad words…');

        if (wordfilter.blacklisted(comment)) {
          reject('Comment is a reply, contains a bad word, or looks like spam.');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking if is English…');

        translate.detect(comment, function (error, result) {
          if (result.lang === 'en') {
            console.log('\tOK!');

            console.log('SUCCESS: All checks passed! Comment is useable!');

            resolve(comment);
          }
          else if (typeof(error) !== 'undefined') {
            reject(error);
          }
          else {
            reject('Comment is not in English.')
          }
        })

      }

    });
  });
}

function postTweet (tweet) {

  if (typeof(tweet) !== 'undefined') {
    console.log('NOW TWEETING:', tweet);

    if (isProduction() || canTweetFromLocal) {
      twitter.post('statuses/update', { status: tweet }, function (error) {
        if (error) {
          console.log('ERROR POSTING TWEET:', error);
        }
      });
    }
  }
  else {
    console.log('ERROR: No comment was fetched!');
  }

}

// Tweet on a regular schedule. 8 times a day means every 3 hours. Note that
// Because Heroku cycles dynos once per day, the bot's schedule will not be
// regular: https://devcenter.heroku.com/articles/how-heroku-works#dyno-manager
if (isProduction()) {
  var timesToTweetPerDay = 8;

  setInterval(function () {
    try {
      makeAndPostTweet();
    }
    catch (error) {
      console.log('PROCESS UNSUCCESSFUL!', error);
    }
  }, (1000 * 60 * 60 * 24) / timesToTweetPerDay);
}


///


// Additional filters.
wordfilter.addWords([

  // To get a better set of comments, I'm filtering out a lot of things.
  // The lists below are used in addition to the default set:
  // https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json

  // Promotion.
  'follow',
  'listen to my',
  'check out',
  'check my',
  'subscribe',
  'channel',
  'my cloud',
  'add me',
  'profile',

  'soundcloud',
  'facebook',
  'twitter',
  'youtube',<commit_msg>Add spam term.<commit_after>"use strict";

// Local tweet test override.
var canTweetFromLocal = false;

// Load libraries.
var _ = require('underscore');
var wordfilter = require('wordfilter');
var SC = require('node-soundcloud');
var Twit = require('twit');

// Are we on production? Check if an important environment variable exists.
function isProduction () {
  return (typeof(process.env.TWITTER_CONSUMER_KEY) !== 'undefined');
}

// Use environment variables if we're on production, config files if we're local.
if (isProduction()) {
  var yandexKey = process.env.YANDEX_KEY;

  var twitter = new Twit({
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token: process.env.TWITTER_ACCESS_TOKEN,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  });

  SC.init({
    id:     process.env.SOUNDCLOUD_CLIENT_ID,
    secret: process.env.SOUNDCLOUD_SECRET
  });
}
else {
  var yandexConfig = require('./config/yandex-config.js'),
      yandexKey    = yandexConfig.key;

  var twitter = new Twit(require('./config/twitter-config.js'));

  SC.init(require('./config/soundcloud-config.js'));
}

// Load Yandex Translation API library.
var translate = require('yandex-translate')(yandexKey);

// Execute once upon initialization.
makeAndPostTweet();

// The main process. Get a useable comment and tweet it or try again.
function makeAndPostTweet () {

  getComment()
    .then(function (results) {
      postTweet(results);
    })
    .catch(function (error) {
      console.log('ERROR:', error);
      makeAndPostTweet();
    });

}

// Get a random comment and see if it's usable.
function getComment () {

  return new Promise (function (resolve, reject) {

    console.log('\n---\n');

    // Pick a random comment. The API doesn't provide for this, but SoundCloud
    // comment IDs are sequential! There are a lot of missing comments (deleted
    // spam, etc.), but this has about a 40-50% success rate at finding an
    // actual comment, which is pretty good!
    var randomCommentID = String(_.random(100000000, 300000000));

    // Query the SoundCloud API and filter the results.
    SC.get('/comments/' + randomCommentID, function(error, comment) {

      // console.log('\n\nFULL API RESPONSE:\n\n', comment)

      console.log('LOOKING FOR A COMMENT AT ID #' + randomCommentID + '…');

      if (typeof(error) !== 'undefined') {
        reject('Comment does not exist at this ID anymore.');
      }
      else {
        var comment = comment.body.trim();

        console.log('FOUND A COMMENT:', comment);

        console.log('ANALYZING: Checking if too short…');

        if (comment.length < 1) {
          reject('Comment is too short.');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking if too long…');

        if (comment.length > 141) {
          reject('Comment is too long');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking for bad words…');

        if (wordfilter.blacklisted(comment)) {
          reject('Comment is a reply, contains a bad word, or looks like spam.');
          return;
        }

        console.log('\tOK!');

        console.log('ANALYZING: Checking if is English…');

        translate.detect(comment, function (error, result) {
          if (result.lang === 'en') {
            console.log('\tOK!');

            console.log('SUCCESS: All checks passed! Comment is useable!');

            resolve(comment);
          }
          else if (typeof(error) !== 'undefined') {
            reject(error);
          }
          else {
            reject('Comment is not in English.')
          }
        })

      }

    });
  });
}

function postTweet (tweet) {

  if (typeof(tweet) !== 'undefined') {
    console.log('NOW TWEETING:', tweet);

    if (isProduction() || canTweetFromLocal) {
      twitter.post('statuses/update', { status: tweet }, function (error) {
        if (error) {
          console.log('ERROR POSTING TWEET:', error);
        }
      });
    }
  }
  else {
    console.log('ERROR: No comment was fetched!');
  }

}

// Tweet on a regular schedule. 8 times a day means every 3 hours. Note that
// Because Heroku cycles dynos once per day, the bot's schedule will not be
// regular: https://devcenter.heroku.com/articles/how-heroku-works#dyno-manager
if (isProduction()) {
  var timesToTweetPerDay = 8;

  setInterval(function () {
    try {
      makeAndPostTweet();
    }
    catch (error) {
      console.log('PROCESS UNSUCCESSFUL!', error);
    }
  }, (1000 * 60 * 60 * 24) / timesToTweetPerDay);
}


///


// Additional filters.
wordfilter.addWords([

  // To get a better set of comments, I'm filtering out a lot of things.
  // The lists below are used in addition to the default set:
  // https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json

  // Promotion.
  'follow',
  'listen to my',
  'check out',
  'check my',
  'subscribe',
  'channel',
  'my cloud',
  'add me',
  'profile',
  'premiere',

  'soundcloud',
  'facebook',
  'twitter',
  'youtube',
{'fraction_non_alphanumeric': 0.13674046620501318, 'fraction_numerical': 0.007607529503559933, 'mean_word_length': 2.6660707901322844, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '90759', 'n_tokens_mistral': 3335, 'n_tokens_neox': 3144, 'n_words': 872}