Skip to content

Instantly share code, notes, and snippets.

@pirate
Last active January 22, 2020 16:52
Show Gist options
  • Save pirate/22438209f9ce5a7ece1813dac9014228 to your computer and use it in GitHub Desktop.
Save pirate/22438209f9ce5a7ece1813dac9014228 to your computer and use it in GitHub Desktop.
Read a block of code from stdin, submit it to carbon.sh, and output the resulting tweet url.
#!/usr/bin/env node
/*
Submit code from stdin to carbon.now.sh and return a url to a new tweet containing a screenshot
carbon.now.sh authors: https://dawnlabs.io/
carbonify author: Nick Sweeting <git@nicksweeting.com>
MIT License 2017
*/
const puppeteer = require('puppeteer')
const USAGE = `
Usage:
./carbonify.js < code_file.py
Output:
https://twitter.com/intent/tweet?text=pic.twitter.com/abcd1234.png
Dependencies:
yarn add GoogleChrome/puppeteer
To open a new tweet compose window:
open $(./carbonify.js < code_file.py)
To trigger from SublimeText, add a build variant:
{
"cmd":
["open" "$(/path/to/carbonify.js < \"$file\")"],
"name": "Tweet carbon.now.sh screenshot",
"shell": true
}
`
function log(text) {
process.stderr.write(`${text}\n`)
}
// read stdin into variable
function readInput(buffer) {
return new Promise(function(resolve, reject) {
let code = '';
buffer.on('data', (chunk) => {
code += `${chunk}\n`
})
buffer.on('end', () => {
const empty_inputs = ['', ' ', '\n', '\n\n']
if (empty_inputs.includes(code)) {
log('[!] No input was passed in!')
reject()
} else {
resolve(code)
}
})
buffer.setEncoding('utf8')
buffer.resume()
})
}
// screenshot code on carbon.now.sh and get new tweet url
function getCarbonTweetURL(code) {
return new Promise(async function(resolve, reject) {
const browser = await puppeteer.launch() // for testing use: {headless: false}
const page = await browser.newPage()
// load page and wait for tweet button to go from "Loading..." to "Tweet Image"
log('[1/4] Opening carbon.now.sh in headless chrome...')
await page.goto('https://carbon.now.sh')
await page.waitForFunction(() => {
const twitter_btn = '#toolbar > div.buttons > button:nth-child(1)'
const tweet_btn_elem = document.querySelectorAll(twitter_btn)[0]
return tweet_btn_elem.innerHTML.includes("Tweet Image")
})
// clear example code out of code input field
const code_input = 'div.ReactCodeMirror div.CodeMirror-code > pre:nth-child(11)'
await page.click(code_input)
await page.keyboard.down('Meta')
await page.keyboard.down('a')
await page.keyboard.up('a')
await page.keyboard.up('Meta')
await page.keyboard.press('Backspace')
const lines = code.split('\n')
const len = lines.length
log(`[2/4] Inputting ${len} line code snippet...`)
if (len < 500) {
await page.keyboard.type(code)
} else {
// if file is large, do it line-by-line for performance reasons
lines.forEach(async (line, idx) => {
const mod = (num, amt) => ((num%amt)+amt)%amt
if (idx == 0 || !mod(idx+1, 25)) {
// every 25 lines, show progress
log(` ${idx+1}/${len} lines\n`)
}
await page.keyboard.type(`{line}\n`)
})
log(` ${len}/${len} lines\n`)
}
// catch twitter popup and log url to console instead
log('[3/4] Uploading to Twitter...')
await page.evaluate(() => {
window.open = (url) => console.log(url)
})
page.on('console', async (msg) => {
log('[4/4] Got tweet URL.')
const tweet_url = msg.text.replace('Built%20with%20%23Carbon%2C%20by%20%40dawn_labs%20', '')
await browser.close()
resolve(tweet_url)
})
const tweet_button = '#toolbar > div.buttons > button:nth-child(1)'
await page.click(tweet_button)
})
}
// if run from CLI instead of being imported
if (require.main === module) {
const node_version = Number(process.version.split('.')[0].slice(1))
if (node_version < 8) {
log('[X] You need node version >= 8.0.0 to run this.')
process.exit(1)
}
if (process.argv.includes('--help') || process.argv.includes('-h')) {
log(USAGE)
}
(async () => {
const code = await readInput(process.stdin)
const picture_url = await getCarbonTweetURL(code)
console.log(picture_url)
})()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment