Upload file Cordova node js - javascript

I'm trying to upload a file from a cordova app to a node server. I am getting this exception in the server side
Cannot read property 'file' of undefined
i'm newbie in javascript and i need help thanks
this is the client code
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
//
function onDeviceReady() {
// Retrieve image file location from specified source
navigator.camera.getPicture(
uploadPhoto,
function(message) { alert('get picture failed'); },
{
quality : 50,
destinationType : navigator.camera.DestinationType.FILE_URI,
sourceType : navigator.camera.PictureSourceType.PHOTOLIBRARY
}
);
}
function uploadPhoto(imageURI) {
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var params = {};
params.value1 = "test";
params.value2 = "param";
options.params = params;
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI("http://10.20.160.38:3000/images"), win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
</script>
and this is the server code
(function () {
var serverURL = "http://192.168.1.4:3000", // IMPORTANT: This URL needs to be accessible from your phone for testing.
$scroller = $('.scroller'),
// Get List of images from server
getFeed = function () {
$scroller.empty();
$.ajax({url: serverURL + "/images", dataType: "json", type: "GET"}).done(function (data) {
var l = data.length;
for (var i = 0; i < l; i++) {
$scroller.append('<img src="' + serverURL + '/' + data[i].fileName + '"/>');
}
});
},
// Upload image to server
upload = function (imageURI) {
var ft = new FileTransfer(),
options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = 'filename.jpg'; // We will use the name auto-generated by Node at the server side.
options.mimeType = "image/jpeg";
options.chunkedMode = false;
options.params = { // Whatever you populate options.params with, will be available in req.body at the server-side.
"description": "Uploaded from my phone"
};
ft.upload(imageURI, serverURL + "/images",
function (e) {
getFeed();
},
function (e) {
alert("Upload failed");
}, options);
},
// Take a picture using the camera or select one from the library
takePicture = function (e) {
var options = {
quality: 45,
targetWidth: 1000,
targetHeight: 1000,
destinationType: Camera.DestinationType.FILE_URI,
encodingType: Camera.EncodingType.JPEG,
sourceType: Camera.PictureSourceType.CAMERA
};
navigator.camera.getPicture(
function (imageURI) {
alert(imageURI);
upload(imageURI);
},
function (message) {
// We typically get here because the use canceled the photo operation. Fail silently.
}, options);
return false;
};
$('.camera-btn').on('click', takePicture);
getFeed();
}());

Related

React Native Fetch video file by chunk / YouTube Data API chunk(multipart) upload

I made a YouTube API upload app. It works great with small video file sizes but with larger sizes my app crashes. The exception happens when I try to get the video file with Fetch().
Question: Is there a way I can fetch a large file in React Native and feed it into the YouTube API in smaller chunks?
Here is my fetch code:
const fetchResponse = await fetch(videoUri);
const blob = await fetchResponse.blob();
var file = new File([blob], "video.mp4", {type: "video/mp4"});
My upload YouTube code is taken from the following git repos - supposedly supports multipart upload as well:
https://github.com/youtube/api-samples/blob/master/javascript/cors_upload.js and
https://github.com/youtube/api-samples/blob/master/javascript/upload_video.js
Here is my full upload code:
uploadVideo = async function() {
var match = this.state.match.value;
var video = match.mergedVideo;
var players = match.players;
var scoreboard = this.state.match.value.scoreboard;
var points = match.points;
var title = players[0].name + " vs. " + players[1].name + " " + scoreboard;
var description = this.descriptionBuilder(points, match.videos);
/*const fetchResponse = await fetch(video);
const blob = await fetchResponse.blob();
var file = new File([blob], "video.mp4", {type: "video/mp4"});
console.log(file);*/
const file = await DocumentPicker.pick({
type: [DocumentPicker.types.video],
});
var metadata = {
snippet: {
title: title,
description: description,
tags: ['youtube-cors-upload'],
categoryId: 22
},
status: {
privacyStatus: 'unlisted'
}
};
var uploader = new MediaUploader({
baseUrl: 'https://www.googleapis.com/upload/youtube/v3/videos',
file: file,
token: this.state.user.auth.accessToken,
metadata: metadata,
chunkSize: 1024 * 1024,
params: {
part: Object.keys(metadata).join(',')
},
onError: function(data) {
console.log(data);
var message = data;
try {
var errorResponse = JSON.parse(data);
message = errorResponse.error.message;
} finally {
alert(message);
}
}.bind(this),
onProgress: function(data) {
var currentTime = Date.now();
var bytesUploaded = data.loaded;
var totalBytes = data.total;
var bytesPerSecond = bytesUploaded / ((currentTime - window.uploadStartTime) / 1000);
var estimatedSecondsRemaining = (totalBytes - bytesUploaded) / bytesPerSecond;
var percentageComplete = (bytesUploaded * 100) / totalBytes;
this.setState({ youtubeUploadProgress: percentageComplete / 100});
console.log("Uploaded: " + bytesUploaded + " | Total: " + totalBytes + " | Percentage: " + percentageComplete + " | Esitmated seconds remaining: " + estimatedSecondsRemaining);
}.bind(this),
onComplete: function(data) {
console.log("Complete");
alert("Upload successful!");
this.setState({ youtubeUploadProgress: 0});
}.bind(this)
});
window.uploadStartTime = Date.now();
uploader.upload();
}
and this is my cors_upload.js in React Native class module:
import React, { Component } from 'react';
export default class MediaUploader extends Component {
constructor(props) {
super(props);
const obj = this;
const DRIVE_UPLOAD_URL = 'https://www.googleapis.com/upload/drive/v2/files/';
var options = props;
var noop = function() {};
this.file = options.file;
this.contentType = options.contentType || this.file.type || 'application/octet-stream';
this.metadata = options.metadata || {
'title': this.file.name,
'mimeType': this.contentType
};
this.token = options.token;
this.onComplete = options.onComplete || noop;
this.onProgress = options.onProgress || noop;
this.onError = options.onError || noop;
this.offset = options.offset || 0;
this.chunkSize = options.chunkSize || 0;
//this.retryHandler = new RetryHandler();
//this.retryHandler = new obj.RetryHandler();
this.interval = 1000; // Start at one second
this.maxInterval = 60 * 1000;
this.url = options.url;
if (!this.url) {
var params = options.params || {};
params.uploadType = 'resumable';
//this.url = this.buildUrl_(options.fileId, params, options.baseUrl);
this.url = obj.buildUrl_(options.fileId, params, options.baseUrl);
}
this.httpMethod = options.fileId ? 'PUT' : 'POST';
}
retry = function(fn) {
setTimeout(fn, this.interval);
this.interval = this.nextInterval_();
};
reset = function() {
this.interval = 1000;
};
nextInterval_ = function() {
var interval = this.interval * 2 + this.getRandomInt_(0, 1000);
return Math.min(interval, this.maxInterval);
};
getRandomInt_ = function(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
buildQuery_ = function(params) {
params = params || {};
return Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
};
buildUrl_ = function(id, params, baseUrl) {
var url = baseUrl || DRIVE_UPLOAD_URL;
if (id) {
url += id;
}
var query = this.buildQuery_(params);
if (query) {
url += '?' + query;
}
return url;
};
upload = function() {
//var self = this;
console.log("UPLOAD called", this.file.size);
var xhr = new XMLHttpRequest();
xhr.open(this.httpMethod, this.url, true);
xhr.setRequestHeader('Authorization', 'Bearer ' + this.token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('X-Upload-Content-Length', this.file.size);
xhr.setRequestHeader('X-Upload-Content-Type', this.contentType);
xhr.onload = function(e) {
console.log("ON LOAD CALLED");
if (e.target.status < 400) {
var location = e.target.getResponseHeader('Location');
this.url = location;
this.sendFile_();
} else {
this.onUploadError_(e);
}
}.bind(this);
xhr.onerror = this.onUploadError_.bind(this);
xhr.send(JSON.stringify(this.metadata));
};
sendFile_ = function() {
console.log("SEND FILE CALLED");
var content = this.file;
var end = this.file.size;
if (this.offset || this.chunkSize) {
// Only bother to slice the file if we're either resuming or uploading in chunks
if (this.chunkSize) {
end = Math.min(this.offset + this.chunkSize, this.file.size);
}
content = content.slice(this.offset, end);
}
var xhr = new XMLHttpRequest();
xhr.open('PUT', this.url, true);
xhr.setRequestHeader('Content-Type', this.contentType);
xhr.setRequestHeader('Content-Range', 'bytes ' + this.offset + '-' + (end - 1) + '/' + this.file.size);
xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
if (xhr.upload) {
xhr.upload.addEventListener('progress', this.onProgress);
}
xhr.onload = this.onContentUploadSuccess_.bind(this);
xhr.onerror = this.onContentUploadError_.bind(this);
xhr.send(content);
};
resume_ = function() {
var xhr = new XMLHttpRequest();
xhr.open('PUT', this.url, true);
xhr.setRequestHeader('Content-Range', 'bytes */' + this.file.size);
xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
if (xhr.upload) {
xhr.upload.addEventListener('progress', this.onProgress);
}
xhr.onload = this.onContentUploadSuccess_.bind(this);
xhr.onerror = this.onContentUploadError_.bind(this);
xhr.send();
};
extractRange_ = function(xhr) {
var range = xhr.getResponseHeader('Range');
if (range) {
this.offset = parseInt(range.match(/\d+/g).pop(), 10) + 1;
}
};
onContentUploadSuccess_ = function(e) {
if (e.target.status == 200 || e.target.status == 201) {
this.onComplete(e.target.response);
} else if (e.target.status == 308) {
this.extractRange_(e.target);
this.reset();
this.sendFile_();
}
};
onContentUploadError_ = function(e) {
if (e.target.status && e.target.status < 500) {
this.onError(e.target.response);
} else {
this.retry(this.resume_.bind(this));
}
};
onUploadError_ = function(e) {
this.onError(e.target.response); // TODO - Retries for initial upload
};
}
UPDATE 1:
To avoid using Fetch() I decided to use React Native Document Picker. Now I can select the video file and pass it to the MediaUploader following this guide: https://alishavineeth.medium.com/upload-a-video-from-a-mobile-device-to-youtube-using-react-native-eb2fa54a7445
Now if I set the chunkSize option I will receive a .slice array exception because the object structure doesn't match. If I pass the file without the chunkSize option the metadata uploads to YouTube but the video status will be stuck on processing without any other errors. The video upload process never begins.
DocumentPicker responds with the following object after I select my file:
[{"fileCopyUri": "content://com.android.providers.media.documents/document/video%3A7853", "name": "video_1629795128339.mp4", "size": 192660773, "type": "video/mp4", "uri": "content://com.android.providers.media.documents/document/video%3A7853"}]
UPDATE 2:
Managed to fix my DocumentPicker file issue(from my Update 1) with changing React Native Document Picker to Expo Document Picker.
Now I am able to select large files and call the upload function - the metadata uploads, the video file begins to upload as well but the app crashes during the upload. If I set the chunkSize option on the MediaUploader object I get [TypeError: content.slice is not a function. (In 'content.slice(this.offset, end)', 'content.slice' is undefined)]
Expo Document Picker responds with the following object after I select my video file:
{"name": "video_1629801588164.mp4", "size": 5799179, "type": "video/mp4", "uri": "file:///data/user/0/com.tennis.rec/cache/DocumentPicker/8b350fbf-1b66-4a78-a10f-b61eb2ed3032.mp4"}
UPDATE 3 - RESOLVED!!!
The chunk upload is working now!!! I modified my cors_upload.js file where the chunkSize is being evaluated and sliced with the following code:
if (this.offset || this.chunkSize) {
// Only bother to slice the file if we're either resuming or uploading in chunks
if (this.chunkSize) {
end = Math.min(this.offset + this.chunkSize, this.file.size);
}
console.log("CONTENT SLICE", this.offset, end, this.file.size);
//content = content.slice(this.offset, end);
var base64 = await RNFS.read(this.file.uri, this.chunkSize, this.offset, 'base64');
content = Uint8Array.from(atob(base64), c => c.charCodeAt(0));
}
I added React Native File System and I am using its read() function to load the chunk as base64 and convert it back to a byte array.

not able to upload photo after upgradation of cordova

i am developing an app for android using phonegap in which i am using cordova 3.5.1.jar,required plugins and cordova 3.5.1js file after upgradation from 2.9.0 cordova.To upload camera image and video i am using below function.here i am not able to upload image to to server .When i debugged it i came to know that window.resolveLocalFileSystemURI() function is not getting executing and in filetransfer plugin it executing errorcallback function on fail.Whats the error in code please guide me to solve this issue.
filetransfer.js in plugin
var self = this;
var win = function(result) {
if (typeof result.lengthComputable != "undefined") {
if (self.onprogress) {
self.onprogress(newProgressEvent(result));
}
} else {
successCallback && successCallback(result);
}
};
exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
};
var fail = errorCallback && function(e) {
var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
//alert("error");
errorCallback(error);
};
index.html
function uploadimage(resid) {
var fileName;
for(var i=0;i<Locphotos.length;i++)
{
if (!Locphotos[i]) {
return;
}
fileName= Locphotos[i];
/* window.resolveLocalFileSystemURI(Locphotos[i], function (fileEntry) {
fileEntry.file(function (fileObj) {
fileName = fileObj.fullPath;});
}); */
server = "http://mangitna/service.asmx?op=UploadFile";
if (server) {
// Specify transfer options
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = resid+"-A-" + fileName.substr(fileName.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
options.headers = {
Connection: "close"
};
var ftLocphotos = new FileTransfer();
ftLocphotos.upload(fileName, server, function (r) {
}, function (error) {
}, options);
}
}
}
UPDATED:
after commenting resolveLocalFileSystemURL function.

Node.js formidable file upload working slow on server

I am trying to send files as form data along with some fields using http post request in angular.js and receiving file in app.post in node.js. The file sending works fine on localhost. As they say formidable uploads files at 500 mb/sec speed but on server when I am trying to send a file of 5 to 10 mb it takes 40 to 80 seconds. Please check is there any problem in my implementation.
I am using nginx and pm2 on server.
Node.js code:
// route for uploading audio asynchronously
app.post('/v1/uploadAudio', function(req, res) {
var userName, useravatar, hasfile, ismusicfile, isType, showMe, DWimgsrc, DWid, msgtime;
var imgdatetimenow = Date.now();
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/public/app/upload/music',
keepExtensions: true
});
form.on('end', function() {
res.end();
});
form.parse(req, function(err, fields, files) {
console.log("files : ", files);
console.log("fields : ", fields);
var data = {
username: fields.username,
userAvatar: fields.userAvatar,
repeatMsg: true,
hasFile: fields.hasFile,
isMusicFile: fields.isMusicFile,
istype: fields.istype,
showme: fields.showme,
dwimgsrc: fields.dwimgsrc,
dwid: fields.dwid,
serverfilename: baseName(files.file.path),
msgTime: fields.msgTime,
filename: files.file.name,
size: bytesToSize(files.file.size)
};
var audio_file = {
dwid: fields.dwid,
filename: files.file.name,
filetype: fields.istype,
serverfilename: baseName(files.file.path),
serverfilepath: files.file.path,
expirytime: imgdatetimenow + (120000)
};
files_array.push(audio_file);
ios.sockets.emit('new message music', data);
});
});
AngularJS code:
// =========================================== Audio Sending Code =====================
$scope.$watch('musicFiles', function() {
$scope.sendAudio($scope.musicFiles);
});
// opens the sent music file on music_icon click on new window
$scope.openClickMusic = function(msg) {
$http.post($rootScope.baseUrl + "/v1/getfile", msg).success(function(response) {
if (!response.isExpired) {
window.open($rootScope.baseUrl + '/' + response.serverfilename, "_blank");
} else {
var html = '<p id="alert">' + response.expmsg + '</p>';
if ($(".chat-box").has("p").length < 1) {
$(html).hide().prependTo(".chat-box").fadeIn(1500);
$('#alert').delay(1000).fadeOut('slow', function() {
$('#alert').remove();
});
}
}
});
}
// recieving new music message
$socket.on("new message music", function(data) {
if (data.username == $rootScope.username) {
data.ownMsg = true;
data.dwimgsrc = "app/images/spin.gif";
} else {
data.ownMsg = false;
}
if ((data.username == $rootScope.username) && data.repeatMsg) {
checkMessegesMusic(data);
} else {
$scope.messeges.push(data);
}
});
// replacing spinning wheel in sender message after music message delivered to everyone.
function checkMessegesMusic(msg) {
for (var i = ($scope.messeges.length - 1); i >= 0; i--) {
if ($scope.messeges[i].hasFile) {
if ($scope.messeges[i].istype === "music") {
if ($scope.messeges[i].dwid === msg.dwid) {
$scope.messeges[i].showme = true;
$scope.messeges[i].serverfilename = msg.serverfilename;
$scope.messeges[i].filename = msg.filename;
$scope.messeges[i].size = msg.size;
$scope.messeges[i].dwimgsrc = "app/images/musicplay_icon.png";
break;
}
}
}
};
}
// download music file if it exists on server else return error message
$scope.downloadMusic = function(ev, elem) {
var search_id = elem.id;
for (var i = ($scope.messeges.length - 1); i >= 0; i--) {
if ($scope.messeges[i].hasFile) {
if ($scope.messeges[i].istype === "music") {
if ($scope.messeges[i].dwid === search_id) {
$http.post($rootScope.baseUrl + "/v1/getfile", $scope.messeges[i]).success(function(response) {
if (!response.isExpired) {
var linkID = "#" + search_id + "A";
$(linkID).find('i').click();
return true;
} else {
var html = '<p id="alert">' + response.expmsg + '</p>';
if ($(".chat-box").has("p").length < 1) {
$(html).hide().prependTo(".chat-box").fadeIn(1500);
$('#alert').delay(1000).fadeOut('slow', function() {
$('#alert').remove();
});
}
return false;
}
});
break;
}
}
}
};
}
// validate file type to 'music file' function
$scope.validateMP3 = function(file) {
if (file.type == "audio/mp3" || file.type == "audio/mpeg") {
return true;
} else {
var html = '<p id="alert">Select MP3.</p>';
if ($(".chat-box").has("p").length < 1) {
$(html).hide().prependTo(".chat-box").fadeIn(1500);
$('#alert').delay(1000).fadeOut('slow', function() {
$('#alert').remove();
});
}
return false;
}
}
// sending new 'music file' function
$scope.sendAudio = function(files) {
if (files && files.length) {
$scope.isFileSelected = true;
for (var i = 0; i < files.length; i++) {
var file = files[i];
var dateString = formatAMPM(new Date());
var DWid = $rootScope.username + "dwid" + Date.now();
var audio = {
username: $rootScope.username,
userAvatar: $rootScope.userAvatar,
hasFile: $scope.isFileSelected,
isMusicFile: true,
istype: "music",
showme: false,
dwimgsrc: "app/images/musicplay_icon.png",
dwid: DWid,
msgTime: dateString
}
$socket.emit('send-message', audio, function(data) { // sending new image message via socket
});
var fd = new FormData();
fd.append('file', file);
fd.append('username', $rootScope.username);
fd.append('userAvatar', $rootScope.userAvatar);
fd.append('hasFile', $scope.isFileSelected);
fd.append('isMusicFile', true);
fd.append('istype', "music");
fd.append('showme', false);
fd.append('dwimgsrc', "app/images/musicplay_icon.png");
fd.append('dwid', DWid);
fd.append('msgTime', dateString);
fd.append('filename', file.name);
$http.post('/v1/uploadAudio', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}).then(function(response) {
// console.log(response);
});
}
}
};
I've used Formidable on a couple of side projects, and when uploading to localhost, I do see the 500mb/sec quoted capability (depending on physical hardware of the computer).
However, when uploading a file over the internet, you are subject to the bandwidth limitations of your ISP upload speed as well as the download speed of your server.
You report that a 10MB file takes ~80 seconds to upload to the server. That's about 125KBps (or around 1 megabit/second) which seems fairly reasonable for a home/office ISP upload speed (depending on region of the world).
A good way to eliminate your home/office network performance from the troubleshooting equation would be to write a node.js script that uploads a file several times and calculates an average speed. Run that test file on your local computer, then try again from a different server in the cloud.

How to get Format Image from cordova/phonegap used getPicture From Gallery in Android?

Hy guys,
i have some question about get format picture from galery used plugin phonegap/cordova. in ios, i do not have to get format, but in android i should getting format picture, example .png / .jpg / .gif.
In my code I set :
navigator.camera.getPicture(uploadPhoto, function(message) {
alert('get picture failed');
}, {
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.SAVEDPHOTOALBUM
});
}
function uploadPhoto(imageURI) {
var options = new FileUploadOptions();
options.fileKey = "file";
if (device.platform == "Android" || device.platform == "android") {
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
}
options.mimeType = "image/jpg";
var user = Storage.getObject("user");
var params = new Object();
options.params = {
user_id: parseInt(user.id)
}
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI, "http://www.exampl.com/app/upload-receiptPhotoLibrary", win, fail, options);
}
option.filename not result file with format file, how to get format file in option.filename ?
You need to check the mime type
var sFile = new MediaFile("some.jpg", "file:///mnt/sdcard/some.jpg");
console.log("file path = " + sFile.fullPath);
sFile.getFormatData(function(metadata) {
console.log("mimeType = " + metadata.type);
}, function() {
console.log("fail");
});

Merging multiple parts of a file in Cordova

Within my Cordova app, I am downloading arbitrary files like images or video files. This is done with the Cordova file-transfer plugin and the "Range" Header, because I need to download the files in parts.
My Problem is, that I want to merge back the several small "Byte"-Files back together into the original file they once where to use that file. Every time I'm trying to read the resulting parts as binaryString via the FileReader and write them together in a new file, that file ends up a lot larger than the parts of the original file altogther and the resulting file is unusable.
Any help is appreciated.
Here is my code until now (long and ugly):
document.addEventListener('deviceready', deviceready, false);
var App;
var finishedFileUrl = "";
var async = {
sequence: function(items, callback) {
var def = $.Deferred(),
deferrers = [$.Deferred()];
for(var i = 0; i < items.length; i++) {
(function (n) {
deferrers[n + 1] = $.Deferred();
deferrers[n].always(function() {
callback(items[n], deferrers[n + 1]);
});
})(i);
}
deferrers[items.length].always(function() {
def.resolve();
});
deferrers[0].resolve();
return def.promise();
}
}
var aSmallImageArray = [
'' // Put URL to JPG accessible with Range Header Request here
];
var aByteSizeImageArray = [];
function formatDownloadArray(fileSize) {
for(var j = 1000; j <= fileSize; j += 1000) {
aByteSizeImageArray.push(j);
}
aByteSizeImageArray.push(j);
}
function deviceready() {
console.log('dv ready');
function registerHandlers() {
App = new DownloadApp();
formatDownloadArray(XXXXX); // XXXXX should be size of JPG in bytes
document.getElementById("startDl").onclick = function() {
var that = this;
console.log("load button clicked");
var folderName = "testimagefolder";
// sequence call
async.sequence(aByteSizeImageArray, function(currentBytes, iter) {
var filePath = aSmallImageArray[0];
var fileName = aSmallImageArray[0].substr(52,99) + currentBytes;
console.log(filePath);
console.log(fileName);
console.log("Starting with: " + fileName);
var uri = encodeURI(filePath);
var folderName = "testimagefolder";
document.getElementById("statusPlace").innerHTML = "<br/>Loading: " + uri;
App.load(currentBytes, uri, folderName, fileName,
function progress (percentage) {
document.getElementById("statusPlace").innerHTML = "<br/>" + percentage + "%";
},
function success (entry) {
console.log("Entry: " + entry);
document.getElementById("statusPlace").innerHTML = "<br/>Image saved to: " + App.filedir;
console.log("DownloadApp.filedir: " + App.filedir);
iter.resolve();
},
function error () {
document.getElementById("statusPlace").innerHTML = "<br/>Failed load image: " + uri;
iter.resolve();
}
);
}).then(function afterAsync () {
console.log("ASYNC DONE");
var ohNoItFailed = function ohNoItFailed (exeperro) {
console.log(exeperro);
}
// now we merge the fileparts into one file to show it
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) {
FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) {
Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function itSuccessedAgain (fileEntry) {
finishedFileUrl = fileEntry.toURL();
var directoryReader = Directory.createReader();
var allFiles = directoryReader.readEntries(function succesReadDir (fileEntries) {
async.sequence(fileEntries, function(currentFile, iterThis) {
currentFile.file(function (theActualFile) {
var myFileReader = new FileReader();
myFileReader.onload = function (content) {
console.log('FileReader onload event fired!');
console.log('File Content should be: ' + content.target.result);
fileEntry.createWriter(
function mergeImage (writer) {
writer.onwrite = function (evnt) {
console.log("Writing successful!");
iterThis.resolve();
}
writer.seek(writer.length);
writer.write(content.target.result);
}, ohNoItFailed);
};
myFileReader.readAsBinaryString(theActualFile);
}, ohNoItFailed);
}).then(function afterAsyncTwo () {
console.log("NOW THE IMAGE SHOULD BE TAKEN FROM THIS PATH: " + finishedFileUrl);
//window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) {
//FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) {
//Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function itSuccessedAgain (fileEntry) {
//fileEntry.createWriter(
document.getElementById("image_here").src = finishedFileUrl;
});
}, ohNoItFailed);
}, ohNoItFailed);
}, ohNoItFailed);
}, ohNoItFailed);
});
};
}
registerHandlers();
}
var DownloadApp = function() {}
DownloadApp.prototype = {
filedir: "",
load: function(currentBytes, uri, folderName, fileName, progress, success, fail) {
var that = this;
that.progress = progress;
that.success = success;
that.fail = fail;
filePath = "";
that.getFilesystem(
function(fileSystem) {
console.log("GotFS");
that.getFolder(fileSystem, folderName, function(folder) {
filePath = folder.toURL() + fileName;
console.log("FILEPATH: " + filePath);
console.log("URI: " + uri);
that.transferFile(currentBytes, uri, filePath, progress, success, fail);
}, function(error) {
console.log("Failed to get folder: " + error.code);
typeof that.fail === 'function' && that.fail(error);
});
},
function(error) {
console.log("Failed to get filesystem: " + error.code);
typeof that.fail === 'function' && that.fail(error);
}
);
},
getFilesystem: function (success, fail) {
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, success, fail);
},
getFolder: function (fileSystem, folderName, success, fail) {
fileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, success, fail)
},
transferFile: function (currentBytes, uri, filePath, progress, success, fail) {
var that = this;
that.progress = progress;
that.success = success;
that.fail = fail;
console.log("here we go");
console.log("filePath before Request: " + filePath);
var previousBytes = currentBytes - 1000;
var transfer = new FileTransfer();
transfer.onprogress = function(progressEvent) {
if (progressEvent.lengthComputable) {
var perc = Math.floor(progressEvent.loaded / progressEvent.total * 100);
typeof that.progress === 'function' && that.progress(perc); // progression on scale 0..100 (percentage) as number
} else {
}
};
transfer.download(
uri,
filePath,
function success (entry) {
console.log("File saved to: " + entry.toURL());
typeof that.success === 'function' && that.success(entry);
},
function errorProblem(error) {
console.log("An error has occurred: Code = " + error.code);
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code " + error.code);
typeof that.fail === 'function' && that.fail(error);
},
true,
{
headers: {
"Range": "bytes=" + previousBytes + "-" + currentBytes
}
}
);
}
}
async code by stackoverflow-user: Paul Facklam
-> Thanks a lot!
you can build a blob from other blobs, like the ones you use FileReader on now. (File()s are Blobs)
// put three blobs into a fourth:
var b=new Blob([new Blob(["hello"]), new Blob([" "]), new Blob(["world"])]);
// verify the blob has the data we expect:
var fr=new FileReader();
fr.onload=function(){alert(this.result);};
fr.readAsBinaryString(b); // shows: "hello world"
the binaryString flavor is used here to show how these low-order strings stack up, but the actual new blob instance should have all the orig (arbitrary) bytes from the original blobs, even if they aren't composed of simple strings...
Using readAsArrayBuffer() instead of readAsBinaryString() did the trick!
So instead of:
myFileReader.readAsBinaryString(theActualFile);
I did:
myFileReader.readAsBinaryArray(theActualFile);
And the resulting image file is usable.

Categories

Resources