🎉 Pipedream raises $20M Series A 🎉
Read the blog post and TC Techcrunch article.
Random Comic Book
•@raymondcamden•
•code:
•data:private•last updated:1 month ago
today
Build integrations remarkably fast!
You're viewing a public workflow template.
Sign up to customize, add steps, modify code and more.
Join 250,000+ developers using the Pipedream platform
steps.
trigger
Cron Scheduler
Deploy to configure a custom schedule
This workflow runs on Pipedream's servers and is triggered on a custom schedule.
steps.
getRandomCover
auth
to use OAuth tokens and API keys in code via theauths object
code
Write any Node.jscodeand use anynpm package. You can alsoexport datafor use in later steps via return or this.key = 'value', pass input data to your code viaparams, and maintain state across invocations with$checkpoint.
async (event, steps) => {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
}
67
	
  const PRIV_KEY = process.env.MARVEL_PRIVATE_KEY;
  const API_KEY = process.env.MARVEL_API_KEY;
  
	//const crypto = require('crypto');
	import { createHash } from 'crypto';

	import fetch from 'node-fetch';


	const IMAGE_NOT_AVAIL = "http://i.annihil.us/u/prod/marvel/i/mg/b/40/image_not_available";

  const getRandomInt = function(min, max) {
	  return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  //first select a random year
	let year = getRandomInt(1960, new Date().getFullYear()-1);
	//then a month
	let month = getRandomInt(1,12);

  let monthStr = month<10?"0"+month:month;
	//lame logic for end of month
	let eom = month==2?28:30;
	let beginDateStr = year + "-" + monthStr + "-01";
	let endDateStr = year + "-" + monthStr + "-" + eom;
	let url = "http://gateway.marvel.com/v1/public/comics?limit=100&format=comic&formatType=comic&dateRange="+beginDateStr+"%2C"+endDateStr+"&apikey="+API_KEY;
	let ts = new Date().getTime();
	let hash = createHash('md5').update(ts + PRIV_KEY + API_KEY).digest('hex');
		url += "&ts="+ts+"&hash="+hash;
	
	let result = await fetch(url);
	let data = (await result.json()).data;
	if(!data.results) $end("No results, data was " + data);
	let resultData = data.results;
	console.log('initial set',resultData.length);
	// if(comic.thumbnail && comic.thumbnail.path != IMAGE_NOT_AVAIL) {
	let comics = resultData.filter(c => {
		return c.thumbnail && c.thumbnail.path !== IMAGE_NOT_AVAIL;
	});
	console.log('now we have ',comics.length);
	let selectedComic = comics[getRandomInt(0, comics.length-1)];

	//rewrite simpler
	this.image = {};
	this.image.title = selectedComic.title;
	for(let x=0; x<selectedComic.dates.length;x++) {
		if(selectedComic.dates[x].type === 'onsaleDate') {
			this.image.date = new Date(selectedComic.dates[x].date);
			//rewrite nicer
			this.image.date = `${this.image.date.getMonth()+1}/${this.image.date.getFullYear()}`;
		}
	}

	this.image.url = selectedComic.thumbnail.path + "." + selectedComic.thumbnail.extension;
	if(selectedComic.urls.length) {
		for(let x=0; x<selectedComic.urls.length; x++) {
			if(selectedComic.urls[x].type === "detail") {
				this.image.link = selectedComic.urls[x].url;
			}
		}
	}
	// one more time server, text for tweet
	this.image.tweet = `${this.image.title} published ${this.image.date}\n${this.image.link}`; 
	console.log(this.image);
	
  const PRIV_KEY = process.env.MARVEL_PRIVATE_KEY;
  const API_KEY = process.env.MARVEL_API_KEY;
  
	//const crypto = require('crypto');
	import { createHash } from 'crypto';

	import fetch from 'node-fetch';


	const IMAGE_NOT_AVAIL = "http://i.annihil.us/u/prod/marvel/i/mg/b/40/image_not_available";

  const getRandomInt = function(min, max) {
	  return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  //first select a random year
	let year = getRandomInt(1960, new Date().getFullYear()-1);
	//then a month
	let month = getRandomInt(1,12);

  let monthStr = month<10?"0"+month:month;
	//lame logic for end of month
	let eom = month==2?28:30;
	let beginDateStr = year + "-" + monthStr + "-01";
	let endDateStr = year + "-" + monthStr + "-" + eom;
	let url = "http://gateway.marvel.com/v1/public/comics?limit=100&format=comic&formatType=comic&dateRange="+beginDateStr+"%2C"+endDateStr+"&apikey="+API_KEY;
	let ts = new Date().getTime();
	let hash = createHash('md5').update(ts + PRIV_KEY + API_KEY).digest('hex');
		url += "&ts="+ts+"&hash="+hash;
	
	let result = await fetch(url);
	let data = (await result.json()).data;
	if(!data.results) $end("No results, data was " + data);
	let resultData = data.results;
	console.log('initial set',resultData.length);
	// if(comic.thumbnail && comic.thumbnail.path != IMAGE_NOT_AVAIL) {
	let comics = resultData.filter(c => {
		return c.thumbnail && c.thumbnail.path !== IMAGE_NOT_AVAIL;
	});
	console.log('now we have ',comics.length);
	let selectedComic = comics[getRandomInt(0, comics.length-1)];

	//rewrite simpler
	this.image = {};
	this.image.title = selectedComic.title;
	for(let x=0; x<selectedComic.dates.length;x++) {
		if(selectedComic.dates[x].type === 'onsaleDate') {
			this.image.date = new Date(selectedComic.dates[x].date);
			//rewrite nicer
			this.image.date = `${this.image.date.getMonth()+1}/${this.image.date.getFullYear()}`;
		}
	}

	this.image.url = selectedComic.thumbnail.path + "." + selectedComic.thumbnail.extension;
	if(selectedComic.urls.length) {
		for(let x=0; x<selectedComic.urls.length; x++) {
			if(selectedComic.urls[x].type === "detail") {
				this.image.link = selectedComic.urls[x].url;
			}
		}
	}
	// one more time server, text for tweet
	this.image.tweet = `${this.image.title} published ${this.image.date}\n${this.image.link}`; 
	console.log(this.image);
steps.
upload_media_to_twitter
Uploads media to Twitter using the Upload API
auth
(auths.twitter)
params
URL

URL of media to upload to Twitter

string ·params.url
Media Type
string ·params.media_type
code
async (params, auths) => {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
}
90
const axios = require("axios")
const chunk = require("lodash.chunk")

// Data we need to make the Twitter API request
const oauthSignerUri = auths.twitter.oauth_signer_uri
const token = {
  key: auths.twitter.oauth_access_token,
  secret: auths.twitter.oauth_refresh_token,
}
const signConfig = {
  token,
  oauthSignerUri
}

// Download image, base64 encode it, then upload the media to Twitter
const imageResponse = await axios({
  url: params.url,
  method: "GET",
  responseType: "arraybuffer"
})

const file = Buffer.from(imageResponse.data, 'binary')
const total_bytes = file.length
const base64EncodedFile = file.toString('base64')
const { media_type } = params

// First, tell Twitter the type of file you're uploading, how big it is, etc.
// https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init
const mediaUploadInitRequest = {
  method: 'POST',
  data: '',
  url: "https://upload.twitter.com/1.1/media/upload.json",
  params: {
    command: "INIT",
    total_bytes,
    media_type,
  }
}

// Twitter returns a media_id_string that we use to upload the file,
// and to reference it in future steps
this.uploadMediaInitResponse = (await require("@pipedreamhq/platform").axios(this, mediaUploadInitRequest, signConfig))
this.mediaIdString = this.uploadMediaInitResponse.media_id_string 

// Split the file into chunks, APPEND each chunk
const splitStringRe = new RegExp('.{1,' + 10000 + '}', 'g');
const chunks = base64EncodedFile.match(splitStringRe);

// Collect all of our requests into an array
const requests = []

for (const [segment_index, media_data] of chunks.entries()) {
  // APPEND file content in chunks
  // See https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-append
  const mediaUploadAppendRequest = {
    method: 'POST',
    data: '',
    url: "https://upload.twitter.com/1.1/media/upload.json",
    params: {
      command: "APPEND",
      media_id: this.mediaIdString,
      segment_index,
      media_data,
    }
  }
  requests.push(require("@pipedreamhq/platform").axios(this, mediaUploadAppendRequest, signConfig))
}

// Send N requests at a time
const requestChunks = chunk(requests, 10)

for (const [i, chunk] of requestChunks.entries()) {
  console.log(`Processing chunk ${i}`)
  await Promise.all(chunk)
}

// Finally, tell Twitter we're done uploading
// https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-finalize
const mediaUploadFinalizeRequest = {
    method: 'POST',
    data: '',
    url: "https://upload.twitter.com/1.1/media/upload.json",
    params: {
      command: "FINALIZE",
      media_id: this.mediaIdString,
    }
  }
  await require("@pipedreamhq/platform").axios(this, mediaUploadFinalizeRequest, signConfig)
const axios = require("axios")
const chunk = require("lodash.chunk")

// Data we need to make the Twitter API request
const oauthSignerUri = auths.twitter.oauth_signer_uri
const token = {
  key: auths.twitter.oauth_access_token,
  secret: auths.twitter.oauth_refresh_token,
}
const signConfig = {
  token,
  oauthSignerUri
}

// Download image, base64 encode it, then upload the media to Twitter
const imageResponse = await axios({
  url: params.url,
  method: "GET",
  responseType: "arraybuffer"
})

const file = Buffer.from(imageResponse.data, 'binary')
const total_bytes = file.length
const base64EncodedFile = file.toString('base64')
const { media_type } = params

// First, tell Twitter the type of file you're uploading, how big it is, etc.
// https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init
const mediaUploadInitRequest = {
  method: 'POST',
  data: '',
  url: "https://upload.twitter.com/1.1/media/upload.json",
  params: {
    command: "INIT",
    total_bytes,
    media_type,
  }
}

// Twitter returns a media_id_string that we use to upload the file,
// and to reference it in future steps
this.uploadMediaInitResponse = (await require("@pipedreamhq/platform").axios(this, mediaUploadInitRequest, signConfig))
this.mediaIdString = this.uploadMediaInitResponse.media_id_string 

// Split the file into chunks, APPEND each chunk
const splitStringRe = new RegExp('.{1,' + 10000 + '}', 'g');
const chunks = base64EncodedFile.match(splitStringRe);

// Collect all of our requests into an array
const requests = []

for (const [segment_index, media_data] of chunks.entries()) {
  // APPEND file content in chunks
  // See https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-append
  const mediaUploadAppendRequest = {
    method: 'POST',
    data: '',
    url: "https://upload.twitter.com/1.1/media/upload.json",
    params: {
      command: "APPEND",
      media_id: this.mediaIdString,
      segment_index,
      media_data,
    }
  }
  requests.push(require("@pipedreamhq/platform").axios(this, mediaUploadAppendRequest, signConfig))
}

// Send N requests at a time
const requestChunks = chunk(requests, 10)

for (const [i, chunk] of requestChunks.entries()) {
  console.log(`Processing chunk ${i}`)
  await Promise.all(chunk)
}

// Finally, tell Twitter we're done uploading
// https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-finalize
const mediaUploadFinalizeRequest = {
    method: 'POST',
    data: '',
    url: "https://upload.twitter.com/1.1/media/upload.json",
    params: {
      command: "FINALIZE",
      media_id: this.mediaIdString,
    }
  }
  await require("@pipedreamhq/platform").axios(this, mediaUploadFinalizeRequest, signConfig)
steps.
post_tweet
Post a tweet.
auth
(auths.twitter)
params
Status
string ·params.status
Optional
code
async (params, auths) => {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
}
23
const axios = require('axios')
const {status, in_reply_to_status_id, auto_populate_reply_metadata, exclude_reply_user_ids, attachment_url, media_ids, possibly_sensitive, lat, long, place_id, display_coordinates, trim_user, enable_dmcommands, fail_dmcommands, card_uri} = params
const body = {
  config: {
    url: `https://api.twitter.com/1.1/statuses/update.json`,
    method: 'POST',
    params,
  },
  token: {
    key: auths.twitter.oauth_access_token,
    secret: auths.twitter.oauth_refresh_token,
  },
}
const proxy = "https://api.pipedream.com/v1/oauth1/app_13GhY1"
const resp = await axios.post(proxy,body)

const {messages, data} = resp.data
for (const message of messages) {
  console.log(message)
}
return data
const axios = require('axios')
const {status, in_reply_to_status_id, auto_populate_reply_metadata, exclude_reply_user_ids, attachment_url, media_ids, possibly_sensitive, lat, long, place_id, display_coordinates, trim_user, enable_dmcommands, fail_dmcommands, card_uri} = params
const body = {
  config: {
    url: `https://api.twitter.com/1.1/statuses/update.json`,
    method: 'POST',
    params,
  },
  token: {
    key: auths.twitter.oauth_access_token,
    secret: auths.twitter.oauth_refresh_token,
  },
}
const proxy = "https://api.pipedream.com/v1/oauth1/app_13GhY1"
const resp = await axios.post(proxy,body)

const {messages, data} = resp.data
for (const message of messages) {
  console.log(message)
}
return data