I am trying to gather the URL of a media message sent in by a user in a python function. In theory (and according to this https://www.twilio.com/blog/retrieving-twilio-mms-image-urls-in-python tutorial) my python code below should work for this:
last_message = client.messages.list(limit = 1)
last_message_instance = last_message[0]
media = last_message_instance
media_url = 'https://api.twilio.com' + media.uri[:-5]
However, for some reason the media.uri parameter does not return all three sid (AccountSid, MessageSid, Sid) strings needed for the url. The url should be composed of:
https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}/Media/{Sid}.json
The .uri returns only my AccountSid and the sent message's MessageSid (interestingly, labelled as Sid in the json message as shown below)
"sid": "MMbde22b567bf7e3c77fcd4fe01d286446",
Does anyone have any tips on how to find the Media/{Sid} term I need (this typically begins with MEXxXxXxX) Thanks!
I think the issue here is that you are only making the request to the API to get a message, which is why you do not have the detail about the media.
You can request the media for the message by calling last_message_instance.media.list(). The result of that will be a list of media objects from which you can get the media URL.
last_message = client.messages.list(limit = 1)
last_message_instance = last_message[0]
for media in last_message_instance.media.list():
media_url = 'https://api.twilio.com' + media.uri[:-5]
print(media_url)
Related
Assumption / What I want to achieve
I want to use YouTube Data API V3 to get the video ID without any omissions, and find out if the cause of the trouble is in the code or in the video settings of YouTube (API side).
Problem
The following code is used to get the video information from YouTube Data API, but the number of IDs I got did not match the number of videos that are actually posted.
from apiclient.discovery
import build
id = "UCD-miitqNY3nyukJ4Fnf4_A" #sampleID
token_check = None
nextPageToken = None
id_info = []
while True:
if token_check != None:
nextPageToken = token_check
Search_Video = youtube.search().list(
part = "id",
channelId = id,
maxResults = 50,
order = 'date',
safeSearch = "none",
pageToken = nextPageToken
).execute()
for ID_check in Search_Video.get("items", []):
if ID_check["id"]["kind"] == "youtube#video":
id_info.append(ID_check["id"]["videoId"])
try:
token_check = Search_Video["nextPageToken"]
except:
print(len(id_info)) #check number of IDs
break
I also used the YouTube Data API function to get the videoCount information of the channel, and noticed that the value of videoCount did not match the number of IDs obtained by the code above, which is why I posted this.
According to channels() API, this channel have 440 videos, but the above code gets only 412 videos (at 10:30 a.m. JST).
Supplemental Information
・Python 3.9.0
・YouTube Data API v3
You have to acknowledge that the Search.list API endpoint does not have a crisp behavior. That means you should not expect precise results from it. Google does not document this behavior as such, but this forum has many posts from users experiencing that.
If you want to obtain all the IDs of videos uploaded by a given channel then you should employ the following two-step procedure:
Step 1: Obtain the ID of the Uploads Playlist of a Channel.
Invoke the Channels.list API endpoint, queried with its request parameter id set to the ID of the channel of your interest (or, otherwise, with its request parameter mine set to true) for to obtain that channel's uploads playlist ID, contentDetails.relatedPlaylists.uploads.
def get_channel_uploads_playlist_id(youtube, channel_id):
response = youtube.channels().list(
fields = 'items/contentDetails/relatedPlaylists/uploads',
part = 'contentDetails',
id = channel_id,
maxResults = 1
).execute()
items = response.get('items')
if items:
return items[0] \
['contentDetails'] \
['relatedPlaylists'] \
.get('uploads')
else:
return None
Do note that the function get_channel_uploads_playlist_id should only be called once for to obtain the uploads playlist
ID of a given channel; subsequently use that ID as many times as needed.
Step 2: Retrieve All IDs of Videos of a Playlist.
Invoke the PlaylistItems.list API endpoint, queried with its request parameter playlistId set to the ID obtained from get_channel_uploads_playlist_id:
def get_playlist_video_ids(youtube, playlist_id):
request = youtube.playlistItems().list(
fields = 'nextPageToken,items/snippet/resourceId',
playlistId = playlist_id,
part = 'snippet',
maxResults = 50
)
videos = []
is_video = lambda item: \
item['snippet']['resourceId']['kind'] == 'youtube#video'
video_id = lambda item: \
item['snippet']['resourceId']['videoId']
while request:
response = request.execute()
items = response.get('items', [])
assert len(items) <= 50
videos.extend(map(video_id, filter(is_video, items)))
request = youtube.playlistItems().list_next(
request, response)
return videos
Do note that, when using the Google's APIs Client Library for Python (as you do), API result set pagination is trivially simple: just use the list_next method of the Python API object corresponding to the respective paginated API endpoint (as was shown above):
request = API_OBJECT.list(...)
while request:
response = request.execute()
...
request = API_OBJECT.list_next(
request, response)
Also note that above I used twice the fields request parameter. This is good practice: ask from the API only the info that is of actual use.
Yet an important note: the PlaylistItems.list endpoint would not return items that correspond to private videos of a channel when invoked with an API key. This happens when your youtube object was constructed by calling the function apiclient.discovery.build upon passing to it the parameter developerKey.
PlaylistItems.list returns items corresponding to private videos only to the channel owner. This happens when the youtube object is constructed by calling the function apiclient.discovery.build upon passing to it the parameter credentials and if credentials refer to the channel that owns the respective playlist.
An additional important note: according to Google staff, there's an upper 20000 limit set by design for the number of items returned via PlaylistItems.list endpoint when queried for a given channel's uploads playlist. This is unfortunate, but a fact.
I have integrated Twilio and it works fine. Now I want to capture all the intermediate message statuses. I referred to Sending Messages.
My code looks like -
require __DIR__ . '/vendor/autoload.php';
// Use the REST API Client to make requests to the Twilio REST API
use Twilio\Rest\Client;
// Your Account SID and Auth Token from twilio.com/console
$sid = '****************';
$token = '*****************';
$client = new Client($sid, $token);
// send message
$message = $client->messages->create(
// the number you'd like to send the message to
'+1xxxxxxxxx',
array(
'from' => '+1xxxxxxxx',
'body' => 'Test web hook message '.date('h:i'),
'statusCallback' => "https://xxxxxx/xxxx.php",
)
);
But the output/response returned to statusCallback is different as -
"{\"SmsSid\":\"SM72478c1ea61f467dbc33338123c0ad0\",\"SmsStatus\":\"sent\",\"MessageStatus\":\"sent\",\"To\":\"+1xxxxxxxx\",\"MessageSid\":\"SM72478c1ea612222dbc3b7858123c0ad0\",\"AccountSid\":\"ACb655a10c1c2222e4af158c5395d64beb\",\"From\":\"+1xxxxxxx\",\"ApiVersion\":\"2010-04-01\"}"
But I need the response as it is defined at Sending Messages
EDIT
If checked at Sending Messages, we can see the fields returned in the output are - account_sid, api_version, body, num_segments, num_media, date_created, date_sent, date_updated, direction, error_code, error_message, from, price, sid, status, to and uri.
But I receive fields as - SmsSid, SmsStatus, MessageStatus, To, MessageSid, AccountSid, From and ApiVersion.
For me, the fields - num_segments, date_sent, direction, error_code, error_message are important which I am not receiving. Do I need to use another API of TWILIO to retrieve this information ?
Why am I getting different response ?
Twilio developer evangelist here.
When you send a message and set a statusCallback URL the sending messages documentation says:
Twilio will POST the MessageSid along with the other standard request parameters as well as MessageStatus and ErrorCode.
The standard request parameters are:
MessageSid
SmsSid
AccountSid
MessagingServiceSid
From
To
Body
NumMedia
as well as some others specifically about media or geographic data based on the two numbers.
If you need to find out those other attributes of the message, you will need to look up the message using the REST API.
Let me know if that helps at all.
What does your code for your callback url script look like?
What you have is just an escaped JSON string, so to match what you see on the documentation you just have to do this:
$json = '{\"SmsSid\":\"SM72478c1ea61f467dbc33338123c0ad0\",\"SmsStatus\":\"sent\",\"MessageStatus\":\"sent\",\"To\":\"+1xxxxxxxx\",\"MessageSid\":\"SM72478c1ea612222dbc3b7858123c0ad0\",\"AccountSid\":\"ACb655a10c1c2222e4af158c5395d64beb\",\"From\":\"+1xxxxxxx\",\"ApiVersion\":\"2010-04-01\"}';
echo stripslashes($json);
I'm trying to retrieve channel, and than add user to this channel.
Call to API with
https://www.twilio.com/docs/api/ip-messaging/rest/channels#retrieve-a-channel
returns
{"uri":"/v1/Services/ISdb4f1f1479164d12b532f935aaca8619/Channels/qwe123","sid":"qwe123"}
which is useless, because i need channel Sid to add a user.
My code:
$uniqueName = 'qwe123';
$this->client = new \IPMessaging_Services_Twilio($params['accountSid'],$params['authToken']);
$service = $this->client->services->get($params['serviceSid']);
$channel = $service->channels->get($uniqueName);
print $channel; exit;
The issue with the UniqueName is due to there being a "." in the UniqueName value. The REST API interprets that as an extension. Please try change your UniqueName value to "subdomain:engagement_test"
In Twilio when the ImageMedia URL is given it is accessing the twilio api as follows
https://api.twilio.com/2010-04-01/Accounts/{account sid}/Messages/{message sid}/Media/{media sid}
If you have manually logged into the twilio API that url redirects to the image located at
http://media.twiliocdn.com.s3-website-us-east-1.amazonaws.com/{account sid}/{image id}
How can I get the direct image ID from the twilio API to include in my web app?
I am working with node.js and every time I try to poll the media resources all I receive is the link to the api.twilio.com and not the mdeia.twiliocdn.com
The library doesn't handle this feature that I can find
However, if anyone else comes across the same problem here is the solution
install request.
Then just get NumMedia and MediaUrl parameters...
if(req.body.NumMedia > 0){
var request = require('request')
request.get(req.body.MediaUrl0).auth(config.twilio.sid, config.twilio.auth, false).pipe(fs.createWriteStream("/var/www/app/public/mms/" + sid + '1.jpg' ));
}
Remember that up to 10 images can be sent so you would just need the logic too gather those extra images.
How do I query the contents of a specific collection using the Python client for Google Docs API?
This is how far I've come:
client = gdata.docs.service.DocsService()
client.ClientLogin('myuser', 'mypassword')
FOLDER_FEED1 = "/feeds/documents/private/full/-/folder"
FOLDER_FEED2 = "/feeds/default/private/full/folder%3A"
feed = client.Query(uri=FOLDER_FEED1 + "?title=MyFolder&title-exact=true")
full_id = feed.entry[0].resourceId.text
(res_type, res_id) = full_id.split(":")
feed = client.Query(uri=FOLDER_FEED2 + res_id + "/contents")
for entry in feed.entry:.
print entry.title.text
The first call to Client.Query succeeds and seems to provide a valid resource ID. The second call, however, returns:
{'status': 400, 'body': 'Invalid request URI', 'reason': 'Bad Request'}
How can I correct this to get it working?
It is much easier once you have a folder entry, to call client.GetResources(entry.content.src) rather than generating the URI by yourself and using a Query.
In your case, client.GetResources(feed.entry[0].content.src).