Skip to content

Instantly share code, notes, and snippets.

@arvidkahl
Last active July 3, 2021 11:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save arvidkahl/cab7dbed999fc14dd2febb55342badbd to your computer and use it in GitHub Desktop.
Save arvidkahl/cab7dbed999fc14dd2febb55342badbd to your computer and use it in GitHub Desktop.
Twitter Giveaway bash+js script

This is a script picking winners for a contest where:

  • every winning entry has to mention one other twitter account in a reply
  • double winners are allowed

You'll need a few things installed:

  • jq
  • twarc
  • boxes

Run npm install before running the script.

You'll also need to chmod +x ./giveaway.sh.

twarc needs to be configured using twarc configure

Replace the conversation ID and your Twitter handle with your data.

#!/bin/bash
clear
echo "Zero to Sold / Gratitude Giveaway" | boxes
echo ""
echo "Loading replies for the giveaway tweet (this could take a while)."
# twarc replies 1410898364691066881 --recursive > replies.jsonl
LINECOUNT=$(wc -l < replies.jsonl | xargs)
echo "Found $LINECOUNT replies."
echo "Loading retweets for the giveaway tweet."
# twarc retweets 1410898364691066881 > retweets.jsonl
LINECOUNTRT=$(wc -l < retweets.jsonl | xargs)
echo "Found $LINECOUNTRT retweets."
echo ""
cat replies.jsonl retweets.jsonl > all.jsonl
jq --slurp . <all.jsonl >all.json
echo "Picking random winners!"
node ./pick.js > winners.txt
cat winners.txt
{
"name": "giveaway",
"version": "1.0.0",
"description": "",
"main": "pick.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.21"
}
}
let fs = require ("fs")
let _ = require("lodash")
function getOthers(tweet) {
let text = tweet.full_text.replace(/@arvidkahl/g, '').replace("@"+tweet.user.screen_name, '')
let m = text.match(/@[\S]+/);
if (m) {m = m[0].replace(/[\.'].*/,"")}
return m || ""
}
function isAlreadyWinner(all, it) {
if (!it || !it.user) return false;
return _.some(all, (i)=> {
return i.user.screen_name == it.user.screen_name || i.full_text.indexOf(it.user.screen_name)>-1
})
}
let data = _.map(JSON.parse(fs.readFileSync("./all.json", {encoding: 'utf-8'})), (i) => _.extend(i, {type: i.is_quote_status==true?'retweet':'reply'}))
const max_winners = 50
let candidates = []
candidates = _.shuffle(data)
candidates = _.filter(candidates, (i)=>{return i.user.screen_name!='arvidkahl'}) // filter out my own account
candidates = _.filter(candidates, (i)=>{return (getOthers(i))}) // only those who mention other accounts
candidates = _.uniqBy(candidates, (i) => (i.user.screen_name + getOthers(i)).split('').sort().join('')) // filter out replies to replies
winners = []
while (winners.length < max_winners) {
let candidate = candidates.shift();
if (!isAlreadyWinner(winners, candidate)) winners.push(candidate)
}
console.log("=== Long ===\n\n")
_.forEach(winners, (v, i)=>{
console.log(`Winner #${i+1}: @${v.user.screen_name} (and ${getOthers(v)}) [${v.type}] https://twitter.com/${v.user.screen_name}/status/${v.id_str}`)
})
console.log("\n\n=== Tweetable ===\n\n")
_.forEach(winners, (v, i)=>{
console.log(`Winner #${i+1}: @${v.user.screen_name} and ${getOthers(v)}`)
})
console.log("\n\n=== Accounts ===\n\n")
let names = []
_.forEach(winners, (v, i)=>{
names.push(v.user.screen_name)
names.push(getOthers(v).replace("@",''))
})
_.forEach(_.uniq(names.sort()), (v) => console.log(v))
@Keirua
Copy link

Keirua commented Jul 2, 2021

I’m not sure if this is a feature, but right now if a name appear in multiple tweets its odds of being picked are increased. Maybe you should extract the list of twitter handles somehow, discard duplicates, and use the remaining list in order to pick a winner ?

@arvidkahl
Copy link
Author

Great idea. I'll keep track of winners and discard duplicates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment