anytv-node-youku-uploader
Version:
A simple nodejs library for youku authentication and upload.
329 lines (262 loc) • 11.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _md5File = require('md5-file');
var _md5File2 = _interopRequireDefault(_md5File);
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _cuddle = require('cuddle');
var _cuddle2 = _interopRequireDefault(_cuddle);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _dns = require('dns');
var _dns2 = _interopRequireDefault(_dns);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var YoukuUploader = function () {
function YoukuUploader(config, _metadata, _access_token) {
_classCallCheck(this, YoukuUploader);
this.UPLOAD_TOKEN_URL = 'https://openapi.youku.com/v2/uploads/create.json';
this.UPLOAD_COMMIT_URL = 'https://openapi.youku.com/v2/uploads/commit.json';
this.metadata = _metadata;
this.client_id = config.client_id;
this.access_token = _access_token;
this.progress_callback = function () {};
this.filepath = this.metadata.filepath;
this.client_secret = config.client_secret;
this.slice_size = config.slice_size || 10240;
this.metadata.file_md5 = (0, _md5File2.default)(this.metadata.filepath);
this.metadata.file_size = _fs2.default.statSync(this.metadata.filepath).size;
this.metadata.file_ext = _path2.default.extname(this.metadata.filepath).slice(1);
}
_createClass(YoukuUploader, [{
key: 'set_slice_size',
value: function set_slice_size(size) {
this.slice_size = size;
}
}, {
key: 'get_upload_token',
value: function get_upload_token(callback) {
this.metadata.client_id = this.client_id;
this.metadata.access_token = this.access_token;
// save token before calling user callback
_cuddle2.default.get.to(this.UPLOAD_TOKEN_URL).send(this.metadata).then(this.save_upload_token.bind(this, callback));
}
}, {
key: 'save_upload_token',
value: function save_upload_token(callback, err, result, request) {
if (err) {
console.log('Error here', err);
return callback(err, result, request);
}
// save token for easier access
this.token_info = result;
callback(null, result, request);
}
}, {
key: 'create_file',
value: function create_file(callback) {
var _this = this;
if (!this.base_url) {
//resolve dns because youku wants ip instead of domain
return _dns2.default.resolve4(this.token_info.upload_server_uri, function (err, result) {
if (err) {
return callback(err);
}
var params = { upload_token: _this.token_info.upload_token };
_this.upload_ip = result[Math.floor(Math.random() * result.length)];
_this.base_url = 'http://' + _this.upload_ip + '/gupload/';
_this.create_file(callback);
});
}
var params = {
ext: this.metadata.file_ext,
file_size: this.metadata.file_size,
upload_token: this.token_info.upload_token,
slice_length: this.slice_size
};
_cuddle2.default.post.to(this.base_url + 'create_file').send(params).then(callback);
}
}, {
key: 'upload',
value: function upload(callback) {
var _this2 = this;
var start = function start() {
_this2.get_upload_token(create_file);
};
var create_file = function create_file(err, result, request) {
if (err) {
return callback(err);
}
if (_this2.video_id_callback) {
_this2.video_id_callback(result);
}
_this2.create_file(create_slice);
};
var create_slice = function create_slice(err, result) {
if (err) {
console.log('Error creating file');
return callback(err);
}
_this2.new_slice(upload_slice);
};
var upload_slice = function upload_slice(err, result, args, request) {
if (err) {
console.log('Error creating new slice');
return callback(err);
}
_this2.upload_slice(result, function (err, result) {
if (err) {
console.log('Error uploading slice');
console.log(err);
return callback(err);
}
_this2.checker = setInterval(function () {
if (_this2.finished) {
_this2.commit(callback);
clearInterval(_this2.checker);
}
}, 1000);
});
_this2.check(function (err, result) {
if (err) {
return callback(err);
}
_this2.uploader_ip = result.upload_server_ip;
_this2.finished = result.finished;
});
};
start();
}
}, {
key: 'new_slice',
value: function new_slice(callback) {
var _this3 = this;
_cuddle2.default.get.to(this.base_url + 'new_slice').send({ upload_token: this.token_info.upload_token }).then(function (err, result, request) {
if (err) {
return callback(err);
}
_this3.slice_upload_meta = result;
callback(err, result, request);
});
}
}, {
key: 'upload_slice',
value: function upload_slice(upload_meta, callback) {
var _this4 = this;
var buffer = void 0;
var _fd = void 0;
var start = function start() {
if (typeof upload_meta === 'string') {
upload_meta = JSON.parse(upload_meta);
}
buffer = new Buffer(upload_meta.length);
_fs2.default.open(_this4.metadata.filepath, 'r', read_file);
};
var read_file = function read_file(err, fd) {
_fd = fd;
// read offset and length based on youku return
_fs2.default.read(fd, buffer, 0, upload_meta.length, upload_meta.offset, call_api);
};
var call_api = function call_api(err, bytesRead) {
if (err) {
return callback(err);
}
var params = {
upload_token: _this4.token_info.upload_token,
slice_task_id: upload_meta.slice_task_id,
offset: upload_meta.offset,
length: upload_meta.length,
hash: _this4.hash(buffer.toString('binary'))
};
(0, _request2.default)({
url: _this4.base_url + 'upload_slice',
qs: params,
method: 'POST',
body: buffer,
headers: {
'Accept': 'application/json'
}
}, process_slice);
};
var process_slice = function process_slice(err, response, body) {
if (err) {
return callback(err);
}
if (typeof body === 'string') {
body = JSON.parse(body);
}
_fs2.default.close(_fd);
// continue uploading slices while slice_task_id is not 0 (done)
if (body.slice_task_id != 0) {
upload_meta.offset = body.offset;
upload_meta.length = body.length;
upload_meta.slice_task_id = body.slice_task_id;
return _this4.upload_slice(upload_meta, callback);
}
// call callback when all slices are uploaded
callback(null, body);
};
start();
}
}, {
key: 'check',
value: function check(callback) {
var _this5 = this;
var params = { upload_token: this.token_info.upload_token };
_cuddle2.default.get.to(this.base_url + 'check').send(params).then(function (err, result) {
if (err) {
return callback(err);
}
if (typeof result === 'string') {
result = JSON.parse(result);
}
if (result.status) {
switch (result.status) {
case 1:
// case 1 is `done` in their API
return callback(null, result);
default:
// while not done, pass the progress
_this5.progress_callback(result);
setTimeout(function () {
_this5.check(callback);
}, 1000);
}
}
});
}
}, {
key: 'commit',
value: function commit(callback) {
var params = {
access_token: this.access_token,
client_id: this.client_id,
upload_token: this.token_info.upload_token,
upload_server_ip: this.uploader_ip
};
_cuddle2.default.get.to(this.UPLOAD_COMMIT_URL).send(params).then(callback);
}
}, {
key: 'on_video_id',
value: function on_video_id(callback) {
this.video_id_callback = callback;
}
}, {
key: 'on_progress',
value: function on_progress(callback) {
this.progress_callback = callback;
}
}, {
key: 'hash',
value: function hash(string, algo) {
return require('crypto').createHash(algo || 'md5').update('' + string, 'ascii').digest('hex');
}
}]);
return YoukuUploader;
}();
exports.default = YoukuUploader;