Open vertangelx opened 9 years ago
Can't you construct a blob from DATA_URL
or FILE_URI
?
I don't know much about cordova, but there has to be a way to read file contents. And if you can read file contents, then you can create blobs.
From here I gather:
function onInitFs(fs) {
fs.root.getFile(fileURL, {}, function(fileEntry) {
// Get a File object representing the file.
fileEntry.file(function(file) {
//file is someting you can send through slingshot.
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
I was curious about this as well and I found out that you can construct the object from the file uri in cordova using the following:
window.resolveLocalFileSystemURL(file.uri, function(fileEntry) {
fileEntry.file(function(fileObj) {
var uploader = new Slingshot.Upload("myFileUploads")
uploader.send(fileObj, function (error, downloadUrl) {
if (error) console.log(error)
console.log(downloadUrl)
})
})
Slingshot accepts the file object fine and it goes ahead with the upload and returns the file url with success but when I view any files uploaded like this from cordova on my s3 bucket they are all 15 bytes large and obviously corrupted somewhere in the process.
If I could get some help with this issue that would be great. I have some code to upload a file to my s3 bucket from cordova with just the uri which works fine but I would prefer to just use the slingshot package for both cordova and web.
Also just noticed testing in the iOS simulator that the object doesn't get a type assigned with is an issue
I'll see if I can figure these out
@danecando thanks for sharing this. Did you check if fileObj.size
matches the size that you are looking for? Also did you try the method I've posted above?
@gsuess I couldn't get the fileEntry using the code you provided.
The file sizes in the object are correct before the upload.
@danecando did you adjust the file size accordingly in code I've provided? In that sample it was limited to 1MB (1024*1024
), which is not very high.
As for your method, 15 bytes sounds like a URI string itself. Did you check the contents of the file that is uploaded to the bucket? Also note that S3 will not overwrite files if you provide the same key as an already existing file. Instead it will silently ignore your upload.
@gsuess this is what the files contain
[object Object] <- perfect 15 bytes :p
Wonderful.
Check file objects contents with the FileReader
:
var reader = new FileReader()
reader.onload = function (event) {
var contents = event.target.result;
console.log(contents);
};
reader.readAsText(fileObject);
the onload event doesn't fire
@danecando did you check the onerror
handler then? Looks like we are getting to the bottom of it.
{"type":"error","bubbles":false,"cancelBubble":false,"cancelable":false,"lengthComputable":false,"loaded":0,"total":0,"target":{"_readyState":2,"_error":{"code":5},"_result":null,"_localURL":"cdvfile://localhost/temporary/cdv_photo_027.jpg","_realReader":{"result":null}}}
the first is what the file object looks like and the second is the readastext error
I20150119-11:23:22.806(-5)? (ios) {"name":"cdv_photo_030.jpg","localURL":"cdvfile://localhost/temporary/cdv_photo_030.jpg","type":null,"lastModified":1421684596000,"lastModifiedDate":1421684596000,"size":1396725,"start":0,"end":1396725}
I20150119-11:23:22.808(-5)? (ios) {"type":"error","bubbles":false,"cancelBubble":false,"cancelable":false,"lengthComputable":false,"loaded":0,"total":0,"target":{"_readyState":2,"_error":{"code":5},"_result":null,"_localURL":"cdvfile://localhost/temporary/cdv_photo_030.jpg","_realReader":{"result":null}}}
So the file comes from the camera? Perhaps should not load images as text...
Use .readAsDataURL()
instead.
it looks like readAsDataURL returns successfully with: data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/......... <- really long string
I think your platform doesn't support sending files with FormData
.
this would be really great to implement!
@geritol what are you referring to?
to make somehow possible to post pictures from cordova apps.
@geritol it is possible to post pictures: https://github.com/CulturalMe/meteor-slingshot/issues/24
Hey guys...
Has anyone found a good solution? I´m currently using resolveLocalFileSystemURL, but get the "[object Object]" uploaded as well...
@thomasf1 I'm getting the cordova file with fileEntry.file, turning that into a data uri, and then turning the data uri into a blob
@danecando Thanks! I´ll try that :)
Could you share some of your code? :)
@thomasf1 something like this: https://gist.github.com/danecando/92ef9240c6ab715f35c4
@danecando Thanks, that helped me a lot :)... Got it almost working, some filename stuff remaining...
@danecando Funny thing: It worked perfectly on iOS (it was our last issue, submitted to the app store), but doesn´t seem to work on Android - there the uploaded File on S3 is empty... Did you have similar issues?
@thomasf1 it works fine for me on my galaxy s4. I haven't really tested on any other android devices. I'm also sending mine through another function that resizes the image and spits out a data URI
@danecando Ah, in what cases was the build-in "targetWidth:" not quite working/satisfactory?
When using mdg:camera
https://github.com/meteor/mobile-packages/tree/master/packages/mdg:camera
you get back a DATA_URL
, which can be converted to a blob with
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
@danecando this doesnt work for me with video file :/ im getting this problem : http://stackoverflow.com/questions/26733070/cordova-capture-video-and-retrieve-base64-data
basically returns " data:video/mp4;base64," but there isn't any encoded data after the filetype.
any thoughts guys ? @gsuess @danecando @lorensr @thomasf1
Thanks
For future reference this is what i did , i had to recreate the file object from media-capture plugin with resolveLocalFileSystem
captureSuccess = (mediaFiles) ->
path = mediaFiles[0].fullPath
window.resolveLocalFileSystemURL path, (fileEntry)->
fileEntry.file((data)->
reader = new FileReader()
reader.onloadend = (e)->
console.log e.target.result
blob = b64toBlobAlt(e.target.result, 'video/mp4')
console.log blob
if blob
uploader = new Slingshot.Upload('myVideoUpload')
uploader.send blob, (error, downloadUrl) ->
if error
console.error 'Error uploading', uploader.xhr.response
else
console.log downloadUrl
Meteor.users.update Meteor.userId(), $set: 'profile.videoUrl': downloadUrl
return
reader.readAsDataURL(data)
)
return
Same issue with me too. The file
argument of the callback in FileEntry.file ( )
is accepted by uploader.send
but the file uploaded is exactly of 15 bytes, corrupted and the checksums don't match
@kevohagan Sorry, we didn´t try/use Videos...
@thomasf1 How did you resolve your file naming issues if they are (resolved that is) ?
@kevohagan : Were you able to upload videos successfully? I am not with these code.
var captureSuccess = function(mediaFiles) {
var b64toBlobAlt = function(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
};
var path = mediaFiles[0].fullPath;
window.resolveLocalFileSystemURL(path, function(fileEntry) {
fileEntry.file(function(data) {
var reader = new FileReader();
reader.onloadend = function(e) {
var blob = b64toBlobAlt(e.target.result, 'video/mp4');
if (blob) {
var uploader = new Slingshot.Upload("myFileUploads");
alert(uploader);
uploader.send(blob, function(error, downloadUrl) {
if (error) {
alert('Error uploading', uploader.xhr.response);
} else {
alert(downloadUrl);
}
});
}
};
reader.readAsDataURL(data);
});
});
};
}
I'm stuck at this, too. Tried the Blob conversion (using both code I found somewhere else and the @lorensr version), but I always get the following error message:
processMessage failed: Stack: Error: Match error: Expected particular constructor
at checkSubtree (http://meteor.local/packages/check.js?ac81167b8513b85b926c167bba423981b0c4cf9c:287:11)
at check (http://meteor.local/packages/check.js?ac81167b8513b85b926c167bba423981b0c4cf9c:67:5)
at _.extend.send (http://meteor.local/packages/edgee_slingshot.js?83a247b1bf011050d107d9d4e4ac2b3c0ae4ab34:110:7)
Files uploaded using a file-input field are working fine with my code. It's the data URI's I'm struggling with (BTW: had similar problems with CollectionFS/GridFS, so I hoped it would work better with slingshot). Would anybody who already solved this problem please be so kind and post a complete working sample? That would be great! PS: Like @elGusto I'm wondering how I can set a filename for my S3 bucket if I'm uploading the file as a data URI. I guess that's a case for the 'key' field of the directive, but maybe there's an easier way to do this?
EDIT: My problem is solved. The root cause was Meteor loading a very, very old version of Slingshot (0.0.3) instead of the latest one. Slingshot uploads now work as a charm.
Does anyone have an example that works on the iOS simulator?
None of the example work for me. The code below works for me on METEOR@1.3-cordova-beta.2 hope will help someone i don't try on iOS simulator just on actual device.
function videoCaptureSuccess(mediaFiles) {
var file = '/local-filesystem' + mediaFiles[0].fullPath;
getBlobURL(file, "video/quicktime", function(url, blob){
uploader.send(blob, function (error, downloadUrl) {
alert(downloadUrl);
});
});
}
function getBlobURL(url, mime, callback) {
var xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.responseType = "arraybuffer";
xhr.addEventListener("load", function() {
var arrayBufferView = new Uint8Array( this.response );
var blob = new Blob( [ arrayBufferView ], { type: mime } );
var url = window.URL.createObjectURL(blob);
callback(url, blob);
});
xhr.send();
}
+1
Same problem here: the file stored on AWS S3 is 15 bytes long and contains:
[object Object]
I still don't understand why exactly. It would be cool to patch Slingshot instead of using a hack. After all the purpose of Slingshot is to avoid these sort of pains.
While working on Ionic 2 app I encountered same issue with FIleReader events not firing. Turned out to be an issue with zone.js and after long hours I got an workaround here: https://github.com/driftyco/ionic-native/issues/505#issuecomment-243434491
Can we pass either
DATA_URL
orFILE_URI
from Cordova'snavigator.camera.getPicture
to the first parameter ofuploader.send
?Right now it seems that we need to pass the
file
object from aninput
withtype="file"