Created
January 26, 2024 17:45
-
-
Save bLd75/ab3b400bddde265da1a1bdb929a61c3f to your computer and use it in GitHub Desktop.
twitter_gm_v3.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config(); | |
const fs = require('fs'); | |
const readline =require('readline'); | |
const {TwitterApi} = require('twitter-api-v2'); | |
const { TwitterApiV2Settings } = require('twitter-api-v2'); | |
const { ApiPromise, WsProvider } = require('@polkadot/api'); | |
const csv = require('jquery-csv'); | |
TwitterApiV2Settings.debug = true; | |
const client = new TwitterApi({ | |
appKey: process.env.TWITTER_CONSUMER_KEY, | |
appSecret: process.env.TWITTER_CONSUMER_SECRET, | |
accessToken: process.env.TWITTER_ACCESS_TOKEN, | |
accessSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET, | |
}); | |
const ARCHIVE_PATH = process.env.ARCHIVE_PATH; | |
var lastIndex = 0; | |
async function main () { | |
const provider = new WsProvider('wss://ws.gm.bldnodes.org'); | |
const api = await ApiPromise.create({ provider }); | |
// Init GM events csv | |
const gmEvents = 'gm-sent.csv'; | |
var gmEventsOutput = await fs.createWriteStream(gmEvents,{flags:'a'}); | |
lastIndex = initCsv(gmEvents,gmEventsOutput); | |
console.log("π€Scanning GM on chain, let's dance"); | |
await api.query.system.events(events => { | |
events.forEach((record) => { | |
if(record.event.section == "tokens" && record.event.method == "Transfer") { | |
const type = record.event.data[0]; | |
const sender = record.event.data[1]; | |
const receiver = record.event.data[2]; | |
writeEvents(gmEventsOutput, api, type, sender, receiver); | |
} | |
}); | |
}); | |
//Start reporting | |
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); | |
console.log("π you Twitter API, I'm sending summaries now π"); | |
while(true) { | |
const gmSummary = craftTweet(gmEvents); | |
if(gmSummary != null) { | |
console.log(`\n${new Date().toGMTString()} - Spread love lil bird π¦\n\n${gmSummary}`); | |
const succes = await postTweetThread(gmSummary); | |
if(succes) { | |
//Move file and recreate it only if tweet was posted successfully | |
gmEventsOutput.end(); | |
fs.rename(gmEvents, `${ARCHIVE_PATH}/gm-notified-${Date.now()}.csv`,() => { | |
gmEventsOutput = fs.createWriteStream(gmEvents,{flags:'a'}); | |
lastIndex = initCsv(gmEvents,gmEventsOutput); | |
}); | |
} | |
} else { | |
console.log(`\n${new Date().toGMTString()} - No love to deliver lately`); | |
} | |
//wait 6 hours | |
await sleep(21600000); | |
} | |
} | |
function initCsv(file, output){ | |
if (fs.existsSync(file)) { | |
const data = fs.readFileSync(file).toString().split("\n"); | |
var lastLine = data.slice(-1)[0]; | |
// Reading 1 line above if last line is empty | |
if(lastLine == '') { | |
lastLine = data.slice(-2)[0]; | |
} | |
var fields = lastLine.split(','); | |
var lastInd = fields[0]; | |
if(lastInd < 1) { | |
lastInd = 0; | |
//console.log("Info: no index found in file",file,", starting at 1"); | |
} | |
return parseInt(lastInd); | |
} else { | |
//console.log("Info: file",file,"doesn't exist, initializing indexing"); | |
output.write('index,type,sender_addr,sender_hasId,sender_judgment,sender_name,sender_twitter,receiver_addr,receiver_hasId,receiver_judgment,receiver_name,receiver_twitter'); | |
return 0; | |
} | |
} | |
async function writeEvents(output, api, type, sender, receiver) { | |
sid = (await api.query.identity.identityOf(sender)).toHuman(); | |
rid = (await api.query.identity.identityOf(receiver)).toHuman(); | |
const senderId = getIdentity(sid); | |
const receiverId = getIdentity(rid); | |
lastIndex += 1; | |
const line = `\n${lastIndex.toString()},${type},${sender.toString()},${senderId.hasId.toString()},${senderId.judgment.toString()},${senderId.name.toString()},${senderId.twitter.toString()},${receiver.toString()},${receiverId.hasId.toString()},${receiverId.judgment.toString()},${receiverId.name.toString()},${receiverId.twitter.toString()}` | |
output.write(line); | |
console.log(`${type} sent by ${senderId.name.toString()} (${sender}) to ${receiverId.name.toString()} (${receiver})`); | |
} | |
function getIdentity(id) { | |
const idObject = { | |
hasId: false, | |
judgment: false, | |
name: false, | |
discord: false, | |
twitter: false | |
}; | |
idObject.hasId = (id == null) ? false : true; | |
if(idObject.hasId) { | |
idObject.judgment = (id.judgements[0] == '') ? false : true; | |
idObject.name = (id.info.display.Raw == '' || id.info.display.Raw == null) ? false : hex2String(id.info.display.Raw); | |
idObject.discord = (id.info.additional == '' || id.info.additional == null) ? false : id.info.additional[0][1].Raw; | |
idObject.twitter = (id.info.twitter.Raw == '' || id.info.twitter.Raw == null) ? false : formatTwitterHandle(id.info.twitter.Raw); | |
} | |
return idObject; | |
} | |
function formatTwitterHandle(handle) { | |
const output = (handle.substring(0,1) == '@') ? handle : ('@'+handle); | |
return output; | |
} | |
function hex2String(hex) { | |
if(hex.substring(0,2) != '0x') { return hex; } | |
hex=hex.replace(/^\s+/g,'');hex=hex.replace(/\s+$/g,'');hex=hex.replace(/0x/g,''); | |
output = Buffer.from(hex,'hex').toString('utf8'); | |
return output; | |
} | |
function craftTweet(gmEvents) { | |
const file = fs.readFileSync(gmEvents, 'utf8'); | |
const tx = csv.toObjects(file); | |
if(tx.length < 2) {return null;} | |
var gms = 0; | |
var gns = 0; | |
var gmDetails = []; | |
//write GM details | |
for(let i = 0; i < tx.length ; i++) { | |
var t = '' | |
if(tx[i].type == 'GM'){ | |
t = 'GM π'; | |
gms+=1; | |
} else { | |
t = 'GN π'; | |
gns+=1; | |
} | |
//receiver has verified twitter | |
if(tx[i].receiver_judgment == 'true' && tx[i].receiver_twitter != 'false') { | |
//sender has verified twitter | |
if(tx[i].sender_judgment == 'true' && tx[i].sender_twitter != 'false') { | |
gmDetails.push(`${tx[i].sender_twitter} sent a ${t} to ${tx[i].receiver_twitter}\n`); | |
} else { | |
gmDetails.push(`An anon sent a ${t} to ${tx[i].receiver_twitter}\n`); | |
} | |
} | |
} | |
gmDetails.unshift(`In the last 6 hours (or more), ${gms} GM π and ${gns} GN π were delivered on-chain\nReceived a GM? Say it back! https://app.gmordie.com/\n\n`); | |
return gmDetails; | |
} | |
async function postTweetThread(tweetText) { | |
var thread = [tweetText[0]]; | |
var buffer = ''; | |
for(i = 1; i < tweetText.length; i++) { | |
const tmp = buffer + tweetText[i]; | |
if(tmp.length > 240) { | |
thread.push(buffer); | |
buffer = tweetText[i]; | |
} else { | |
buffer = tmp; | |
} | |
} | |
if(buffer != '') {thread.push(buffer);} | |
console.log(thread); | |
try { | |
const tweet = await client.v2.tweetThread(thread); | |
console.log(`Tweet posted with ID ${tweet.data.id}`); | |
return true; | |
} catch (error) { | |
console.error(`Failed to post tweet: ${error}`); | |
return false; | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment