I have videos that can be seen only if the user is authenticated. Due to which I decided to return videos in base64 format via API. However, I have quickly identified a problem, having noticed that if the file is greater than 1MB the returned data is truncated.
Example code:
$size = Storage::size($video->path);
header("Content-length: $size");
echo base64_encode(Storage::get($video->path));
<video :src="'getVideoSrc()" />
getVideo() {
this.axios.get('video/1').then(result => {
this.video = result.data;
});
},
getVideoSrc() {
return "data:video/mp4;base64," + this.getVideo();
}
How can this be resolved?
I would avoid using base64 encoding as it's not required and only blows out the size of your data stream.
If you're happy delivering the entire video (as opposed to streaming it), you can use something like this client-side.
<video :src="videoSrc">
data: () => ({ videoSrc: '' }),
methods: {
async getVideo() {
const { data } = await axios.get('video/1', { responseType: 'blob' })
this.videoSrc = URL.createObjectURL(data)
}
}
beforeDestroy() {
// clean up
URL.revokeObjectURL(this.videoSrc)
}
FYI, I'm not sure what changes you'd need to make to your server-side but I imagine it would involve omitting base64_encode()
I am (unfortunately) working on a Windows machine so I had to manually add the FileCollection package to my app, but when I run my app, I can access the file collection and file collection methods from the browser console. However, I can't seem to get the event listeners set up on an actual page. (FYI, I am using iron-router for my templating architecture.)
It seems like the code that needs to be called is just not coming in the right order, but I've experimented with where I place the code and nothing seems to make a difference.
The server side code:
// Create a file collection, and enable file upload and download using HTTP
Images = new fileCollection('images',
{ resumable: true, // Enable built-in resumable.js upload support
http: [
{ method: 'get',
path: '/:_id', // this will be at route "/gridfs/images/:_id"
lookup: function (params, query) { // uses express style url params
return { _id: params._id }; // a mongo query mapping url to myFiles
}
}
]
}
);
if (Meteor.isServer) {
// Only publish files owned by this userId, and ignore
// file chunks being used by Resumable.js for current uploads
Meteor.publish('myImages',
function () {
return Images.find({ 'metadata._Resumable': { $exists: false },
'metadata.owner': this.userId });
}
);
// Allow rules for security. Should look familiar!
// Without these, no file writes would be allowed
Images.allow({
remove: function (userId, file) {
// Only owners can delete
if (userId !== file.metadata.owner) {
return false;
} else {
return true;
}
},
// Client file document updates are all denied, implement Methods for that
// This rule secures the HTTP REST interfaces' PUT/POST
update: function (userId, file, fields) {
// Only owners can upload file data
if (userId !== file.metadata.owner) {
return false;
} else {
return true;
}
},
insert: function (userId, file) {
// Assign the proper owner when a file is created
file.metadata = file.metadata || {};
file.metadata.owner = userId;
return true;
}
});
}
The client side code (currently in main.js at the top level of the client dir):
if (Meteor.isClient) {
// This assigns a file upload drop zone to some DOM node
Images.resumable.assignDrop($(".fileDrop"));
// This assigns a browse action to a DOM node
Images.resumable.assignBrowse($(".fileBrowse"));
// When a file is added via drag and drop
Images.resumable.on('fileAdded', function(file) {
// Create a new file in the file collection to upload
Images.insert({
_id : file.uniqueIdentifier, // This is the ID resumable will use
filename : file.fileName,
contentType : file.file.type
}, function(err, _id) {// Callback to .insert
if (err) {throwError('Image upload failed');}
// Once the file exists on the server, start uploading
Images.resumable.upload();
});
});
Images.resumable.on('fileSuccess', function(file) {
var userId = Meteor.userId();
var url = '/gridfs/images/' + file._id;
Meteor.users.update(userId, {
$set : {
"profile.$.imageURL" : url
}
});
Session.set('uploading', false);
});
Images.resumable.on('fileProgress', function(file) {
Session.set('uploading', true);
});
}
I think the issue might be with using IronRouter. I'll assume you are using some layout.html via Iron router and inside it you've added your template for your file table to be shown. (I'm guessing your are following the sampleApp that came with fileCollection.). I had a problem when I did this and it had to do with where I had the code that attached the listeners. The problem is where you have the code "Images.resumable.assignDrop($(".fileDrop"));" in your client file. The way you have it now, that line of code is running before your template is rendered within the layout.html. So the code can not find the DOM element ".fileDrop". To fix this create a layout.js file and use the rendered method like this...
Template.layout.rendered = function(){
Images.resumable.assignDrop($(".fileDrop"));
}
I am using the dropzone js plugin to upload files to a php server. It is working great. I am facilitating the user to update the uploaded files. So once the user clicks on update button, the dropzone appears, and I am able to display the uploaded files in it through a JQuery-AJAX call. But my problem is that though the files are displayed in the thumbnail format, the number of files in the dropzone counts to zero. I feel that the accept function is not being triggered.But if a new file is added to the displaying list the file count is 1 though there are files already existing in it.
I am using the following code to display the files in dropzone:
var mockFile = { name: "Filename", size: 12345 };
myDropzone.options.addedfile.call(myDropzone, mockFile);
myDropzone.options.thumbnail.call(myDropzone, mockFile, "/image/url");
Can anyone help me solve this?
I think you need to push the mockFile in the dropZone manually like this
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("complete", mockFile);
myDropzone.files.push(mockFile);
It's work for me... if you need more code just ask!
Mock file is not uploaded as explained here https://github.com/enyo/dropzone/issues/418
If you want to submit the form use myDropzone.uploadFiles([]); in init()
$('input[type="submit"]').on("click", function (e) {
e.preventDefault();
e.stopPropagation();
var form = $(this).closest('#dropzone-form');
if (form.valid() == true) { //trigger ASP.NET MVC validation
if (myDropzone.getQueuedFiles().length > 0) {
myDropzone.processQueue();
} else {
myDropzone.uploadFiles([]);
}
}
});
example for U!
jQuery(function($) {
//文件上传
$(".dropzone").dropzone({
url : "pic_upload.jsp?id=<%=request.getParameter("id")%>",
addRemoveLinks : true,
dictRemoveLinks : "x",
dictCancelUpload : "x",
maxFiles : 5,
maxFilesize : 5,
acceptedFiles: "image/*",
init : function() {
//上传成功处理函数
this.on("success", function(file) {
alert("修改前:"+file.name);
});
this.on("removedfile", function(file) {
alert("File " + file.name + "removed");
//ajax删除数据库的文件信息
$.ajax({
type:'post',
url:'pic_delete.jsp?id='+file.name ,
cache:false,
success:function(data){
}
});
});
<%
if(null!=list){
for(PlaceImg img:list){%>
//add already store files on server
var mockFile = { name: "<%=img.getId()%>", size: <%=img.getFilesize()%> };
// Call the default addedfile event handler
this.emit("addedfile", mockFile);
// And optionally show the thumbnail of the file:
this.emit("thumbnail", mockFile, "<%=img.getImgUrl()%>");
<%}
}%>
}
});
I'm trying to add an existing image to my dropzone programmatically, using the dropzone.js FAQ as a guide:
// Add the existing image if it's there.
// headerDropzone is my dropzone (debug shows it as existing and initialized at this point.
var on_load_header = $( '[name="on_load_header_image"]' ).val();
var on_load_header_path = $( '[name="on_load_header_image_path"]' ).val();
if ( on_load_header ) {
// Hardcoded size value is just for testing, see my second question below.
var on_load_header_data = { name: on_load_header, size: 12345 };
// Call the default addedfile event handler
headerDropzone.options.addedfile.call( headerDropzone, on_load_header_data );
// And optionally show the thumbnail of the file:
headerDropzone.options. thumbnail.call( headerDropzone, on_load_header_data, on_load_header_path);
}
My first problem is that this is just not working. The addedfile event doesn't fire (or at least the addedfile handler in headerDropzone never fires), same goes for thumbnail.
My second problem/question is: do I have to provide the file size? I could get it server side, but I'd rather not do it if I don't actually need to.
If you need to add multiple existing files into Dropzone, declare your existing files as array and then add it into Dropzone programmatically inside a loop like so...
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("#myDropzone", {
url: "/file/post",
maxFileSize: 50,
acceptedFiles: ".pdf",
addRemoveLinks: true,
//more dropzone options here
});
//Add existing files into dropzone
var existingFiles = [
{ name: "Filename 1.pdf", size: 12345678 },
{ name: "Filename 2.pdf", size: 12345678 },
{ name: "Filename 3.pdf", size: 12345678 },
{ name: "Filename 4.pdf", size: 12345678 },
{ name: "Filename 5.pdf", size: 12345678 }
];
for (i = 0; i < existingFiles.length; i++) {
myDropzone.emit("addedfile", existingFiles[i]);
//myDropzone.emit("thumbnail", existingFiles[i], "/image/url");
myDropzone.emit("complete", existingFiles[i]);
}
The Dropzone FAQ leaves out important settings required to properly preload a dropzone with (an) existing file(s).
My init method for my dropzone:
Dropzone.options.MyDropZoneID = {
...
init: function () {
var mockFile = { name: fileName, size: fileSize, type: fileMimeType, serverID: 0, accepted: true }; // use actual id server uses to identify the file (e.g. DB unique identifier)
this.emit("addedfile", mockFile);
this.createThumbnailFromUrl(mockFile, fileUrl);
this.emit("success", mockFile);
this.emit("complete", mockFile);
this.files.push(mockFile);
...
I don't know if the above is a perfect implementation, but it is working correctly with the maxFiles setting. Which is very important if you don't want buggy behavior (like the default message displaying when it shouldn't or extra files getting uploaded). You definitely need to set the accepted property to true and add the file to the files property. The only thing that I think is not required is emitting the success. I haven't played around with that enough though to know for sure.
Note: I used the following NuGet package:
Created by: Matias Meno
Id: dropzone
Version: 4.2.0
See if the functions headerDropzone.options.addedfile and headerDropzone.options.thumbnail are actually defined. It should work the way you did it, but without further info it's difficult to tell what's wrong.
About the filesize: No, it's not necessary to actually provide the accurate filesize. It's just that Dropzone automatically displays the filesize. If you don't care if some false filesize is displayed then you can just provide some random number or 0. Otherwise you might want to hide the filesize with CSS, or with JS after you add it. (The element in question has the class dz-size.
The JavaScript version of it would look something like this:
var fileSizeElement = on_load_header_data.previewElement.querySelector(".dz-size");
fileSizeElement.parentNode.removeChild(fileSizeElement);
This is now answered in official FAQ
Dropzone.options.myDropzone = {
init: function() {
let myDropzone = this;
// If you only have access to the original image sizes on your server,
// and want to resize them in the browser:
let mockFile = { name: "Filename 2", size: 12345 };
myDropzone.displayExistingFile(mockFile, "https://i.picsum.photos/id/959/600/600.jpg");
// If the thumbnail is already in the right size on your server:
let mockFile = { name: "Filename", size: 12345 };
let callback = null; // Optional callback when it's done
let crossOrigin = null; // Added to the `img` tag for crossOrigin handling
let resizeThumbnail = false; // Tells Dropzone whether it should resize the image first
myDropzone.displayExistingFile(mockFile, "https://i.picsum.photos /id/959/120/120.jpg", callback, crossOrigin, resizeThumbnail);
myDropzone.files.push(mockFile); // line missing in official docs
// If you use the maxFiles option, make sure you adjust it to the
// correct amount:
let fileCountOnServer = 2; // The number of files already uploaded
myDropzone.options.maxFiles = myDropzone.options.maxFiles - fileCountOnServer;
}
};
Originally I was doing something along these lines to programmatically upload a pre-existing file to Dropzone:
headerDropzone.emit("addedfile", imageFile);
headerDropzone.emit("thumbnail", imageFile, imageUrl);
headerDropzone.files.push(file);
However, referencing this Dropzone Github Issue I found an easier way to directly upload:
headerDropzone.uploadFiles([imageFile])
Unfortunately there are no references to this uploadFiles method in the Dropzone Documentation, so I figured I'd share some knowledge with all you Dropzone users.
Hope this helps someone
I had the same problem and found Dropzone's handleFiles(files) method.
So if you have inputTypeFileRef, you can
// inputTypeFiles.files is an object of type FileList
var fileArray = Object.values(inputTypeFiles.files || {});
myDropZone.handleFiles(fileArray);
That will also trigger all the Dropzone's events and pass file(s) data that it normally would by dragging a file on it - progress, file size, etc.
Hope it helped.
The latest Dropzone is lack of examples and the documentation is not clear or incomplete. You can use the following to add existing images to Dropzone.
for (var i = 0; i < imagesList.length; i++) {
let name = imagesList[i];
name = name.substring(name.lastIndexOf('/') + 1);
fetch(imagesList[i])
.then(res => res.blob())
.then(blob => {
let file = new File([blob], name, blob);
myDropzone1.addFile(file);
});
}
imagesList is a list of images which you want to add to Dropzone.
However, I am still facing a problem: Images are not being added or shown in the order/sequence as in imagesList. They appear rather random. Is there a way to make the images shown in the order/sequence as in imagesList?
Many of these answers are pretty dated, this is working for me in the latest Dropzone JS at the time of writing (take note of the included comments):
init: function() {
var dzObj = this;
// In my template I looped through existing files from the database and created:
// <div class="existing-image" data-url="/path/to/file.jpg"></div>
$('.existing-image').each(function() {
// I didn't have this data - works fine without
var mockFile = { name: '', size: '', dataURL: $(this).data('url') };
// Call the default addedfile event handler
dzObj.emit("addedfile", mockFile);
// The Dropzone JS FAQ incorrectly references "file" here instead of mockFile".
// The other parameters are outdated, dataURL goes in the object above,
// and you need to pass through other parameters.
// It DOES NOT WORK without the thumbnail event being triggered.
dzObj.createThumbnailFromUrl(mockFile, dzObj.options.thumbnailWidth, dzObj.options.thumbnailHeight, dzObj.options.thumbnailMethod, true, function (dataUrl) {
dzObj.emit("thumbnail", mockFile, dataUrl);
});
// Make sure that there is no progress bar, etc...
dzObj.emit("complete", mockFile);
dzObj.options.maxFiles = dzObj.options.maxFiles - 1;
});
}
#tjbp's response worked well for me, with the following changes:
I could not delete the programatically added file and then add another. I fixed this by removing this line, which was setting "maxFiles" to 0.
// If you use the maxFiles option, make sure you adjust it to the
// correct amount:
var existingFileCount = 1; // The number of files already uploaded
myDropzone.options.maxFiles = myDropzone.options.maxFiles - existingFileCount;
To make sure the "Delete" button was visible, I had to add the following line:
if (mockFile.previewElement) {
mockFile.previewElement.classList.add("dz-success");
}
Nothing here worked for me with version 5.7.0 but this did:
var myDropzone = new Dropzone(document.body, {
url: "<?= site_url('site/upload') ?>",
acceptedFiles: "<?= $uploadFieldAcceptValue ?>",
maxFilesize: 15,
maxFiles: 5,
autoQueue: false,
thumbnailWidth: 80,
thumbnailHeight: 80,
init: function(){
var that = this;
that.on("addedfile", function(file) {
// remove the start button
var startButton = file.previewElement.querySelector(".start");
if(startButton){
startButton.parentNode.removeChild(startButton);
}
});
<?php if(is_array($userUploads) && count($userUploads) > 0) { ?>
<?php foreach($userUploads as $userUpload) { ?>
<?php $file = $userUpload['file']; ?>
var mockFile = {
name: '<?= basename($file) ?>',
size: <?= filesize($file) ?>
};
var fileUrl = '<?= base_url() . str_replace('\\', '/', preg_replace('~^'. preg_quote(FCPATH) .'~', '', $file)) ?>';
var callback = null;
var crossOrigin = null;
var resizeThumbnail = true;
that.displayExistingFile(mockFile, fileUrl, callback, crossOrigin, resizeThumbnail);
that.emit("success", mockFile);
that.emit('complete', mockFile);
<?php } ?>
that.options.maxFiles = that.options.maxFiles - <?= count($userUploads) ?>;
<?php } ?>
}
});
On Dropzone 5.7.0 there is a "displayExistingFile" function. I called it on init section, works fine.
/**
* Called when dropzone initialized
* You can add event listeners here
*/
init: function init() {
var mockFile = { name: "Filename 1.pdf", size: 12345678 };
this.displayExistingFile(mockFile, "../../assets/site/wp-content/uploads/cropped-ic_credifisco-1-192x192.png");
},
I have the following:
new qq.FileUploader({
element: $('#' + domid + ' #upload')[0],
action: '/api/panel/upload_file',
debug: true,
allowedExtensions: [
'jpg',
'jpeg',
'gif',
'png',
'bmp',
'pdf'
],
params: {
room : 'a_room',
module : 'a_module'
},
onSubmit: function(id, fileName) {
this.params.name = fileName;
},
onProgress: function(id, fileName, loaded, total) { },
onComplete : function(id, fileName, data) {
/* FINISH */
}
});
Which sends the upload request to:
case "api" :: "panel" :: "upload_file" :: Nil Post req => {
var response = true
req.body match {
case Full(file) =>
/* DO SOMETHING */
case _ => response = false
}
}
This works fine in both Firefox and Chrome, but when uploading with IE9 the file doesnt seem to get past:
req.body match {
case Full(file) =>
}
Is there something I'm missing or need to do to get this working properly?
Thanks in advance for any help, much appreciated :)
Firstly, req.body will give you an array of bytes, not a file. Lift will automatically detect if you're uploading a file or an arbitrary payload. Its not a good idea to put files into memory, especially if they might be large.
Look into req.uploadedFiles, and req.rawInputStream with OnDiskFileParamHolder.apply - if i recall how vallums uploader works, you have to manually push the input stream into the FileParamHolder, from which you can just call .file and then have a direct java.io.File instance to work with.