node.js / Youtube API / Upload - node.js

Using the following code I'm tring to upload a video youtube via direct upload. I already have the access token (auth_key). I'm pretty sure I'm sending the post data incorrectly...
function upload(auth_key, devKey, callback){
fs.readFile('test.mp4', function(err, movie){
var boundary = randomString();
var xml =
'<?xml version="1.0"?>' +
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">' +
'<media:group>' +
'<media:title type="plain">Bad Wedding Toast</media:title>' +
'<media:description type="plain">I gave a bad toast at my friends wedding.</media:description>' +
'<media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">People</media:category>' +
'<media:keywords>toast, wedding</media:keywords>' +
'</media:group>' +
'</entry>'
;
var post_data =
'--' + boundary + '\n' +
'Content-Type: application/atom+xml; charset=UTF-8' + '\n' +
xml + '\n' +
'--' + boundary + '\n' +
'Content-Type: video/mp4' + '\n' +
'Content-Transfer-Encoding: binary' + '\n' +
movie + '\n' +
'--' + boundary + '--' + '\n'
;
var options = {
host: 'uploads.gdata.youtube.com',
port: 443,
path: '/feeds/api/users/default/uploads',
method: 'POST',
headers: {
'Authorization:': 'GoogleLogin auth=' + auth_key,
'GData-Version': '2',
'X-GData-Key': 'key=' + devKey,
'Slug': 'test.mp4',
'Content-Type': 'multipart/related; boundary="' + boundary + '"',
'Content-Length': post_data.length,
'Connection': 'close'
}
}
var req = https.request(options, function(res) {
var response = '';
res.on('data', function(chunk) {
response += chunk;
});
res.on('end', function(){
callback(response);
});
});
if(post_data){
req.write(post_data);
}
req.end();
req.on('error', function(e) {
console.error(e);
});
});
}
Is failing with "Invalid Request"?

You have some errors in your code, the syntax of the html request is missing "\r\n". You should also use the http library and port 80. Your Authorization header is invalid, it should not contain an ":" at the end. And I think the way your are adding the data and calculating the content length also messes things up.
I've successfully uploaded videos to youtube with the following code:
var file_reader = fs.createReadStream(file_path, {encoding: 'binary'});
var file_contents = '';
file_reader.on('data', function(data)
{
file_contents += data;
});
file_reader.on('end', function()
{
var xml =
'<?xml version="1.0"?>' +
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">' +
' <media:group>' +
' <media:title type="plain">' + title + '</media:title>' +
' <media:description type="plain">' + description + '</media:description>' +
' <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">' + category + '</media:category>' +
' <media:keywords>' + keywords + '</media:keywords>' +
' </media:group>' +
'</entry>';
var boundary = Math.random();
var post_data = [];
var part = '';
part = "--" + boundary + "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n\r\n" + xml + "\r\n";
post_data.push(new Buffer(part, "utf8"));
part = "--" + boundary + "\r\nContent-Type: video/mp4\r\nContent-Transfer-Encoding: binary\r\n\r\n";
post_data.push(new Buffer(part, 'ascii'));
post_data.push(new Buffer(file_contents, 'binary'));
post_data.push(new Buffer("\r\n--" + boundary + "--"), 'ascii');
var post_length = 0;
for(var i = 0; i < post_data.length; i++)
{
post_length += post_data[i].length;
}
var options = {
host: 'uploads.gdata.youtube.com',
port: 80,
path: '/feeds/api/users/default/uploads?alt=json',
method: 'POST',
headers: {
'Authorization': 'GoogleLogin auth=' + auth_key,
'GData-Version': '2',
'X-GData-Key': 'key=' + exports.developer_key,
'Slug': 'video.mp4',
'Content-Type': 'multipart/related; boundary="' + boundary + '"',
'Content-Length': post_length,
'Connection': 'close'
}
}
var req = http.request(options, function(res)
{
res.setEncoding('utf8');
var response = '';
res.on('data', function(chunk)
{
response += chunk;
});
res.on('end', function()
{
console.log(response);
response = JSON.parse(response);
callback(response);
});
});
for (var i = 0; i < post_data.length; i++)
{
req.write(post_data[i]);
}
req.on('error', function(e) {
console.error(e);
});
req.end();
});

Related

Jquery rest called Image not dispalyed in sharepoint online page

i am developing an share point hosted online application when i am fetch Picture Library list items successfully.But the Image is not displayed in the page. Here i attached my code whats wrong? Could any one guide to me. I am a new on Share point online App.
function LoadImages() {
appWebUrl = window.location.protocol + "//" + window.location.host + _spPageContextInfo.webServerRelativeUrl;
hostWebUrl = _spPageContextInfo.siteAbsoluteUrl;
$(function () {
var utilTargetsList = "CustomerLicenceGallary";
$.ajax({
url: appWebUrl + "/_api/SP.AppContextSite(#target)/web/lists/getbytitle('" + utilTargetsList + "')/items?#target='" + hostWebUrl + "'",
method: "GET",
headers: {
"accept": "application/json;odata=verbose", "content-type": "application/json;odata=verbose", "X-RequestDigest": jQuery("#__REQUESTDIGEST").val()
},
success: function (d) {
var stringData = JSON.stringify(d);
var jsonObject = JSON.parse(stringData);
var results = jsonObject.d.results;
for (var i = 0; i < results.length; i++) {
jQuery('#Image').attr('src', results[i]["Name"]);
break;
}
},
//success: getitemssucces
error: function (error) {
console.log(JSON.stringify(error.toString()));
}
});
});
}
$(document).ready(function () {
LoadImages();
});
<div> <img id="Image" alt="Image" /></div>
PictureLibrary List
I got answer and working fine thanks all to support.
var arrayOfImageObjects = new Array();
var currentImageIndex = 0;
var hostWebUrl;
var appWebUrl;
function GetImagesAndRotate() {
appWebUrl = window.location.protocol + "//" + window.location.host
+ _spPageContextInfo.webServerRelativeUrl;
hostWebUrl = _spPageContextInfo.siteAbsoluteUrl;
// var url = appWebUrl + "/_api/SP.AppContextSite(#target)/web/lists/getbytitle('CustomerLicenceLibrary')/items?$expand=File"
//url: appWebUrl + "/_api/SP.AppContextSite(#target)/web/lists/getbytitle('" + utilTargetsList + "')/items?$top=1&#target='" + hostWebUrl + "'&$Orderby=ID desc",
jQuery.ajax({
url: appWebUrl + "/_api/SP.AppContextSite(#target)/web/lists/getbytitle('CustomerLicenceLibrary')/items?$expand=File&#target='" + hostWebUrl + "'",
type: "GET",
headers: {
"X-HTTP-Method": "MERGE",
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
},
success: function (data) {
var result = data.d.results;
for (var i = 0; i < result.length; i++) {
var image = result[i];
var imageObject = {};
imageObject.Name = image.File.Name;
imageObject.Url = image.File.ServerRelativeUrl;
imageObject.Width = image.File.ImageWidth;
imageObject.Height = image.File.ImageHeight;
arrayOfImageObjects.push(imageObject);
}
setTimeout(NextImage, 5000);
},
error: function () {
alert("request failed");
}
});
}
function NextImage() {
if (currentImageIndex < arrayOfImageObjects.length) {
jQuery('#Image').attr('src', arrayOfImageObjects[currentImageIndex].Url);
currentImageIndex++;
}
else
currentImageIndex = 0;
setTimeout(NextImage, 5000);
}
jQuery(document).ready(function () {
GetImagesAndRotate();
});

how do I construct a signature for a delete request which delete an entity in azure datastore in nodejs REST implementation?

I am implementing REST-API for deleting key/entity from table in azure datastore, but seems it has issue in authorization token, and i think there is issue in making 'stringTosign' i.e. 'Signature' in azure.
Below are code,
const key = {
"Namespace": "my-app",
"Path": [
{
"Kind": 'tblxyz',
"Name": "test-datastore-row"
}
]
};
REST Implementation:
public async DeleteAPI(key: Key): Promise<any> {
const tableService = await this.GetTableServiceAsync(); // gives me table metadata
const url = "https://" + tableService.storageAccount + ".table.core.windows.net/" + 'tblxyz' + '(PartitionKey=' + '\'' + key.Namespace + '\'' + ',' + 'RowKey=' + '\'' + key.Path[0].Name + '\'' + ')';
const timestamp = (new Date()).toUTCString();
const stringToSign = timestamp + '\n/' + tableService.storageAccount + '/' + 'tblxyz';
const hmac = crypto.createHmac('sha256', new Buffer(tableService.storageAccessKey, 'base64'))
.update(stringToSign, 'utf-8')
.digest('base64');
return new Promise((resolve, reject) => {
request.delete({
'headers': {
'Authorization': 'SharedKeyLite ' + tableService.storageAccount + ':' + hmac,
'x-ms-date': timestamp,
'x-ms-version': '2016-05-31',
'Content-Type': 'application/json',
'If-Match': '*'
},
'url': url,
'json': true
}, function (err, result) {
if (err) {
console.log('inside delete err', JSON.stringify(err));
return reject(err);
}
if (result.statusCode !== 200 && result.statusCode !== 204) {
console.log('inside delete err: 2', JSON.stringify(result));
return reject(result.body);
}
return resolve();
});
});
}
while making call to this API, i am getting below error,
Anybody have face this problem? Need help ...!!!!
Error message:
Error: the object {
"odata.error": {
"code": "AuthenticationFailed"
"message": {
"lang": "en-US"
"value": "Server failed to authenticate the request. Make sure the value
of Authorization header is formed correctly including the
signature.\nRequestId:df933tt7-0002-0004-41c3-782e5g000000\nTime:2017-12-
19T12:16:37.5434074Z"
}
}
} was thrown, throw an Error :)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
It seems there's an issue with your stringToSign. Based on the documentation, it should include resource's encoded URI path. Can you try with the following:
const stringToSign = timestamp + '\n/' + tableService.storageAccount + '/' + 'tblxyz' + '(PartitionKey=' + '\'' + key.Namespace + '\'' + ',' + 'RowKey=' + '\'' + key.Path[0].Name + '\'' + ')';
UPDATE
Please see this sample code. Essentially the resource's path should be URL encoded:
const request = require("request");
const crypto = require("crypto");
const url = require('url');
var accountName = "account-name";
var accountKey = "account-key";
var tableName = "table-name";
var pk = "partition-key-value";
var rk = "row-key-value";
const encodedUriPath = tableName + '(PartitionKey=' + '\'' + pk + '\'' + ', ' + 'RowKey=' + '\'' + rk + '\'' + ')';
const endpoint = "https://" + accountName + ".table.core.windows.net/" + encodedUriPath;
const parsedUrl = url.parse(endpoint);
const timestamp = (new Date()).toUTCString();
console.log(url);
console.log(timestamp);
const stringToSign = timestamp + '\n/' + accountName + parsedUrl.path;
console.log('--------------------------------------');
console.log(stringToSign);
const hmac = crypto.createHmac('sha256', new Buffer(accountKey, 'base64'))
.update(stringToSign, 'utf-8')
.digest('base64');
console.log('--------------------------------------');
console.log(hmac);
request.delete({
'headers': {
'Authorization': 'SharedKeyLite ' + accountName + ':' + hmac,
'x-ms-date': timestamp,
'x-ms-version': '2016-05-31',
'Content-Type': 'application/json',
'If-Match': '*'
},
'url': endpoint,
'json': true
}, function (err, result) {
if (err) {
console.log('inside delete err', JSON.stringify(err));
} else {
console.log(JSON.stringify(result));
}
});
FYI Azure storage Node.js client library can help to fulfill such work with sample:
var azure = require('azure-storage');
var tableService = azure.createTableService();
var deleteEntity = {
PartitionKey: {'_': 'partitionKey'},
RowKey: {'_': 'rowKey'}
};
tableService.deleteEntity('mytable', deleteEntity, function(error, result, response) {
if(error) {
// Delete table entity error
} else {
// Delete table entity successfully
}
});
Would you share your concern about directly using azure-storage package?
Best Wishes

NodeJs HTTP proxy basic auth

I am trying to implement a simple HTTP proxy that will only try to perform basic auth on the target host.
So far I have the following:
var http = require('http');
const my_proxy = http.createServer(function(request, response) {
console.log(request.connection.remoteAddress + ": " + request.method + " " + request.url);
const options = {
port: 80
, host: request.headers['host']
, method: request.method
, path: request.url
, headers: request.headers
, auth : 'real_user:real_password'
}
};
var proxy_request = http.request(options);
proxy_request.on('response', function (proxy_response) {
proxy_response.on('data', function(chunk) {
response.write(chunk, 'binary');
});
proxy_response.on('end', function() {
response.end();
});
response.writeHead(proxy_response.statusCode, proxy_response.headers);
});
request.on('data', function(chunk) {
proxy_request.write(chunk, 'binary');
});
request.on('end', function() {
proxy_request.end();
});
});
my_proxy.listen(8080);
However, "auth : 'real_user:real_password'" doesn't seem to do anything. Also have tried:
...
auth: {
user: real_user,
pass: real_pass
}
...
You have to generate the auth header
var username = 'Test';
var password = '123';
var auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64');
// auth is: 'Basic VGVzdDoxMjM='
var header = {'Host': 'www.example.com', 'Authorization': auth};
var request = client.request('GET', '/', header);
DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the
var username = 'Test';
var password = '123';
// Deprecated
// var auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64');
var auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
// auth is: 'Basic VGVzdDoxMjM='
var header = {'Host': 'www.example.com', 'Authorization': auth};
var request = client.request('GET', '/', header);

Upload a video to youtube with node.js

I've made some headway with the official Google API node client but I've reached a bit of a dead end figuring out how to get my video file up to youtube.
I have a video: example.mp4
I have this code:
OAuth2Client = googleapis.OAuth2Client;
var oauth2Client = new OAuth2Client('XXXXXX', 'XXXXXXX', 'http://callback_url');
googleapis.discover('youtube', 'v3').execute(function(err, client) {
if (err) console.log(err);
// I think the following is the bones of what I want to do
client.youtube.videos.insert({}).execute(function(err, client) {
if (err) console.log(err);
});
});
I only get an error using the insert method (which I expected with no params passed), the client initialises and returns fine.
I'm not sure how to pass the video (in the same directory as the script) to YouTube. Just a pointer would be greatly appreciated.
How about this code:
var googleapis = require('googleapis');
googleapis.discover('youtube', 'v3').execute(function(err, client) {
var metadata = {
snippet: { title:'title', description: 'description'},
status: { privacyStatus: 'private' }
};
client
.youtube.videos.insert({ part: 'snippet,status'}, metadata)
.withMedia('video/mp4', fs.readFileSync('user.flv'))
.withAuthClient(auth)
.execute(function(err, result) {
if (err) console.log(err);
else console.log(JSON.stringify(result, null, ' '));
});
});
You could use this package to do that:
https://github.com/h2non/youtube-video-api
This code works for me:
var file_reader = fs.createReadStream(file_path, {encoding: 'binary'});
var file_contents = '';
file_reader.on('data', function(data)
{
file_contents += data;
});
file_reader.on('end', function()
{
var xml =
'<?xml version="1.0"?>' +
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">' +
' <media:group>' +
' <media:title type="plain">' + title + '</media:title>' +
' <media:description type="plain">' + description + '</media:description>' +
' <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">' + category + '</media:category>' +
' <media:keywords>' + keywords + '</media:keywords>' +
' </media:group>' +
'</entry>';
var boundary = Math.random();
var post_data = [];
var part = '';
part = "--" + boundary + "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n\r\n" + xml + "\r\n";
post_data.push(new Buffer(part, "utf8"));
part = "--" + boundary + "\r\nContent-Type: video/mp4\r\nContent-Transfer-Encoding: binary\r\n\r\n";
post_data.push(new Buffer(part, 'ascii'));
post_data.push(new Buffer(file_contents, 'binary'));
post_data.push(new Buffer("\r\n--" + boundary + "--"), 'ascii');
var post_length = 0;
for(var i = 0; i < post_data.length; i++)
{
post_length += post_data[i].length;
}
var options = {
host: 'uploads.gdata.youtube.com',
port: 80,
path: '/feeds/api/users/default/uploads?alt=json',
method: 'POST',
headers: {
'Authorization': 'GoogleLogin auth=' + auth_key,
'GData-Version': '2',
'X-GData-Key': 'key=' + exports.developer_key,
'Slug': 'example.mp4',
'Content-Type': 'multipart/related; boundary="' + boundary + '"',
'Content-Length': post_length,
'Connection': 'close'
}
}
var req = http.request(options, function(res)
{
res.setEncoding('utf8');
var response = '';
res.on('data', function(chunk)
{
response += chunk;
});
res.on('end', function()
{
console.log(response);
response = JSON.parse(response);
callback(response);
});
});
for (var i = 0; i < post_data.length; i++)
{
req.write(post_data[i]);
}
req.on('error', function(e) {
console.error(e);
});
req.end();
});

Node.js YouTube API Upload unable to convert video

I'm trying to upload video to youtube programatically. I chose to use Node.js for the task.
I get an XML response as well as an HTTP Status Code of 201 and I see the video appear in video manager, however the video always has the message "Failed (unable to convert video file)".
I can upload the file through YouTube's own uploader on their page and there are no problems. I only have to upload to a single account, so I set up the OAuth2 for the account and stored the refresh token. The refresh token is hard-coded, though I replace it with a variable below.
Does the refresh token need to, itself, be refreshed?
My code:
var qs = require('querystring'),
https = require('https'),
fs = require('fs');
var p_data = qs.stringify({
client_id: myClientID,
client_secret: myClientSecret,
refresh_token: refreshTokenForAccount,
grant_type: 'refresh_token'
});
var p_options = {
host: 'accounts.google.com',
port: '443',
method: 'POST',
path: '/o/oauth2/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': p_data.length,
'X-GData-Key': myDeveloperKey
}
};
var file_path = process.argv[1] || "video.mp4";
var json = "";
var p_req = https.request(p_options, function(resp){
resp.setEncoding( 'utf8' );
resp.on('data', function( chunk ){
json += chunk;
});
resp.on("end", function(){
debugger;
var access_token = JSON.parse(json).access_token;
var title="test upload1",
description="Second attempt at an API video upload",
keywords="",
category="Comedy";
var file_reader = fs.createReadStream(file_path, {encoding: 'binary'});
var file_contents = '';
file_reader.on('data', function(data)
{
file_contents += data;
});
file_reader.on('end', function()
{
var xml =
'<?xml version="1.0"?>' +
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">' +
' <media:group>' +
' <media:title type="plain">' + title + '</media:title>' +
' <media:description type="plain">' + description + '</media:description>' +
' <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">' + category + '</media:category>' +
' <media:keywords>' + keywords + '</media:keywords>' +
' </media:group>' +
'</entry>';
var boundary = Math.random();
var post_data = [];
var part = '';
part = "--" + boundary + "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n\r\n" + xml + "\r\n";
post_data.push(new Buffer(part, "utf8"));
part = "--" + boundary + "\r\nContent-Type: video/mp4\r\nContent-Transfer-Encoding: binary\r\n\r\n";
post_data.push(new Buffer(part, 'utf8'));
post_data.push(new Buffer(file_contents, 'binary'));
post_data.push(new Buffer("\r\n--" + boundary + "--\r\n\r\n", 'utf8'));
var post_length = 0;
for(var i = 0; i < post_data.length; i++)
{
post_length += post_data[i].length;
}
var options = {
host: 'uploads.gdata.youtube.com',
port: 443,
path: '/feeds/api/users/default/uploads',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + access_token,
'X-GData-Key': myDeveloperKey,
'Slug': 'video.mp4',
'Content-Type': 'multipart/related; boundary="' + boundary + '"',
'Content-Length': post_length,
'Connection': 'close'
}
}
var req = https.request(options, function(res)
{
res.setEncoding('utf8');
console.dir(res.statusCode);
console.dir(res.headers);
var response = '';
res.on('data', function(chunk)
{
response += chunk;
});
res.on('end', function()
{
console.log( "We got response: " );
console.log(response);
});
});
for (var i = 0; i < post_data.length; i++)
{
req.write(post_data[i]);
}
req.on('error', function(e) {
console.error(e);
});
req.end();
});
});
});
p_req.write(p_data);
p_req.end();
The problem was in the file being uploaded.
This line: var file_path = process.argv[1] || "video.mp4"; should have been var file_path = process.argv[2] || "video.mp4";
Note argv[1] is the absolute path to the script being run, argv[2] is the first command line argument passed to the script.
Of course YouTube would fail to convert the "video", it wasn't video at all it was the script being run.

Resources