Google Text-To-Speech API - text-to-speech

I want to know how can I use Google Text-to-Speech API in my .NET project. I think I need to call a URL to use the web service, but the idea for me is not clear. Can anyone help?

Old answer:
Try using this URL:
http://translate.google.com/translate_tts?tl=en&q=Hello%20World
It will automatically generate a wav file which you can easily get with an HTTP request through any .net programming.
Edit:
Ohh Google, you thought you could prevent people from using your wonderful service with flimsy http header verification.
Here is a solution to get a response in multiple languages (I'll try to add more as we go):
NodeJS
// npm install `request`
const fs = require('fs');
const request = require('request');
const text = 'Hello World';
const options = {
url: `https://translate.google.com/translate_tts?ie=UTF-8&q=${encodeURIComponent(text)}&tl=en&client=tw-ob`,
headers: {
'Referer': 'http://translate.google.com/',
'User-Agent': 'stagefright/1.2 (Linux;Android 5.0)'
}
}
request(options)
.pipe(fs.createWriteStream('tts.mp3'))
Curl
curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=Hello%20Everyone&tl=en&client=tw-ob' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3
Note that the headers are based on #Chris Cirefice's example, if they stop working at some point I'll attempt to recreate conditions for this code to function. All credits for the current headers go to him and the wonderful tool that is WireShark. (also thanks to Google for not patching this)

In an update to Schahriar SaffarShargh's answer, Google has recently implemented a 'Google abuse' feature, making it impossible to send just any regular old HTTP GET to a URL such as:
http://translate.google.com/translate_tts?tl=en&q=Hello%20World
which worked just fine and dandy previously. Now, following such a link presents you with a CAPTCHA. This also affects HTTP GET requests out-of-browser (such as with cURL), because using that URL gives a redirect to the abuse protection page (the CAPTCHA).
To start, you have to add the query parameter client to the request URL:
http://translate.google.com/translate_tts?tl=en&q=Hello%20World&client=t
Google Translate sends &client=t, so you should too.
Before you make that HTTP request, make sure that you set the Referer header:
Referer: http://translate.google.com/
Evidently, the User-Agent header is also required, but interestingly enough it can be blank:
User-Agent:
Edit: NOTE - on some user-agents, such as Android 4.X, the custom User-Agent header is not sent, meaning that Google will not service the request. In order to solve that problem, I simply set the User-Agent to a valid one, such as stagefright/1.2 (Linux;Android 5.0). Use Wireshark to debug requests (as I did) if Google's servers are not responding, and ensure that these headers are being set properly in the GET! Google will respond with a 503 Service Unavailable if the request fails, followed by a redirect to the CAPTCHA page.
This solution is a bit brittle; it is entirely possible that Google will change the way they handle these requests in the future, so in the end I would suggest asking Google to make a real API endpoint (free or paid) that we can use without feeling dirty for faking HTTP headers.
Edit 2: For those interested, this cURL command should work perfectly fine to download an mp3 of Hello in English:
curl 'http://translate.google.com/translate_tts?ie=UTF-8&q=Hello&tl=en&client=t' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3
As you may notice, I have set both the Referer and User-Agent headers in the request, as well as added the client=t parameter to the querystring. You may use https instead of http, your choice!
Edit 3: Google now requires a token for each GET request (noted by tk in the querystring). Below is the revised cURL command that will correctly download a TTS mp3:
curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=hello&tl=en&tk=995126.592330&client=t' -H 'user-agent: stagefright/1.2 (Linux;Android 5.0)' -H 'referer: https://translate.google.com/' > google_tts.mp3
Notice the &tk=995126.592330 in the querystring; this is the new token. I obtained this token by pressing the speaker icon on translate.google.com and looking at the GET request. I simply added this querystring parameter to the previous cURL command, and it works.
NOTE: obviously this solution is very frail, and breaks at the whim of the architects at Google who introduce new things like tokens required for the requests. This token may not work tomorrow (though I will check and report back)... the point is, it is not wise to rely on this method; instead, one should turn to a commercial TTS solution, especially if using TTS in production.
For further explanation of the token generation and what you might be able to do about it, see Boude's answer.
If this solution breaks any time in the future, please leave a comment on this answer so that we can attempt to find a fix for it!

Expanding on Chris' answer. I managed to reverse engineer the token generation process.
The token for the request is based on the text and a global TKK variable set in the page script. These are hashed in JavaScript thus resulting in the tk param.
Somewhere in the page script you will find something like this:
TKK='403413';
This is the amount of hours passed since epoch.
The text is pumped in the following function (somewhat deobfuscated):
var query = "Hello person";
var cM = function(a) {
return function() {
return a
}
};
var of = "=";
var dM = function(a, b) {
for (var c = 0; c < b.length - 2; c += 3) {
var d = b.charAt(c + 2),
d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
d = b.charAt(c + 1) == Tb ? a >>> d : a << d;
a = b.charAt(c) == Tb ? a + d & 4294967295 : a ^ d
}
return a
};
var eM = null;
var cb = 0;
var k = "";
var Vb = "+-a^+6";
var Ub = "+-3^+b+-f";
var t = "a";
var Tb = "+";
var dd = ".";
var hoursBetween = Math.floor(Date.now() / 3600000);
window.TKK = hoursBetween.toString();
fM = function(a) {
var b;
if (null === eM) {
var c = cM(String.fromCharCode(84)); // char 84 is T
b = cM(String.fromCharCode(75)); // char 75 is K
c = [c(), c()];
c[1] = b();
// So basically we're getting window.TKK
eM = Number(window[c.join(b())]) || 0
}
b = eM;
// This piece of code is used to convert d into the utf-8 encoding of a
var d = cM(String.fromCharCode(116)),
c = cM(String.fromCharCode(107)),
d = [d(), d()];
d[1] = c();
for (var c = cb + d.join(k) +
of, d = [], e = 0, f = 0; f < a.length; f++) {
var g = a.charCodeAt(f);
128 > g ? d[e++] = g : (2048 > g ? d[e++] = g >> 6 | 192 : (55296 == (g & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (g = 65536 + ((g & 1023) << 10) + (a.charCodeAt(++f) & 1023), d[e++] = g >> 18 | 240, d[e++] = g >> 12 & 63 | 128) : d[e++] = g >> 12 | 224, d[e++] = g >> 6 & 63 | 128), d[e++] = g & 63 | 128)
}
a = b || 0;
for (e = 0; e < d.length; e++) a += d[e], a = dM(a, Vb);
a = dM(a, Ub);
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return a.toString() + dd + (a ^ b)
};
var token = fM(query);
var url = "https://translate.google.com/translate_tts?ie=UTF-8&q=" + encodeURI(query) + "&tl=en&total=1&idx=0&textlen=12&tk=" + token + "&client=t";
document.write(url);
I managed to successfully port this to python in my fork of gTTS, so I know this works.
Edit: By now the token generation code used by gTTS has been moved into gTTS-token.
Edit 2: Google has changed the API (somewhere around 2016-05-10), this method requires some modification. I'm currently working on this. In the meantime changing the client to tw-ob seems to work.
Edit 3:
The changes are minor, yet annoying to say the least. The TKK now has two parts. Looking something like 406986.2817744745. As you can see the first part has remained the same. The second part is the sum of two seemingly random numbers. TKK=eval('((function(){var a\x3d2680116022;var b\x3d137628723;return 406986+\x27.\x27+(a+b)})())'); Here \x3d means = and \x27 is '. Both a and b change every UTC minute. At one of the final steps in the algorithm the token is XORed by the second part.
The new token generation code is:
var xr = function(a) {
return function() {
return a
}
};
var yr = function(a, b) {
for (var c = 0; c < b.length - 2; c += 3) {
var d = b.charAt(c + 2)
, d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d)
, d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d
}
return a
};
var zr = null;
var Ar = function(a) {
var b;
if (null !== zr)
b = zr;
else {
b = xr(String.fromCharCode(84));
var c = xr(String.fromCharCode(75));
b = [b(), b()];
b[1] = c();
b = (zr = window[b.join(c())] || "") || ""
}
var d = xr(String.fromCharCode(116))
, c = xr(String.fromCharCode(107))
, d = [d(), d()];
d[1] = c();
c = "&" + d.join("") +
"=";
d = b.split(".");
b = Number(d[0]) || 0;
for (var e = [], f = 0, g = 0; g < a.length; g++) {
var l = a.charCodeAt(g);
128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 == (l & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023),
e[f++] = l >> 18 | 240,
e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
e[f++] = l >> 6 & 63 | 128),
e[f++] = l & 63 | 128)
}
a = b;
for (f = 0; f < e.length; f++)
a += e[f],
a = yr(a, "+-a^+6");
a = yr(a, "+-3^+b+-f");
a ^= Number(d[1]) || 0;
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return c + (a.toString() + "." + (a ^ b))
}
;
Ar("test");
Of course I can't generate a valid url anymore, since I don't know how a and b are generated.

An additional alternative is: responsivevoice.org a simple example JsFiddle is Here
HTML
<div id="container">
<input type="text" name="text">
<button id="gspeech" class="say">Say It</button>
<audio id="player1" src="" class="speech" hidden></audio>
</div>
JQuery
$(document).ready(function(){
$('#gspeech').on('click', function(){
var text = $('input[name="text"]').val();
responsiveVoice.speak("" + text +"");
<!-- http://responsivevoice.org/ -->
});
});
External Resource:
https://code.responsivevoice.org/responsivevoice.js

i have created this like : q= urlencode & tl = language name
Just try this :
https://translate.google.com.vn/translate_tts?ie=UTF-8&q=%E0%A6%86%E0%A6%AE%E0%A6%BF%20%E0%A6%A4%E0%A7%8B%E0%A6%AE%E0%A6%BE%E0%A6%AF%E0%A6%BC%20%E0%A6%AD%E0%A6%BE%E0%A6%B2%E0%A7%8B%E0%A6%AC%E0%A6%BE%E0%A6%B8%E0%A6%BF+&tl=bn&client=tw-ob

Allright, so Google has introduces tokens (see the tk parameter in the new url) and the old solution doesn't seem to work. I've found an alternative - which I even think is better-sounding, and has more voices! The command isn't pretty, but it works. Please note that this is for testing purposes only (I use it for a little domotica project) and use the real version from acapella-group if you're planning on using this commercially.
curl $(curl --data 'MyLanguages=sonid10&MySelectedVoice=Sharon&MyTextForTTS=Hello%20World&t=1&SendToVaaS=' 'http://www.acapela-group.com/demo-tts/DemoHTML5Form_V2.php' | grep -o "http.*mp3") > tts_output.mp3
Some of the supported voices are;
Sharon
Ella (genuine child voice)
EmilioEnglish (genuine child voice)
Josh (genuine child voice)
Karen
Kenny (artificial child voice)
Laura
Micah
Nelly (artificial child voice)
Rod
Ryan
Saul
Scott (genuine teenager voice)
Tracy
ValeriaEnglish (genuine child voice)
Will
WillBadGuy (emotive voice)
WillFromAfar (emotive voice)
WillHappy (emotive voice)
WillLittleCreature (emotive voice)
WillOldMan (emotive voice)
WillSad (emotive voice)
WillUpClose (emotive voice)
It also supports multiple languages and more voices - for that I refer you to their website; http://www.acapela-group.com/

You can download the Voice using Wget:D
wget -q -U Mozilla "http://translate.google.com/translate_tts?tl=en&q=Hello"
Save the output into a mp3 file:
wget -q -U Mozilla "http://translate.google.com/translate_tts?tl=en&q=Hello" -O hello.mp3
Enjoy !!

Google text to speech
<!DOCTYPE html>
<html>
<head>
<script>
function play(id){
var text = document.getElementById(id).value;
var url = 'http://translate.google.com/translate_tts?tl=en&q='+text;
var a = new Audio(url);
a.play();
}
</script>
</head>
<body>
<input type="text" id="text" />
<button onclick="play('text');"> Speak it </button>
</body>
</html>

Use http://www.translate.google.com/translate_tts?tl=en&q=Hello%20World
note the www.translate.google.com

As of now, Google official Text-to-Speech service is available at https://cloud.google.com/text-to-speech/
It's free for the first 4 million characters.

I used the url as above: http://translate.google.com/translate_tts?tl=en&q=Hello%20World
And requested with python library..however I'm getting HTTP 403 FORBIDDEN
In the end I had to mock the User-Agent header with the browser's one to succeed.

Go to console.developer.google.com login and get an API key
or use microsoft bing's API
https://msdn.microsoft.com/en-us/library/?f=255&MSPPError=-2147217396
or even better use AT&T's speech API developer.att.com(paid one)
For voice recognition
Public Class Voice_recognition
Public Function convertTotext(ByVal path As String, ByVal output As String) As String
Dim request As HttpWebRequest = DirectCast(HttpWebRequest.Create("https://www.google.com/speech-api/v1/recognize?xjerr=1&client=speech2text&lang=en-US&maxresults=10"), HttpWebRequest)
'path = Application.StartupPath & "curinputtmp.mp3"
request.Timeout = 60000
request.Method = "POST"
request.KeepAlive = True
request.ContentType = "audio/x-flac; rate=8000"
request.UserAgent = "speech2text"
Dim fInfo As New FileInfo(path)
Dim numBytes As Long = fInfo.Length
Dim data As Byte()
Using fStream As New FileStream(path, FileMode.Open, FileAccess.Read)
data = New Byte(CInt(fStream.Length - 1)) {}
fStream.Read(data, 0, CInt(fStream.Length))
fStream.Close()
End Using
Using wrStream As Stream = request.GetRequestStream()
wrStream.Write(data, 0, data.Length)
End Using
Try
Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
Dim resp = response.GetResponseStream()
If resp IsNot Nothing Then
Dim sr As New StreamReader(resp)
MessageBox.Show(sr.ReadToEnd())
resp.Close()
resp.Dispose()
End If
Catch ex As System.Exception
MessageBox.Show(ex.Message)
End Try
Return 0
End Function
End Class
And for text to speech: use this.
I think you'll understand this
if didn't then use vbscript to vb/C# converter.
still didn't then contact Me.
I have done this before ,can't find the code now that this why i'm not directly givin' you the code.

Because it came up in chat here , and the first page for googeling was this one, i decided to let all in on my findings googling some more XD
you really dont need to go any length anymore to make it work simply stand on the shoulders of giants:
there is a standard
https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi.html
and an example
http://html5-examples.craic.com/google_chrome_text_to_speech.html
at least for your web projects this should work (e.g. asp.net)

#! /usr/bin/python2
# -*- coding: utf-8 -*-
def run(cmd):
import os
import sys
from subprocess import Popen, PIPE
print(cmd)
proc=Popen(cmd, stdin=None, stdout=PIPE, stderr=None, shell=True)
while True:
data = proc.stdout.readline() # Alternatively proc.stdout.read(1024)
if len(data) == 0:
print("Finished process")
break
sys.stdout.write(data)
import urllib
msg='Hello preety world'
msg=urllib.quote_plus(msg)
# -v verbosity
cmd='curl '+ \
'--output tts_responsivevoice.mp2 '+ \
"\""+'https://code.responsivevoice.org/develop/getvoice.php?t='+msg+'&tl=en-US&sv=g2&vn=&pitch=0.5&rate=0.5&vol=1'+"\""+ \
' -H '+"\""+'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0'+"\""+ \
' -H '+"\""+'Accept: audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5'+"\""+ \
' -H '+"\""+'Accept-Language: pl,en-US;q=0.7,en;q=0.3'+"\""+ \
' -H '+"\""+'Range: bytes=0-'+"\""+ \
' -H '+"\""+'Referer: http://code.responsivevoice.org/develop/examples/example2.html'+"\""+ \
' -H '+"\""+'Cookie: __cfduid=ac862i73b6a61bf50b66713fdb4d9f62c1454856476; _ga=GA1.2.2126195996.1454856480; _gat=1'+"\""+ \
' -H '+"\""+'Connection: keep-alive'+"\""+ \
''
print('***************************')
print(cmd)
print('***************************')
run(cmd)
Line:
/getvoice.php?t='+msg+'&tl=en-US&sv=g2&vn=&pitch=0.5&rate=0.5&vol=1'+"\""+ \
is responsible for language.
tl=en-US
There is another preety interesting site with tts engines that can be used in this manner.
substitute o for null
iv0na.c0m
have a nice day

The 2023 Answer:
There's a Google Text to Speech Service in Google Cloud. It is an API service. To use it, you must first enable the Text-to-Speech API in Google Console.
Next, go to APIs & Services > Credentials and create a new API Key (Create Credentials > API Key).
Finally, you can call the POST API endpoint https://texttospeech.googleapis.com/v1/text:synthesize?key=[API KEY]
{ "audioConfig": { "audioEncoding": "LINEAR16", "pitch": "0.00", "speakingRate": "1.00" }, "input": { "text": "Hello World" }, "voice": { "languageCode": "en-US", "name": "en-US-Wavenet-E" } }
Response:
{
"audioContent": "UklGRr7CAABXQVZF..."
}

Related

API call from google sheets is too long

I am trying to write a script in google sheets to update my 3commas bots. The API requires a number of mandatory fields are passed even when there's only 1 item that needs to be updated.
The code I have is below and it uses the values already read from the platform updating only the base_order_volume value. This works perfectly except for when the pairs value is long (more the 2k chars) and then I get an error from the UrlFetchApp call because the URL is too long.
var sheet = SpreadsheetApp.getActiveSheet();
var key = sheet.getRange('F4').getValue();
var secret = sheet.getRange('F5').getValue();
var baseUrl = "https://3commas.io";
var editBots = "/ver1/bots/"+bots[botCounter].id+"/update";
var patchEndPoint = "/public/api"+editBots+"?";
.
.
[loop around values in sheet]
.
.
var BaseOrder=Number(sheet.getRange(rowCounter,12).getValue().toFixed(2));
var botParams = {
"name": bots[botCounter].name,
"pairs": bots[botCounter].pairs,
"max_active_deals": bots[botCounter].max_active_deals,
"base_order_volume": BaseOrder,
"take_profit": Number(bots[botCounter].take_profit),
"safety_order_volume": bots[botCounter].safety_order_volume,
"martingale_volume_coefficient": bots[botCounter].martingale_volume_coefficient,
"martingale_step_coefficient": Number(bots[botCounter].martingale_step_coefficient),
"max_safety_orders": bots[botCounter].max_safety_orders,
"active_safety_orders_count": Number(bots[botCounter].active_safety_orders_count),
"safety_order_step_percentage": Number(bots[botCounter].safety_order_step_percentage),
"take_profit_type": bots[botCounter].take_profit_type,
"strategy_list": bots[botCounter].strategy_list,
"bot_id": bots[botCounter].id
};
var keys = Object.keys(botParams);
var totalParams = keys.reduce(function(q, e, i) {
q += e + "=" + encodeURIComponent(JSON.stringify(botParams[e])) + (i != keys.length - 1 ? "&" : "");
return q;
},endPoint);
var signature = Utilities.computeHmacSha256Signature(totalParams, secret);
signature = signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
var headers = {
'APIKEY': key,
'Signature': signature,
};
try {
var params = {
'method': 'PATCH',
'headers': headers,
'muteHttpExceptions': true
};
var response = JSON.parse(UrlFetchApp.fetch(baseUrl + totalParams, params).getContentText());
I have tried to set the botParams as a payload in the params but when I do the signature is incorrect.
I anyone knows how to use sheets to make a call using extensive length of parameters I'd appreciate any help at all
Some sample data for the bots array would be
{
"name": "TestBot",
"base_order_volume": 0.001,
"take_profit": 1.5,
"safety_order_volume": 0.001,
"martingale_volume_coefficient": 2,
"martingale_step_coefficient": 1,
"max_safety_orders": 1,
"active_safety_orders_count": 1,
"safety_order_step_percentage": 2.5,
"take_profit_type": "total",
"stop_loss_percentage": 0,
"cooldown": 0,
"pairs": ["BTC_ADA","BTC_TRX"],
"trailing_enabled":"true",
"trailing_deviation":0.5,
"strategy_list": [{"strategy":"cqs_telegram"}]
}
Thanks in advance
I'd consider using a Cloud Function to either do the heavy lifting, or, if you're worried about costs, use it as a proxy. You can then call the cloud function from Google Sheets. Cloud Functions can be written in whatever language you're most comfortable with, including Node.
Check the GCP pricing calculator to see what the cost would be. For many cases it would be completely free.
This should give you a sense of how to use cloud functions for CSV creation:
https://codelabs.developers.google.com/codelabs/cloud-function2sheet#0
Here is a SO question with an answer that explains how to query cloud functions with authentication.

Access REST API via lua script

Is there way to access rest api with pure lua script
GET / POST both way need to access and display response
i already tried
local api = nil
local function iniit()
if api == nil then
-- body
api = require("http://api.com")
.create()
.on_get(function ()
return {name = "Apple",
id = 12345}
end)
end
end
In linux , mac we can easily install luarocks , and then we can install curl package. It's easiest way to unix like os.
-- HTTP Get
local curl = require('curl')
curl.easy{
url = 'api.xyz.net?a=data',
httpheader = {
"X-Test-Header1: Header-Data1",
"X-Test-Header2: Header-Data2",
},
writefunction = io.stderr -- use io.stderr:write()
}
:perform()
:close()
In windows i faced several problems. Cant install luarocks correctly. then luarock install command not work correctl, etc..
In first dwnload lua from official site, and then create structure like (below web site)
http://fuchen.github.io/dev/2013/08/24/install-luarocks-on-windows/
then i download lua luadist
http://luadist.org/
then i got same structure luadist extracted folder and lua folder.
merged luadist folder and lua folder
Finaly we can use http.soket
local http=require("socket.http");
local request_body = [[login=user&password=123]]
local response_body = {}
local res, code, response_headers = http.request{
url = "api.xyz.net?a=data",
method = "GET",
headers =
{
["Content-Type"] = "application/x-www-form-urlencoded";
["Content-Length"] = #request_body;
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(response_body),
}
print(res)
print(code)
if type(response_headers) == "table" then
for k, v in pairs(response_headers) do
print(k, v)
end
end
print("Response body:")
if type(response_body) == "table" then
print(table.concat(response_body))
else
print("Not a table:", type(response_body))
end
IF YOU DO THESE STEPS CORRECTLY , THIS WILL BE WORK 1000% SURE

Curl doesn't download all the records from the website

Using the API to download the companies' complete call log. The documentation states that to download all without pagination to list 0 for number of records per page. This does not work for me. What am I doing wrong?
Tried 0
curl --request GET \
--url 'https://platform.ringcentral.com/restapi/v1.0/account/~/call-log?view=Simple&dateFrom=2019-07-26&dateTo=2019-07-28&page=1&perPage=0' \
--header 'accept: application/json' \
--header 'authorization: Bearer <MyToken>'
Expected full call log. Returned only 99 records
As per this link, "1000 is the max perPage setting. If there are more than 1000 records, you will be able to call the nextPage in a URL that's provided in the API response paging property."
https://forums.developers.ringcentral.com/questions/329/exporting-call-log-data.html
You can try removing the page option
As per this below link the solution to read at once without pagination they suggested is:
read all extensions under your account.
read call log of each
extension one at a time.
ref: https://forums.developers.ringcentral.com/questions/1254/how-to-read-all-users-call-logs-at-once.html
The documentation states that to download all without pagination to list 0 for number of records per page.
I searched through the docs, but couldn't find that line or anything specifically related.
The API Spec for the perPage query parameter for the current endpoint reads the following:
/restapi/v1.0/account/{accountId}/call-log:
get:
tags:
...
parameters:
...
- name: perPage
in: query
description: Indicates the page size (number of items)
default: 100
required: false
type: integer
...
Though by taking a look at one of the examples provided, I assume that to get max logs perPage should be set to 1000 and page should not be provided as the following function suggest:
function readCallLogs(){
var configs = {}
if ($('#phoneNumber').val() != "")
configs['phoneNumber'] = $('#phoneNumber').val()
if ($('#extension').val() != "")
configs['extensionNumber'] = $('#extension').val()
if ($('#direction').val() != "default")
configs['direction'] = $('#direction').val()
if ($('#type').val() != "default")
configs['type'] = $('#type').val()
if ($('#transport').val() != "default")
configs['transport'] = $('#transport').val()
configs['view'] = $('#view').val()
configs['showBlocked'] = $('#showBlocked').is(":checked")
configs['withRecording'] = $('#withRecording').is(":checked")
configs['dateFrom'] = $("#fromdatepicker").val() + "T00:00:00.000Z"
configs['dateTo'] = $("#todatepicker").val() + "T23:59:59.999Z"
configs['perPage'] = 1000
var url = "readlogs?access=" + $('#access_level').val();
var posting = $.post( url, configs );
posting.done(function( response ) {
var res = JSON.parse(response)
if (res.hasOwnProperty('calllog_error')){
alert(res.calllog_error)
}else{
callLogsData = new CallLogsData(JSON.parse(response))
drawGraphs()
}
});
posting.fail(function(response){
alert(response.statusText);
});
}
Hence you should try editing your initial call to match the following:
GET /restapi/v1.0/account/~/call-log?view=Simple&dateFrom=2019-07-26&dateTo=2019-07-28&perPage=1000 HTTP/1.1
Host: platform.devtest.ringcentral.com
Accept: application/json
Authorization: Bearer U0pDMDFQMTdQQVMwMHxBQUFBeHFCSjZGR3FSYkNJREcyQUlUNTUyN085b05PZEUza2R4VV9oWjF0ZzhKOUpEekJ4WDU5T2U1czFvSzJ3WGN4NF9QWWRPMEVYNENYQjd4dmJsWHJocGJRcC1BcDlrUHZIczcycTVONm13NDZJSWN6VnZ1YzNsU3NVY2doMnd2UHlCMGxkaC1MTXlfZFk5VS0yZUUtWnpRejhKUXJtT21yMFQ0ZHpKQ1AwbnhfQmRRTTRKazR3OVNuTVE4THNOa3BfcW1oX21mUGtQdWNkUVN4ZnRaUzd8Mkt2

How do I set http headers in Adobe Illustrator ExtendScript when using the BridgeTalk HttpConnection object?

I am trying to make http post requests from within Illustrator ExtendScript (via BridgeTalk) and for the most part it is working. However, the documentation on using HttpConnection is non-existent and I am trying to figure out how to set http-headers. The HttpConnection object has both a requestheaders and responseheaders property so I suspect it is possible.
By default, the post requests are being sent with the Content-Type header "text/html", and I would like to override it so that I can use either "application/x-www-form-urlencoded" or "multipart/form-data".
Here is what I have so far:
var http = function (callback) {
var bt = new BridgeTalk();
bt.target = 'bridge' ;
var s = '';
s += "if ( !ExternalObject.webaccesslib ) {\n";
s += " ExternalObject.webaccesslib = new ExternalObject('lib:webaccesslib');\n";
s += "}\n";
s += "var html = '';\n";
s += "var http = new HttpConnection('http://requestb.in/1mo0r1z1');\n";
s += "http.method = 'POST';\n";
s += "http.requestheaders = 'Content-Type, application/x-www-form-urlencoded'\n";
s += "http.request = 'abc=123&def=456';\n";
s += "var c=0,t='';for(var i in http){t+=(i+':'+http[i]+'***');c++;}t='BEFORE('+c+'):'+t;alert(t);\n"; // Debug: to see what properties and values exist on the http object
s += "http.response = html;\n";
s += "http.execute() ;\n";
s += "http.response;\n";
s += "var t='AFTER:';for(var i in http){t+=(i+':'+http[i]+'***');}alert(t);\n"; // Debug: to see what properties and values have been set after executing
bt.body = s;
bt.onResult = function (evt) {
callback(evt);
};
bt.onError = function (evt) {
callback(evt);
};
bt.send();
};
Things to note:
If I try setting the requestheaders properties like in my code above, the request fails. If I comment it out, the request succeeds. The default value for requestheaders is undefined.
Examining the http object after a successful request, shows the reponseheaders properties to be set to: "Connection, keep-alive,Content-Length, 2,Content-Type, text/html; charset=utf-8,Date, Wed, 24 Jun 2015 09:45:40 GMT,Server, gunicorn/18.0,Sponsored-By, https://www.runscope.com,Via, 1.1 vegur". Before the request executes, the responseheaders is set to undefined.
If anyone could help me set the request headers (in particular the Content-Type header), I would be eternally grateful!
Solved it!
The key for setting the content-type header is to set the http.mime property as follows:
s += "http.mime = 'application/x-www-form-urlencoded';\n";
Also for completeness, you can add your own custom headers as follows:
s += "http.requestheaders = ['My-Sample-Header', 'some-value'];\n";
(It turns out the headers is an array which takes the format [key1, value1, key2, value2, .......])

Sending form data with an HTTP PUT request using Grinder API

I'm trying to replicate the following successful cURL operation with Grinder.
curl -X PUT -d "title=Here%27s+the+title&content=Here%27s+the+content&signature=myusername%3A3ad1117dab0ade17bdbd47cc8efd5b08" http://www.mysite.com/api
Here's my script:
from net.grinder.script import Test
from net.grinder.script.Grinder import grinder
from net.grinder.plugin.http import HTTPRequest
from HTTPClient import NVPair
import hashlib
test1 = Test(1, "Request resource")
request1 = HTTPRequest(url="http://www.mysite.com/api")
test1.record(request1)
log = grinder.logger.info
test1.record(log)
m = hashlib.md5()
class TestRunner:
def __call__(self):
params = [NVPair("title","Here's the title"),NVPair("content", "Here's the content")]
params.sort(key=lambda param: param.getName())
ps = ""
for param in params:
ps = ps + param.getValue() + ":"
ps = ps + "myapikey"
m.update(ps)
params.append(NVPair("signature", ("myusername:" + m.hexdigest())))
request1.setFormData(tuple(params))
result = request1.PUT()
The test runs okay, but it seems that my script doesn't actually send any of the params data to the API, and I can't work out why. There are no errors generated, but I get a 401 Unauthorized response from the API, indicating that a successful PUT request reached it, but obviously without a signature the request was rejected.
This isn't exactly an answer, more of a workaround that I came up with, that I've decided to post since this question hasn't yet received any responses, and it may help anyone else trying to achieve the same thing.
The workaround is basically to use the httplib and urllib modules to build and make the PUT request instead of the HTTPClient module.
import hashlib
import httplib, urllib
....
params = [("title", "Here's the title"),("content", "Here's the content")]
params.sort(key=lambda param: param[0])
ps = ""
for param in params:
ps = ps + param[1] + ":"
ps = ps + "myapikey"
m = hashlib.md5()
m.update(ps)
params.append(("signature", "myusername:" + m.hexdigest()))
params = urllib.urlencode(params)
print params
headers = {"Content-type": "application/x-www-form-urlencoded"}
conn = httplib.HTTPConnection("www.mysite.com:80")
conn.request("PUT", "/api", params, headers)
response = conn.getresponse()
print response.status, response.reason
print response.read()
conn.close()
(Based on the example at the bottom of this documentation page.)
You have to refer to the multi-form posting example in Grinder script gallery, but changing the Post to Put. It works for me.
files = ( NVPair("self", "form.py"), )
parameters = ( NVPair("run number", str(grinder.runNumber)), )
# This is the Jython way of creating an NVPair[] Java array
# with one element.
headers = zeros(1, NVPair)
# Create a multi-part form encoded byte array.
data = Codecs.mpFormDataEncode(parameters, files, headers)
grinder.logger.output("Content type set to %s" % headers[0].value)
# Call the version of POST that takes a byte array.
result = request1.PUT("/upload", data, headers)