Electron: how to serve files from appdata - javascript

I feel like this is such a basic question but I have been at it for hours and seem to be spinning around the answer. I have an electron app which I also used create-react-app on. I have image files in the appData folder for the electron app and I want to be able to display them in the renderer (using react) using an img tag.
I cannot seem to figure out how to do this. Using an absolute path and file:// for the img src doesn't work. I also tried to register a custom protocol but can't seem to get it to work, I just keep getting file not found (see below). Any ideas or links would be appreciated.
protocol.registerFileProtocol('poster', (request, callback) => {
const url = request.url.substr(9)
console.log(url);
callback({path: app.getPath('appData')+'/posters/'+url})
}, (error) => {
if (error) console.error('Failed to register protocol')
})
The image tag would look something like this:
<img src='poster://test.jpg'/>

What I eventually ended up doing was correcting my original code to use userData instead of appData. I didn't end up solving the part where it was converting to lower case so I just made all of my file names in lower case.
To find the path on your machine where you should put the files you can look at the result of a call to:
app.getPath('userData')
Here is the relevant code in my public/electron.js file:
protocol.registerFileProtocol('poster', (request, callback) => {
const url = request.url.substr(9,request.url.length -10)
callback({path: app.getPath('userData')+'/posters/'+url})
}, (error) => {
if (error) console.error('Failed to register protocol')
})
}
protocol.registerStandardSchemes(['poster'])
In my react code it is just a matter now of prefixing the filename in my image tag with 'poster://' so an image tag looks like:
<img src='poster://poster1.jpg/>

Related

NiodeJS/ How to find size of an externally hosted image without downloading it?

I need to find the sizes/metadata of externally hosted images in a document (e.g., markdown documents that have image tags in it), but need to do it without actually downloading the image.
Is there any way to do this easily on NodeJS/ExpressJs using javascript? Some of the solutions are many years old and not sure if there are better methods now.
You can do what was suggested in comments by only grabbing the HEAD instead of using a GET when you call the image.
Using got or whatever you like (http, axios, etc) you set the method to HEAD and look for content-length.
My example program that grabs a twitter favicon, headers only, looks like this:
const got = require('got');
(async () => {
try {
const response = await got('https://abs.twimg.com/favicons/twitter.ico', { method: 'HEAD' });
console.log(response.headers);
} catch (error) {
console.log('something is broken. that would be a new and different question.');
}
})();
and in the response I see the line I need:
'content-length': '912'
If the server doesn't respect HEAD or doesn't return a content-length header, you are probably out of luck.

How to fix 'Unexpected token < in JSON at position 0'?

I'm trying to share a website I've done using GitHub pages, but I'm having troubles loading the JSON files.
This is for a friends game server website, using HTML 5, JavaScript and JSON, I've tried running it from localhost and it worked perferctly fine.
The issue actually is a SyntaxError : Unexpected token < in JSON at position 0 and when I try to look for the JSON file in chrome debugger I can't see my JSON files to check where the probleme could be coming from.
The JSON file :
{
"header_menu_games": "Games",
"header_menu_home": "Home",
"header_menu_rules": "Rules",
"header_menu_support": "Support",
"header_serverip_text": "Server ip:",
"header_serverip_copy_btn": "Copy"
}
The JavaScript code I use to translate :
if (isLanguageAvailable) {
var myRequest = new Request(`../../src/lang/${userLang}.json`);
console.info(`User language (${userLang}) is available`);
} else {
var myRequest = new Request("../../src/lang/en.json");
console.info(`The user language (${userLang}) is unfortunately not available`);
}
console.log(myRequest);
fetch(myRequest)
.then(resp => {
resp.json()
.then(data => {
document.getElementById("lang-header_serverip_text").innerHTML = data.header_serverip_text;
})
.catch(err => {
console.error(err);
});
})
.catch(err => {
console.error(err);
});
Console error:
JavaSript catch error:
The full code is available on GitHub.
I believe you're receiving a 404 error because you're pointing your link at the repository location instead of the actual content. You were linking to a nonexistent link: https://vianpyro.github.io/src/lang/en.json
You can do this one of two ways:
Link to the raw version of the file from the repository
Point at the correct location from your friend's domain
1. Linking to the Raw Version
In github, click on Raw and it should open a page containing the actual JSON.
You'll see that the actual link to the content is: https://raw.githubusercontent.com/Vianpyro/Aycraft/master/src/lang/en.json
2. Linking to the hosted location
Part of your original problem was that you weren't pointing at the right path. Your friend's site is hosted at https://vianpyro.github.io/Aycraft and not https://vianpyro.github.io/.
This means that the base url of the site is https://vianpyro.github.io/Aycraft and everything in the path has to follow that. You have to include the /Aycraft after the domain name since that is the baseurl of the site.
The correct url would be:
https://vianpyro.github.io/Aycraft/src/lang/en.json

Share image plus text via Whatsapp with React Native

I am working on a react native app and one of my needs is to be able to share via Whatsapp, a png image (created from a svg) plus some text in the message. I have achieved this on Android using react-native-share but when I try it on iOS, the message is populated with the provided text but the image is ignored. I have also tried with Share from react-native but the result is the same.
I have tried this sharing directly a base64 image (data:image/png;base64,image_data) as well as saving the created image and add the path as the url but the result is always the same.
The only way to make this work on iOS (with both react-native-share and Share) is to omit the message, but the text is needed in the requirement.
Is there a way to achieve this?
Versions:
React Native - 0.55.0
react-native-share - 1.1.2
As a side note, the sharing process on Twitter, Email, SMS and some other apps is working correctly.
Code sample:
const base64Data = this.state.uri
const dir = `${RNFS.DocumentDirectoryPath}/tmp_${moment().valueOf()}.png`
RNFS.writeFile(dir, base64Data, 'base64').then(async () => {
const options = {
url: Platform.OS === 'android' ? `file://${dir}` : dir,
message: '' // By omitting the message, whatsapp shows the image
}
try {
await Share.open(options)
// Delete file when share action is completed
await RNFS.unlink(dir)
} catch (error) {
console.log('error', error)
}
}).catch((err) => {
console.log(err.message)
})

webshot does not render local images inside html

I'm using node-webshot and phantomjs-cli to render an html string to a png image.
The html contains an image tag. The image is not rendered when it is the src attribute points to a local file and no error is raised. However it does render the image when the src points to a http location. I've tried all of the different file path combinations that I can think of, eg
<img src=images/mushrooms.png"/>
<img src=images//mushrooms.png"/>
<img src=c:\images\mushrooms.png"/>
<img src=c:\\images\\mushrooms.png"/>
<img src=file://c:\\images\\mushrooms.png"/>
<img src=file://images//mushrooms.png"/>
etc..
but so far no luck. Interestingly it works fine on my colleague's machine which is a Mac but not on mine which is Windows, and I've tried with two different Windows machines with no success.
Here is some simplified code that focuses on the issue:
'use strict'
const webshot = require('webshot');
console.log('generating');
webshot('<html><head></head><body><img src="c:\\images\\mushrooms.png"/></body></html>', 'output.png', {siteType: 'html'}, function(err) {
console.log(err);
});
/*
webshot('<html><head></head><body><img src="https://s10.postimg.org/pr6zy8249/mushrooms.png"/></body></html>', 'output.png', {siteType: 'html'}, function(err) {
console.log(err);
});
*/
The commented out code block is an example of it working with a web link as the image source but I need it to work off of a local path.
Has anyone had this issue before an know how to solve it?
Thanks
Local files should be accessible via the file: URI Scheme:
<img src="file:///C:/images/mushrooms.png">
Per the specification:
A file URL takes the form:
file://<host>/<path>
I think that you need to set static folders.
Use something like this in your code app.use(express.static(path.join(__dirname, 'public')));
Learn more about it here.
Can be because you never open the quotes.
try:
<img src="images/mushrooms.png"/>
Likely a phantomjs problem, I've run into bugs before and they barely maintain the project to this date. You should consider switching to Headless Chrome, which is new and officially maintained by the Chromium team.
Edit: here's an example
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent('<html><head></head><body><img src="c:\\images\\mushrooms.png"/></body></html>');
await page.screenshot({path: 'output.png'});
await browser.close();
})();
Edit 2: here's the link the node package

Stream file uploaded with Express.js through gm to eliminate double write

I'm using Express.js and have a route to upload images that I then need to resize. Currently I just let Express write the file to disk (which I think uses node-formidable under the covers) and then resize using gm (http://aheckmann.github.com/gm/) which writes a second version to disk.
gm(path)
.resize(540,404)
.write(dest, function (err) { ... });
I've read that you can get a hold of the node-formidable file stream before it writes it to disk, and since gm can accept a stream instead of just a path, I should be able to pass this right through eliminating the double write to disk.
I think I need to override form.onPart but I'm not sure where (should it be done as Express middleware?) and I'm not sure how to get a hold of form or what exactly to do with the part. This is the code skeleton that I've seen in a few places:
form.onPart = function(part) {
if (!part.filename) { form.handlePart(part); return; }
part.on('data', function(buffer) {
});
part.on('end', function() {
}
}
Can somebody help me put these two pieces together? Thanks!
You're on the right track by rewriting form.onPart. Formidable writes to disk by default, so you want to act before it does.
Parts themselves are Streams, so you can pipe them to whatever you want, including gm. I haven't tested it, but this makes sense based on the documentation:
var form = new formidable.IncomingForm;
form.onPart = function (part) {
if (!part.filename) return this.handlePart(part);
gm(part).resize(200, 200).stream(function (err, stdout, stderr) {
stdout.pipe(fs.createWriteStream('my/new/path/to/img.png'));
});
};
As for the middleware, I'd copypaste the multipart middleware from Connect/Express and add the onPart function to it: http://www.senchalabs.org/connect/multipart.html
It'd be a lot nicer if formidable didn't write to disk by default or if it took a flag, wouldn't it? You could send them an issue.

Categories

Resources