Use Mapbox with offline maps in Electron app - electron

Is it possible to have an electron app showing offline map?
I downloaded the mbtiles and stored in the electron app, but I'm not able to show it in the angular side of the electron app.
I have the following code:
<mgl-map
class="map"
id = "map"
[style]="'mbtiles://assets/resources/downloaded.mbtiles'"
[center]="[mapCenter.longitude, mapCenter.latitude]"
(load) = "onLoad($event)"
(dragEnd)="mapDrag()"
[doubleClickZoom]="false"
[bearing]="[bearing]"
[zoom]="[zoom]"
[pitch]="[pitch]">
</mgl-map>
But I get the error
zone-evergreen.js:1068 Fetch API cannot load mbtiles://User/hello/path/to/file.mbtiles. URL scheme "mbtiles" is not supported.
So, in order to make it works in an online way I have to change the style for
[style]="'mapbox://styles/mapbox/streets-v9'"
Is it possible to make it works serving the mbtiles from the nodejs code or in other way?

To serve up your local mbtiles file, you need to register the mbtiles protocol in main.js. Something like this should do it:
const electron = require('electron');
const protocol = electron.protocol;
const path = require('path');
protocol.registerHttpProtocol('mbtiles', (req, cb) => {
const url = 'assets/resources/downloaded.mbtiles';
cb({ path: path.normalize(`${__dirname}/${url}`) })
});
You can read up on protocol handlers in electron here: https://www.electronjs.org/docs/api/protocol#protocol

Related

Images/Videos CDN URL - Detect file type/extension

I'm trying to implement Story Mention rendering according to IG messenger graph API.
IG webhooks sends the payload URL of the media as CDN URLs that are extensionless,
which means I can't detect the file type(could be any kind of image or a video file).
The purpose is to render the URL to an HTML element and to prevent saving some file extensions.
Did anybody find out how to get this information?
An example for IG CDN URL
https://lookaside.fbsbx.com/ig_messaging_cdn/?asset_id=17952754300482708&signature=AbxVoHUcW3qKGZvE0FwrbpSEKBqkYGH9wFDUY9xnywlxxek8lWtrTwE173Sxhta9jbp0bgDiL17IpyiI82vqHGNPUD1wdMUZphwQOggW-_877cCI1BxaY_aDUZ8hj5OwmHK9E8OnSybqtMVmGXCX_hBF399t1Hb44zspeL3d9NWb9rib
Python:
import requests
res = requests.head(url)
print res.headers
I was able to retrieve the content type by making a request with node-fetch.
const fetch = require('node-fetch');
const response = await fetch(mediaUrl, { method: 'HEAD' });
const contentType = response.headers.get('Content-Type');

Download file with Playwright

How to download a file with Playwright?
I'm aware of this question
How to catch a download with playwright?
but that example code does not work. Using the latest released Playwright, there is no 'pageTarget' function on the browser instance:
const client = await browser.pageTarget(page).createCDPSession();
All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded files are deleted when the browser closes.
Download event is emitted once the download starts. Download path becomes available once download completes:
const [ download ] = await Promise.all([
page.waitForEvent('download'), // wait for download to start
page.click('a')
]);
// wait for download to complete
const path = await download.path();
...
https://github.com/microsoft/playwright/blob/master/docs/api.md#class-download
Playwright is going to support downloads in a cross-browser compatible way soon, you can track this feature request.
For now the above Chromium-specific snippet could be fixed by changing the line to:
const client = await context.newCDPSession(page);
which uses the new method for creating CDP sessions.

Passing arguments to a running electron app

I have found some search results about using app.makeSingleInstance and using CLI arguments, but it seems that the command has been removed.
Is there any other way to send a string to an already started electron app?
One strategy is to have your external program write to a file that your electron app knows about. Then, your electron app can listen for changes to that file and can read it to get the string:
import fs
fs.watch("shared/path.txt", { persistent: false }, (eventType: string, fileName: string) => {
if (eventType === "change") {
const myString: string = fs.readFileSync(fileName, { encoding: "utf8" });
}
});
I used the synchronous readFileSync for simplicity, but you might want to consider the async version.
Second, you'll need to consider the case where this external app is writing so quickly that maybe the fs.watch callback is triggered only once for two writes. Could you miss a change?
Otherwise, I don't believe there's an Electron-native way of getting this information from an external app. If you were able to start the external app from your Electron app, then you could just do cp.spawn(...) and use its stdout pipe to listen for messages.
If shared memory were a thing in Node, then you could use that, but unfortunately it's not.
Ultimately, the most elegant solution to my particular problem was to add a http api endpoint for the Electron app using koa.
const Koa = require("koa");
const koa = new Koa();
let mainWindow;
function createWindow() {
let startServer = function() {
koa.use(async ctx => {
mainWindow.show();
console.log("text received", ctx.request.query.text);
ctx.body = ctx.request.query.text;
});
koa.listen(3456);
};
}
Now I can easily send texts to Electron from outside the app using the following url:
localhost:3456?text=myText

Reading File on Google Drive using Dart

I created a configuration file (Simple Text File) on my Google Drive and now I would like to read it from my Chrome Packaged Dart Application. But I'm not able to get more information of the file than it's name, size etc.
For accessing Google Drive I use the google_drive_v2_api.
Any suggestion on how to get the contents of my configuration file would be great! Thanks!
I just did some test in my own chrome app, uploading and downloading a simple file:
chrome.identity.getAuthToken(new chrome.TokenDetails(interactive: true ))
.then((token){
OAuth2 auth = new SimpleOAuth2(token);
var drive = new gdrive.Drive(auth)..makeAuthRequests=true;
drive.files.insert({},content:window.btoa('hello drive!')).then((sentMeta){
print("File sent! Now retrieving...");
drive.files.get(sentMeta.id).then((repliedMeta){
HttpRequest request = new HttpRequest()..open('GET', repliedMeta.downloadUrl)
..onLoad.listen((r)=>print('here is the result:'+r.target.responseText));
auth.authenticate(request).then((oAuthReq)=>oAuthReq.send());
});
});
});
It works, but the HttpRequest to get content back seems heavy...
But i really recommend you to a take look to chrome.storage.sync if your config file size is < to 4ko... If not, you could also use the chrome SyncFileSystem API... They are both easier to use, and SyncFileSystem use Drive as backend.
This page on downloading files talks through the process for getting the contents of a file.

Strange looping audio in mobile browsers for NodeJS application

To illustrate the problem I'm having I created a sample set of code in the Express framework for NodeJS. When a user goes to http://example.com/ there's supposed to be an audio element ready to play the contents of music.mp3. The problem I've noticed on mobile browsers, specifically iOS Chrome and Safari, is that if "music.mp3" is long enough, the entirety of the file won't play, it'll just loop back to the beginning after a while. Any tips/explanations that could explain this behavior to me?
var fs = require("fs");
var express = require("express");
var app = express();
app.get("/music.mp3", function (req, res) {
var music = fs.createReadStream("./music.mp3");
music.pipe(res);
});
app.get("/", function (req, res) {
res.send("<audio controls><source src=\"music.mp3\">Your browser sucks</audio>");
});
app.listen(8080);

Resources