I want to check if file exists, and if it does not, download it. I have tried suggested solutions in this SO question and this blog post
But none of those solution worked for me. Here is my code based on SO question:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
console.log("gotFS");
getFolder(fileSystem, video.folderName, function(folder) {
console.log("Got folder");
var filePath = folder.toURL() + "\/" + "videotest.mp4";
fileSystem.root.getFile(filePath, { create: false }, playVideo(filePath, true), transferFile(video.uri, filePath));
}, function() {
console.log("failed to get folder");
});
},
function() {
console.log("failed to get filesystem");
});
Play video function looks like this:
function playVideo(uri, hasBeenDownloaded) {
console.log("was video dowloaded already", hasBeenDownloaded);
var player = document.getElementById("videoPlayer");
var source = document.createElement("source");
source.src = uri;
source.type = "video/mp4";
player.appendChild(source);
player.load();
}
And here is transferFile function:
function transferFile(uri, filePath) {
var transfer = new FileTransfer();
transfer.download(
uri,
filePath,
function (entry) {
var targetPath = entry.toURL();
console.log("target path je", targetPath);
document.getElementById("result").innerHTML = "File saved to: " + targetPath;
playVideo(targetPath, false);
},
function (error) {
document.getElementById("result").innerHTML = "An error has occurred: Code = " + error.code;
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
}
);
}
What happens is that both playVideo and transferFile are allays called, no matter if file exists or not.
For example if file already exists, firstly only playVideo will be called and in console it will be logged:
was video dowloaded already: true
And after sometime I see that transferFile function was called, and when file is downloaded it will call playVideo and in console i can see:
was video dowloaded already: false
So why is this happening ?
P.S.
With code suggested in blog post problem is completely same, i.e. both functions are called.
Your code is passing the called function as the callback, not the function itself. Let me give an example. Imagine you have function Foo. It asks you to pass 2 callback functions - one for success, one for failure. You could do this:
function good() { alert('good'); };
function bad() { alert('bad'); };
foo(good, bad);
However, this is what you did:
foo(good(), bad());
This is why you have both being called. You need to change:
fileSystem.root.getFile(filePath, { create: false }, playVideo(filePath, true), transferFile(video.uri, filePath));
to
fileSystem.root.getFile(filePath, { create: false }, playVideo, transferFile);
which means you'll need to access the values you need not as arguments but as regular variables.
Related
i have an issue witch Multer and NestJS to upload file. I try to check if file already exist to return an error. it's working well but if i try to re-upload a file after that, i have infinite pending request. (if i remove the filter i have no problem but i overwrite the file)
here my controller code:
#UseGuards(JwtAuthGuard)
#UseGuards(RolesGuard)
#Role('SCENARISTE')
#Post('upload/sound')
#UseInterceptors(FileInterceptor('file', {
storage: diskStorage({
destination: 'files/sounds',
filename: function (req, file, callback) {
return callback(null, file.originalname);
}
}),
fileFilter: (req, file, callback) => {
if (existsSync(join('files/sounds', file.originalname))) {
return callback(new NotAcceptableException(ErrorType.FILE_ALREADY_EXIST), false);
} else {
return callback(null, true);
}
},
}))
uploadSound(#UploadedFile() file: Express.Multer.File) {
const fileReponse = {
originalname: file.originalname,
mimetype: file.mimetype,
filename: file.filename,
size: file.size,
destination: file.destination,
fieldname: file.fieldname,
path: file.path
};
return fileReponse;
}
thank in advance for your help
may be the first request not close/stop correctly ?
According to Multer's documantion, whenever you want to throw an error, you must call the callback by passing the first argument with an error, and leave the second argument or pass the false value.
Hence, try to change your code like this:
return callback(new NotAcceptableException(ErrorType.FILE_ALREADY_EXIST));
I am using nativescript-mediafilepicker as means of choosing a file, and this can read external storage successfully (I have downloaded a PDF to the 'downloads' folder on iOS and I am able to pick it.) I then try to load the file using the file system module from nativescript library, and this fails because it is listed as NativeScript encountered a fatal error: Uncaught Error: You can’t save the file “com.xxxxxx” because the volume is read only. This doesn't make sense as I am trying to read anyway - I don't understand where the saving part is from. The error comes from fileSystemModule.File.fromPath() line.
Something to note that file['file'] is file:///Users/adair/Library/Developer/CoreSimulator/Devices/82F397CE-B0B3-4ADD-AD52-805265C7AC49/data/Containers/Data/Application/7B47A8BD-6DBA-42CF-8792-38A8C5E61174/tmp/com.xxxxxx/test.pdf
Is the file automatically being pulled to an application specific directory after this media picker?
getFiles() {
let extensions = [];
if (app.ios) {
extensions = [kUTTypePDF]; // you can get more types from here: https://developer.apple.com/documentation/mobilecoreservices/uttype
} else {
extensions = ["pdf"];
}
const mediaFilePicker = new Mediafilepicker();
const filePickerOptions = {
android: {
extensions,
maxNumberFiles: 1,
},
ios: {
extensions,
maxNumberFiles: 1,
},
};
masterPermissions
.requestPermissions([masterPermissions.PERMISSIONS.READ_EXTERNAL_STORAGE,masterPermissions.PERMISSIONS.WRITE_EXTERNAL_STORAGE])
.then((fulfilled) => {
console.log(fulfilled);
mediaFilePicker.openFilePicker(filePickerOptions);
mediaFilePicker.on("getFiles", function (res) {
let results = res.object.get("results");
let file = results[0];
console.dir(file);
let fileObject = fileSystemModule.File.fromPath(file["file"]);
console.log(fileObject);
});
mediaFilePicker.on("error", function (res) {
let msg = res.object.get("msg");
console.log(msg);
});
mediaFilePicker.on("cancel", function (res) {
let msg = res.object.get("msg");
console.log(msg);
});
})
.catch((e) => {
console.log(e);
});
},
The issue I have experienced is resultant of the expectation of File.fromPath and what is returned by the file picker. File picker is returning a "file://path" URI, and File.fromPath is expecting a string of just "path".
Simply using the following instead is enough.
let fileObject = fileSystemModule.File.fromPath(file["file"].replace("file://","");
I'm trying to get the example code for the file-transfer plugin working, it's taken straight from the Cordova docs:
function downloadFile2() {
window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {
console.log('file system open: ' + fs.name);
// Make sure you add the domain name to the Content-Security-Policy <meta> element.
var url = 'http://cordova.apache.org/static/img/cordova_bot.png';
// Parameters passed to getFile create a new file or return the file if it already exists.
fs.root.getFile('downloaded-image.png', { create: true, exclusive: false }, function (fileEntry) {
download2(fileEntry, url, true);
}, function () { logError('Error creating file'); });
}, function () { logError('Error creating fs'); });
}
function download2(fileEntry, uri, readBinaryData) {
var fileTransfer = new FileTransfer();
var fileURL = fileEntry.toURL();
console.log('Downloading ' + uri + ' to ' + fileURL);
fileTransfer.download(
uri,
fileURL,
function (entry) {
console.log("Successful download...");
console.log("download complete: " + entry.toURL());
if (false && readBinaryData) {
// Read the file...
readBinaryFile(entry);
}
else {
// Or just display it.
displayImageByFileURL(entry);
}
},
function (error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
null, // or, pass false
{
//headers: {
// "Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
//}
}
);
}
function displayImageByFileURL(fileEntry) {
var elem = document.getElementById('imageElement');
elem.src = fileEntry.toURL();
}
I'm using the latest versions of the file-transfer and file plugins (1.7.1/6.0.1). I have added the domain to the Content-Security-Policy element as mentioned in the example:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: http://cordova.apache.org https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
When I run it up in the simulator (Android/iOS) from VS2017 the download fails silently. Neither the success or error callbacks are called, and it doesn't appear to generate a network request. The console log is as follows:
file system open: http_localhost_4400:Temporary
Downloading http://cordova.apache.org/static/img/cordova_bot.png to filesystem:http://localhost:4400/temporary/downloaded-image.png
That filesystem URL looked a bit odd to me, so I have tried other variants such as the full file path, using persistent storage instead of temporary, using 'cdvfile://localhost/persistent/downloaded-image.png', all with the same result. I'm at a loss as to how I can debug this further and wondering if I've missed something really obvious, so any advice appreciated...
Edit
I tried running it again today, and a dialog pooped up in Visual Studio with the message:
There is no handler for the following exec call:
FileTransfer.download("http://cordova.apache.org/static/img/cordova_bot.png", "cdvfile://localhost/persistent/downloaded-image.png", true, 1, null)
I did some more experimenting, including running it up in the VS simulator for Android. For some reason it had trouble connecting to cordova.apache.org (I was also unable to access this site in the browser on the emulator), but downloading a file from github worked correctly....
I am building PhoneGap based application for iOS platform.
I want to download few image files to a specific directory.
I want to store downloaded images in folder www/my_img/
So that in my app I can further use this image as:
<img src="my_img/downloaded.jpg" width="100px" height="100px">
I am using PhoneGap plugin for downloading images:
var url = 'http://myServer.com/img.jpg';
var filePath = 'www/my_img/';
var fileTransfer = new FileTransfer();
var uri = encodeURI(url);
fileTransfer.download(
uri,
filePath,
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
false,
{
headers: {
}
}
);
But problem is image is not getting saved in specified folder.
How can I save downloaded image in "www/my_img/" folder?
The problem is in the value for filePath. This needs to be a device-absolute-file-path or a filesystem URL.
Have a look at the comptibility notes part of the docs:
There are some predefined folders which you can use. I think the most appropriate for your case (it's r/w, without the need to set any permissions and is persistent) is:
cordova.file.dataDirectory
You could store your downloaded image there and, when done, set the image src.
Translating this to your case:
HTML
<img id="downloadedimage" width="100px" height="100px">
JS
var url = 'http://myServer.com/img.jpg';
var filePath = cordova.file.dataDirectory + '/img.png';
var fileTransfer = new FileTransfer();
var uri = encodeURI(url);
fileTransfer.download(
uri,
filePath,
function(entry) {
console.log("download complete: " + entry.fullPath);
document.getElementById("downloadedimage").src = entry.toURL();
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
false,
{
headers: {
}
}
);
I think you should before get access to the filesystem. When ok, you can download the image in the folder you create in the dir you got access. If you need, I can give you a snippet.
EDIT:
1) access to the filesystem:
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFSCategory, fail);
}
2) if filesystem's got, get main dir:
function gotFSCategory(fileSystem) {
window.fileSystem = fileSystem;
fileSystem.root.getDirectory(window.appRootDirName, {
create : true,
exclusive : false
}, dirReadyCategory, fail);
}
3) when main dir is ready, save it and go on:
function dirReadyCategory(entry) {
window.appRootDir = entry;
console.log('application dir is ready with window.appRootDir: '+JSON.stringify(window.appRootDir));
// Start my code:
start_my_code();
}
As for the filepath var, I use this one (one for each file):
var filePath = window.appRootDir.toURL() + fileName;
I am using Pase.com with js SDK for the backend of my Dart App. This works fine apart from the parse sdk accepts an object of callback functions. In dart Im unsure how to do this, I can get single callbacks working fine. But Im completely lost here.
Normal Parse JS for registering a user
var user = new Parse.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("email", "email#example.com");
// other fields can be set just like with Parse.Object
user.set("phone", "415-392-0202");
user.signUp(null, {
success: function(user) {
// Hooray! Let them use the app now.
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}
});
My Dart code
void registerSuccess(user) {
print("success");
}
void registerFailed(user, error){
print("fail");
}
void register(String email, String password)
{
js.scoped(() {
var parse = js.context.Parse;
var parseUser = new js.Proxy(parse.User);
parseUser.set("username", "my name");
parseUser.set("password", "my pass");
parseUser.set("email", "email#example.com");
print(parseUser.getEmail());
var callbackSuccess = new js.Callback.once(() => registerSuccess());
var callbackFailed = new js.Callback.once(() => registerFailed());
parseUser.signUp(null,{"success":callbackSuccess, "error": callbackFailed});
//parseUser.signUp();
});
}
Also the callback function needs accept vars passed back from the js.
Any help would be a appreciated, I have be spinning my wheels for 2 days on this.
Instead of :
var callbackSuccess = new js.Callback.once(() => registerSuccess());
var callbackFailed = new js.Callback.once(() => registerFailed());
parseUser.signUp(null,{"success":callbackSuccess, "error": callbackFailed});
use :
var callbackSuccess = new js.Callback.once(registerSuccess);
var callbackFailed = new js.Callback.once(registerFailed);
parseUser.signUp(null, js.map({"success":callbackSuccess, "error": callbackFailed}));