picture do not show in sails.js view - sails.js

My assets folder :
assets
| images
| media
| book
| pictures
i want to create new book when i upload book picture in above path, But when i try to show this image in view, the image can not be displayed and there is no error either.
my code is:
//BookController
create: function (request, response, next) {
var title = request.body.title;
var subject = request.body.subject;
var brief = request.body.brief;
var author = request.body.author;
var origin_pic_name = null;
request.file('pic').upload({
dirname: '../../assets/images/media/book/pictures/',
},function (err, file) {
if(err) console.log(err);
origin_pic_name = file[0]['fd'].split('\\').reverse()[0] ;
Book.create({title:title,subject:subject,brief:brief,author:author,pic:origin_pic_name}).exec(function (err) {
if(err) response.end(500, {error: 'Database Error'});
response.redirect('/');
});
});},
index : function (request, response, next) {
Book.find({}).exec(function (err, books) {
if(err) response.end(500, {error: 'Database Error'});
response.view('book/index', {books:books});
});},
//my index.ejs
<ol>
<% books.forEach(function (value) {%>
<h3><li> <%= value.title %></li></h3>
<ul><%= value.author %></ul>
<ul><%= value.subject %></ul>
<ul><%= value.brief %></ul>
<ul><img src="/images/media/book/pictures/<%= value.pic %>"/></ul>
<% })%>
</ol>
thank you

Out of the box, sails caches assets during the sails lift process. To get around this, for file uploads, you can alter your controller to copy the file immediately after upload.
Here is an example of how you might do that with your current controller. You may need to edit the directory strings to suit your needs.
// BookController
create: function (request, response, next) {
var title = request.body.title;
var subject = request.body.subject;
var brief = request.body.brief;
var author = request.body.author;
var origin_pic_name = null;
request.file('pic').upload({
dirname: '../../assets/images/media/book/pictures/',
},function (err, file) {
if(err) console.log(err);
origin_pic_name = file[0]['fd'].split('\\').reverse()[0];
// Variable to hold the current directory
var currentDir = '../../assets/images/media/book/pictures/' + origin_pic_name;
// Variable to hold the temp directory
var tempDir = '.tmp/public/images/media/book/pictures/' + origin_pic_name;
// copy the image from the current directory to the temp to the temp folder
fs.createReadStream(currentDir).pipe(fs.createWriteStream(tempDir));
Book.create({title:title,subject:subject,brief:brief,author:author,pic:origin_pic_name}).exec(function (err) {
if(err) response.end(500, {error: 'Database Error'});
response.redirect('/');
});
});
},

You need to be very careful when uploading images to Sails:
The Problem
Grunt is watching for changes in some folders, including the assets dir and subdirs. But that is only possible (activacted, tbh) in "Development" enviroment.
The solution
Create a images/ dir in your root.
When uploading the image, make skipper save the image there.
Write a mediaController that will catch routes like /images/media/book/:name and will try to locate and send a file:
// MediaController.js
var fs = require('fs');
var path = require('path');
module.exports = {
get : function(req, res){
var filepath = req.name.slice(1,req.name.length);
// remove this Sync to an Async
if(fs.existsSync(path.resolve(filepath))){
return res.sendfile(filepath);
} else {
return res.notFound();
}
}
}
//Routes.js
'get /images/books/:name' : 'MediaController.get'
Advantages
You can now restrict the access of images with policies, if you want to!
Better handling at image and 100% control over the fs. Good with DO Spaces, for example...

Related

How I get contain of a href and img from cgv website using axios and jsdom

I have a problem when i wanto target and get contain a href and img from this website https://www.cgv.id/en/movies/now_playing but i always wrong to get it. This is may code:
const { default: axios } = require("axios");
const { JSDOM } = require("jsdom");
(async () => {
try {
const { data } = await axios.get(
"https://www.cgv.id/en/movies/now_playing"
);
let dom = new JSDOM(data).window.document;
let list = [...dom.getElementsByClassName('movie-list-body').querySelectorAll('li')]
list = list.map(v => v.document.querySelectorAll('li a[href]').textContent.trimEnd())
console.log(list);
} catch (error) {
console.log(error);
}
})()
My code is error. How i repair it and can target to get contain a href and img it?
There are couple of issues with using JSDOM there, especially the way you are using it.
Firstly the website in question does not have any markup for the DOM element with the class name movie-list-body as you retrieve it using Axios
On further inspection I realised they are using a jQuery AJAX call to retrieve all the links and images from a JSON file.
Following is the script they are using to do so.
<script>
$(function() {
$.ajax({
type: 'GET',
url: '/en/loader/home_movie_list',
success: function(data) {
$('.movie-list-body').html(data.now_playing);
$('.comingsoon-movie-list-body').html(data.comingsoon);
$('.lazy').lazy({
combined: true
});
}
});
});
</script>
In my opinion you should just use that JSON file. However, if you still want to use JSDOM following are some of the approaches.
Given that the site requires resource processing, if you want to parse the whole page using JSDOM you will have to pass the options as mentioned in the JSDOM documentation as follows:
const options = {
contentType: "text/html",
includeNodeLocations: true,
resources: "usable",
};
let dom = new JSDOM( data, options ).window.document;
These options will allow the JSDOM to load all the resources including jQuery that will in-turn allow the Node to make the AJAX call, populate the element and then in-theory you extract the links. However, there are some CSS files that JSDOM is unable to parse.
Therefore, I think your best bet is to do something along the following lines:
const { default: axios } = require("axios");
const { JSDOM } = require("jsdom");
(async () => {
try {
const data = await axios.get(
"https://www.cgv.id/en/loader/home_movie_list"
);
const base_url = 'https://www.cgv.id';
var dom = new JSDOM(data.data.now_playing).window.document;
var lists = [ ... dom.getElementsByTagName('ul')[0].children ]
var list = lists.map( list => [ base_url+list.firstChild.href, list.firstChild.firstChild.dataset.src ] );
console.log( list );
} catch (error) {
console.log(error);
}
})()
Note:
There is only one catch with the approach mentioned above which is that if the author of the website changes the endpoint for the JSON file, your solution will stop working.

How could I load video files from my library? Ionic 3

I observed that the Native File has not been supported by the Ionic View anymore see list here.
I am trying to get a video from my library by using Native Camera to access the videos. It can return me 3 different formats of path to my videos (DATA_URL, FILE_URI, and NATIVE_URI).reference to Native Camera here
I am currently using FILE_URI as recommended in this post. It returns something like "/storage/emulated/0/DCIM/Camera/VID_20180312_210545.mp4"
Please have a look at my code below. Aiming a better understanding, the current behavior is highlighted by comments with "//** comment ***" :
addVideoToOffer(){
this.platform.ready().then(() =>{
const options: CameraOptions = {
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
destinationType: this.camera.DestinationType.FILE_URI,
mediaType: this.camera.MediaType.VIDEO,
}
this.camera.getPicture(options).then((data_uri) => {
this.readVideoFileasGeneral(data_uri);
});
});
}
readVideoFileasGeneral(data_uri) {
if(!data_uri.includes('file://')) {
data_uri = 'file://' + data_uri;
}
return this.file.resolveLocalFilesystemUrl(data_uri)
.then((entry: FileEntry) => {
//***it does not get in here***
this.presentQuickToastMessage(data_uri);
return new Promise((resolve)=>{//, reject) => {
entry.file((file) => {
let fileReader = new FileReader();
fileReader.onloadend = () => {
let blob = new Blob([fileReader.result], {type: file.type});
resolve({blob: blob, file: file});
};
fileReader.readAsArrayBuffer(file);
});
})
})
.catch((error) => {
this.presentQuickToastMessage(error);
//***it presents "plugin_not_installed" here***
});
}
I understand that I am having this message because Native File is not supported anymore (maybe reason of the plugin_not_installed message). However, I still have to do this task. So, if someone has any idea of what I could be using in order to have the selected videos in a blob, it would be great!
Thanks for reading until here,
Cheers,
Roger A L
makeFileIntoBlob(uri) {
// get the correct path for resolve device file system
let pathIndex = uri.indexOf('var');
let correctPath = uri.slice(+pathIndex);
this.file
.resolveLocalFilesystemUrl((this.platform.is('ios') ? 'file:///' : '') + correctPath)
.then(entry => (<FileEntry>entry).file(file => this.readFile(file)))
.catch(err => console.log('ERROR: ', err));
}
readFile(file) {
if(file) {
const reader = new FileReader();
reader.onloadend = () => {
const blob: any = new Blob([reader.result], { type: file.type });
blob.name = file.name;
console.log(blob);
return blob;
};
reader.readAsArrayBuffer(file);
}
}
You need to get rid of the /private/ and keep file:///, so that your path goes like file:///var/
I'm currently working on something similar.. I have the video recorded with media-capture and then I can display it within a normal video html tag.. if this is all you need then this code may help you...
this.mediaCapture.captureVideo({duration: 10, quality: 0}).then(
(data: MediaFile[]) => {
if (data.length > 0) {
let originname = data[0].fullPath.substr(data[0].fullPath.lastIndexOf('/') + 1);
let originpath = data[0].fullPath.substr(0, data[0].fullPath.lastIndexOf('/') + 1);
let alerta = this.alerts.create({
buttons: ['ok'],
message: this.file.externalDataDirectory
});
alerta.then(set => set.present());
this.file.copyFile(originpath, originname, this.file.externalDataDirectory, 'video.mp4')
.then(result =>{
let videopath = this.webview.convertFileSrc(result.nativeURL)
let video = (document.getElementById('myvideo') as HTMLVideoElement).src = videopath;
.... rest of the code
The problem raise when you try to use the native File plugin... converting files with any method (readAsDataURL, readAsArrayBuffer or readAsBinaryString) will never resolve, this is a known problem with the Ionic Native File plugin but is not taken care of...
What I did is to take the ionic native Filesystem and use it to read the file, this does read the file and get you with a base64 (pretty sure as I don't specify the encoding field) and then you can handle it the way you want...
const data = Filesystem.readFile({
path: result.nativeURL
})
.then(data =>{
...handle data as base64
...rest of the code

Store image to Firebase storage from cordova camera plugins on Ionic

I've red some topics on the subject (e.g: Uploading image to Firebase Storage from Cordova app) but didn't find my answer...
I'm working on a IONIC project with the implementation of the ngCordova camera plugin to take picture and get pic from the librairy.
So I got the result as a image URI and I want to upload it in Firebase storage (as file or Blob).
Here is my code :
$scope.fromCamera = function() {
$ionicPlatform.ready(function() {
var options = {
quality: 75,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 300,
targetHeight: 300,
saveToPhotoAlbum: true e
};
$cordovaCamera.getPicture(options).then(function(imageURI) {
window.resolveLocalFileSystemURL(imageURI, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function () {
// This blob object can be saved to firebase
var blob = new Blob([new Uint8Array(this.result)], { type: "image/jpeg" });
// Create the storage ref
var ref = storageRef.child('images/test');
// Upload the file
uploadPhoto(blob, ref);
};
reader.readAsArrayBuffer(file);
});
}, function (error) {
console.log(error)
});
});
});
};
I read the file and convert it into a Blob before uploading it into firebase. And I got an 'Encoding error' telling me "A URI supplied to the API was malformed, or the resulting Data URL has exceeded the URL length limitations for Data URLs."
I'm running it an chrome browser with the Cordova Mocks extension.
Any help is welcome!
Thanks
uploadPhoto() is my function to upload the file on firebase storage (and save the URL in firebase database)
var storageRef = Firebase.storageRef();
var databaseRef = Firebase.databaseRef();
var uploadPhoto = function(file, ref) {
var task = ref.put(file);
// Update progress bar
task.on('state_changed', function(snapshot){
// nothing
}, function(error) {
// Handle unsuccessful uploads
}, function() {
// Handle successful uploads on complete
$scope.downloadURL = task.snapshot.downloadURL;
$scope.actualKey = databaseRef.child('posts').push().key;
databaseRef.child('posts/' + $scope.actualKey).update({
url : $scope.downloadURL,
id : $scope.actualKey,
time : firebase.database.ServerValue.TIMESTAMP,
});
}
);
}
try changing...
[new Uint8Array(this.result)]
to just this
[this.result]
alternate approach using $cordovaFile
var fileName = imageURI.replace(/^.*[\\\/]/, '');
$cordovaFile.readAsArrayBuffer(cordova.file.tempDirectory, fileName)
.then(function (success) {
// success - get blob data
var imageBlob = new Blob([success], { type: "image/jpeg" });
// Create the storage ref
var ref = storageRef.child('images/test');
// Upload the file
uploadPhoto(imageBlob, ref);
}, function (error) {
// error
});
Instead of getting the path from the URI, in the code, I assume the following...
// modify the image path when on Android
if ($ionicPlatform.is("android")) {
path = cordova.file.cacheDirectory
} else {
path = cordova.file.tempDirectory
}
feel free to parse the path to get the directory

Chrome App FileReader

I'm trying to make use of the file system API in a Chrome App. I've tried all the sample code I can find and can't get a simple text file to read. I'm logging almost every step, and what seems to happen (or not happen) is everything stops the first time I reference a file reader object. It creates just fine, because I can log the .readyState, but after that I can't seem to even set an onload()event or execute a .readAsText().
Here's what I'm calling from a button:
function clickButton(){
chrome.fileSystem.chooseEntry({type: 'openFile', acceptsMultiple: false}, function(FileEntry){
if(chrome.runtime.lastError) {console.warn("Warning: " + chrome.runtime.lastError.message);}
else{
console.log(FileEntry);
var thing = new FileReader();
console.log(thing.readyState);
thing.onloadstart(function(){
console.log("Started loading " & FileEntry);
});
console.log("added onloadstart");
console.log(thing.readyState);
console.log(thing);
thing.readAsText(FileEntry);
console.log(thing.readyState);
console.log(thing.result);
}
});
document.getElementById("status").innerHTML = "I did something";
}
I did read somewhere that Chrome doesn't allow access to local files, but the chrome apps seem to be different. At least, the documentation seems to suggest that.
The only thing I end up with in my console is the FileEntry object.
https://developer.chrome.com/apps/app_storage#filesystem
I've used the example code right from the above link and still can't get it right. Anyone else have this issue or know what I'm doing wrong?
There is a difference between a FileEntry and a File. You need to call FileEntry's .file() method. So, replace
thing.readAsText(FileEntry);
with
FileEntry.file(function(File) {
thing.readAsText(File)
})
https://developer.mozilla.org/en-US/docs/Web/API/FileEntry#File
Try this code...
<!doctype html>
<html>
<script>
function handle_files(files) {
for (i = 0; i < files.length; i++) {
file = files[i]
console.log(file)
var reader = new FileReader()
ret = []
reader.onload = function(e) {
console.log(e.target.result)
}
reader.onerror = function(stuff) {
console.log("error", stuff)
console.log (stuff.getMessage())
}
reader.readAsText(file) //readAsdataURL
}
}
</script>
<body>
FileReader that works!
<input type="file" multiple onchange="handle_files(this.files)">
</body>
</html>
I've written a function to extract text from a file.
function getFileEntryText(fileEntry) {
return new Promise(function (resolve, reject) {
fileEntry.file(function (file) {
var fileReader = new FileReader();
fileReader.onload = function (text) {
resolve(fileReader.result);
};
fileReader.onerror = function () {
reject(fileReader.error);
};
fileReader.readAsText(file);
});
});
}
You can invoke this method like so:
getFileEntryText(fileEntry).then(function(text) {
// Process the file text here
}, function(error) {
// Handle the file error here
});
One thing I'm grappling with when working with the FileSystem is that every call is asynchronous. Having multiple levels of nested callbacks can make for code that's hard to read. I'm currently working around this by converting everything I can to a Promise.
for anyone who is interested, here's my final (working) code, complete with all the console.log()'s I needed to follow all those callbacks.
var chosenEntry = null;
function clickButton(){
console.log("Button clicked");
var accepts = [{
mimeTypes: ['text/*'],
extensions: ['js', 'css', 'txt', 'html', 'xml', 'tsv', 'csv', 'rtf']
}];
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(theEntry) {
if (!theEntry) {
output.textContent = 'No file selected.';
return;
}
// use local storage to retain access to this file
chrome.storage.local.set({'chosenFile': chrome.fileSystem.retainEntry(theEntry)});
console.log("local data set. calling loadFileEntry");
loadFileEntry(theEntry);
console.log("loadFileEntry called, returned to clickButton()");
});
}
function loadFileEntry(_chosenEntry) {
console.log("entered loadFileEntry()");
chosenEntry = _chosenEntry;
chosenEntry.file(function(file) {
readAsText(chosenEntry, function(result) {
console.log("running callback in readAsText");
document.getElementById('text').innerHTML = result;
console.log("I just tried to update textarea.innerHTML");
});
});
console.log("added function to chosenEntry.file()");
}
function readAsText(fileEntry, callback) {
console.log("readAsText called");
fileEntry.file(function(file) {
var reader = new FileReader();
console.log("Created reader as FileReader");
reader.onload = function(e) {
console.log("called reader.onload function");
callback(e.target.result);
};
console.log("calling reader.readAsText");
reader.readAsText(file);
});
}

How to show a default preview icon in case if it's not possible to create a thumbnail?

I am setting up Jquery-File-Upload for my website. The script is you can see here:
http://blueimp.github.io/jQuery-File-Upload/‎
This script automatically creates preview thumbnails of image files, however, it allows to select any files (doc, pdf etc). If user selects such a file, the script shows error "File type not allowed" but doesn't show any thumbnail. I want to set up a default thumbnail image for all non-image files.
I modified jquery.fileupload-image.js file:
Original:
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
}
return data;
}
My modification:
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
} else {
data.files[data.index][options.name||'preview']='<img src="/images/default-thumbnail.png">';
}
return data;
}
It works perfectly but the problem is that I will use this script in different sections of my website and thumbnail size always will be different.
So, I need to define default thumbnail in my html file. I tried:
var defaultthumbnail = '<img src="/images/default-thumbnail.png">';
or in options:
defaultthumbnail: '<img src="/images/default-thumbnail.png">'
but it doesn't work. The script doesn't return image and doesn't show any error.
Any ideas?
<script>
$(function () {
var formData = $('#fileupload').serializeArray();
var defaultthumbnail = '<img src="/images/default-thumbnail.png">';
'use strict';
$('#fileupload').fileupload({
url:'//mydomain.com'
});
$('#fileupload').fileupload('option', {
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
autoUpload:false,
maxNumberOfFiles:10,
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent)
});
if ($.support.cors) {
$.ajax({
url: $('#fileupload').fileupload('option', 'url'),
type: 'HEAD'
}).fail(function () {
$('<div class="alert alert-danger"/>')
.text('Upload server currently unavailable - ' +
new Date())
.appendTo('#fileupload');
});
}
});
</script>
Looks that Jquery-File-Upload project is abandoned...
So if you want to show a default thumbnail for unsupported file types, do the following:
<script>
var defaultthumbnail = '<img src="/images/default-thumbnail.png" />';
$(function () {
var formData = $('#fileupload').serializeArray();
'use strict';
..............
..............
</script>
in jquery.fileupload-image.js file
change
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
}
return data;
}
to
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
} else {
data.files[data.index][options.name||'preview']=defaultthumbnail;
}
return data;
}