Hi, I’m looking to upload media to twitter using a V2 workflow. It looks like this was integrated in V1 and is now unavailable. Does anyone know how this can be done?
Here’s an example V1 workflow:
Thanks for any help/thoughts.
Hi, I’m looking to upload media to twitter using a V2 workflow. It looks like this was integrated in V1 and is now unavailable. Does anyone know how this can be done?
Here’s an example V1 workflow:
Thanks for any help/thoughts.
Hi @hanjoyoutaku,
Unfortunately we don’t have v2 workflow sharing yet but here’s my take at recreating it in v2.
Please let me know if it works for you!
import axios from 'axios';
import { axios as platformAxios } from '@pipedream/platform';
// To use previous step data, pass the `steps` object to the run() function
export default defineComponent({
props: {
twitter: {
type: 'app',
app: 'twitter'
},
url: {
type: 'string',
label: "Photo URL",
description: 'Full URL to the image to download then upload to a Tweet',
},
media_type: {
type: 'string',
label: "Media Type",
description: 'The MIME type of the media being uploaded. See https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init'
}
},
async run({ steps, $ }) {
// Data we need to make the Twitter API request
const oauthSignerUri = this.twitter.$auth.oauth_signer_uri
const token = {
key: this.twitter.$auth.oauth_access_token,
secret: this.twitter.$auth.oauth_refresh_token,
}
const signConfig = {
token,
oauthSignerUri
}
// Download image, base64 encode it, then upload the media to Twitter
const imageResponse = await axios({
url: this.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 = this.media_type;
// 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
const uploadMediaInitResponse = await platformAxios($, mediaUploadInitRequest, signConfig)
$.export('uploadMediaInitResponse', uploadMediaInitResponse);
const mediaIdString = uploadMediaInitResponse.media_id_string;
$.export('mediaIdString', mediaIdString);
// Split the file into chunks, APPEND each chunk
const splitStringRe = new RegExp('.{1,' + 1000 + '}', 'g');
const chunks = base64EncodedFile.match(splitStringRe);
for (const [segment_index, media_data] of chunks.entries()) {
console.log(`Processing chunk ${segment_index}`)
// 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,
}
}
await platformAxios($, mediaUploadAppendRequest, signConfig)
}
// 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 platformAxios($, mediaUploadFinalizeRequest, signConfig)
},
})
Hi pierce, thank you for your help.
At the moment it seems like Twitter is returning error 400, “media_id or media_key parameter is missing.”.
If you have any clues as to why, will be appreciated.
Small v1 to v2 migration mistake on my part. The API call was including the wrong variable name.
import axios from 'axios';
import { axios as platformAxios } from '@pipedream/platform';
// To use previous step data, pass the `steps` object to the run() function
export default defineComponent({
props: {
twitter: {
type: 'app',
app: 'twitter'
},
url: {
type: 'string',
label: "Photo URL",
description: 'Full URL to the image to download then upload to a Tweet',
},
media_type: {
type: 'string',
label: "Media Type",
description: 'The MIME type of the media being uploaded. See https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init'
}
},
async run({ steps, $ }) {
// Data we need to make the Twitter API request
const oauthSignerUri = this.twitter.$auth.oauth_signer_uri
const token = {
key: this.twitter.$auth.oauth_access_token,
secret: this.twitter.$auth.oauth_refresh_token,
}
const signConfig = {
token,
oauthSignerUri
}
// Download image, base64 encode it, then upload the media to Twitter
const imageResponse = await axios({
url: this.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 = this.media_type;
// 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
const uploadMediaInitResponse = await platformAxios($, mediaUploadInitRequest, signConfig)
$.export('uploadMediaInitResponse', uploadMediaInitResponse);
const mediaIdString = uploadMediaInitResponse.media_id_string;
$.export('mediaIdString', mediaIdString);
// Split the file into chunks, APPEND each chunk
const splitStringRe = new RegExp('.{1,' + 1000 + '}', 'g');
const chunks = base64EncodedFile.match(splitStringRe);
for (const [segment_index, media_data] of chunks.entries()) {
console.log(`Processing chunk ${segment_index}`)
// 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,
}
}
await platformAxios($, mediaUploadAppendRequest, signConfig)
}
// 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: mediaIdString,
}
}
await platformAxios($, mediaUploadFinalizeRequest, signConfig)
},
})
Replace your Node.js code with that and see if that helps!
Thanks again Pierce. Looks like we’ve gotten it all working now, but when I add my media id to the create tweet function it doesn’t add an image to the tweet - just the status. Is this a bug with the “create tweet” function in V2, or am I missing something? Here’s a screenshot (I’ve hardcoded a media id example to make sure everything is working)
I’m playing around and don’t want to jump to any conclusions, tried some other options on the CreateTweet functionality e.g. including latitude and longitude or an attachment and those didn’t seem to work either. Maybe I’m missing something.
Thanks for helping me. I love pipedream.
I have another workflow I’m having problems with too, trying to reply using the create tweet function.
All of the parameters are included, but the tweet doesn’t seem to reply. Very open to this being a series of mistakes ha, and we can just keep our attention on the media upload. Is it possible to look at or debug the code inside of the create tweet function?
Hi @hanjoyoutaku ,
This is a quirk with the Twitter API, not sure if you saw this in their documentation but you must upload a Media
instance before it can be used in a tweet:
Here’s a complete tutorial:
But I think I may see a bug in the source code of the action here: pipedream/twitter.app.mjs at 23144807af52ffb2512fe3c064e6ae76cc7c0eae · PipedreamHQ/pipedream · GitHub
The passed parameter is named mediaIds
but Twitter is expected media_ids
. That might be the issue.
I have opened a thread here in our public Github repo, a team member will be working on it:
I believe this bug was affecting other options like you mentioned. Please comment or react to that issue for real time updates.
Thanks so much pierce and other team members.
FWIW on somewhat stale thread…
there may be extra code re encode to B64 & multiple calls on Twitr api
per sample below ( node.express.route server implementation )
So, after auth / tokens with twitter, just buffer the photo , call media/upload saving the response.mediaId for a post tweet
client.v1.tweet(
@yayatvapp ${text} ${mapAddr} #${savedTag}
, {media_ids: myId});
Is there an easy way to upload images to Twitter with Python? Can’t believe this is so hard
Hello @sonnnie, I’ve created a new action request for your usecase here. I’ve added it to Pipedream’s prioritized component backlog. Our component dev will take a look at it soon!
is it possi to upload videos in twitter if yes may i know how to do that?