mirror of https://github.com/jiahaog/Nativefier
Cleanup options.js, rename `--app-name` to `--name`
This commit is contained in:
parent
0d408b001d
commit
51acbaaa9c
13
README.md
13
README.md
|
@ -1,6 +1,7 @@
|
|||
# Nativefier
|
||||
[![Build Status](https://travis-ci.org/jiahaog/nativefier.svg?branch=master)](https://travis-ci.org/jiahaog/nativefier)
|
||||
[![npm version](https://badge.fury.io/js/nativefier.svg)](https://www.npmjs.com/package/nativefier)
|
||||
|
||||
![Dock Screenshot](https://raw.githubusercontent.com/jiahaog/nativefier/master/screenshots/Dock%20Screenshot.png)
|
||||
|
||||
You want to make a native wrapper for Google Maps (or any web page).
|
||||
|
@ -19,6 +20,10 @@ I did this because I was tired of having to `⌘-tab` or `alt-tab` to my browser
|
|||
|
||||
View the changelog [here](https://github.com/jiahaog/nativefier/blob/master/History.md).
|
||||
|
||||
### Features
|
||||
|
||||
- Automatically retrieves the correct icon and app name
|
||||
|
||||
## Installation
|
||||
|
||||
With [Node.js](https://nodejs.org/) installed,
|
||||
|
@ -54,10 +59,10 @@ Creating a native desktop app for [medium.com](http://medium.com):
|
|||
$ nativefier "http://medium.com"
|
||||
```
|
||||
|
||||
Nativefier will intelligently attempt to determine the app name, your OS and processor architecture, among other options. If desired, the app name or other options can be overwritten by specifying the `--app-name "Medium"` as part of the command line options, as such.
|
||||
Nativefier will intelligently attempt to determine the app name, your OS and processor architecture, among other options. If desired, the app name or other options can be overwritten by specifying the `--name "Medium"` as part of the command line options, as such.
|
||||
|
||||
```
|
||||
$ nativefier --app-name "Some Awesome App" "http://medium.com"
|
||||
$ nativefier --name "Some Awesome App" "http://medium.com"
|
||||
```
|
||||
|
||||
**For Windows Users:** Take note that the application menu is automatically hidden by default, you can press `alt` on your keyboard to access it.
|
||||
|
@ -85,10 +90,10 @@ Specifies the destination directory to build the app to, defaults to the current
|
|||
|
||||
Prints the usage information.
|
||||
|
||||
#### [app-name]
|
||||
#### [name]
|
||||
|
||||
```
|
||||
-n, --app-name <value>
|
||||
-n, --name <value>
|
||||
```
|
||||
|
||||
The name of the application, which will affect strings in titles and the icon.
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"clean": "gulp clean",
|
||||
"build": "gulp build",
|
||||
"watch": "while true ; do gulp watch ; done",
|
||||
"package-placeholder": "npm run build && node lib/cli.js http://www.bennish.net/web-notifications.html ~/Desktop --overwrite --app-name notification-test --icon ./test-resources/iconSampleGrey.png && open ~/Desktop/notification-test-darwin-x64/notification-test.app",
|
||||
"package-placeholder": "npm run build && node lib/cli.js http://www.bennish.net/web-notifications.html ~/Desktop --overwrite --name notification-test --icon ./test-resources/iconSampleGrey.png && open ~/Desktop/notification-test-darwin-x64/notification-test.app",
|
||||
"start-placeholder": "npm run build && electron app",
|
||||
"release": "gulp release"
|
||||
},
|
||||
|
|
|
@ -36,24 +36,7 @@ function buildApp(options, callback) {
|
|||
|
||||
async.waterfall([
|
||||
callback => {
|
||||
optionsFactory(
|
||||
options.appName,
|
||||
options.targetUrl,
|
||||
options.platform,
|
||||
options.arch,
|
||||
options.electronVersion,
|
||||
options.outDir,
|
||||
options.overwrite,
|
||||
options.conceal,
|
||||
options.icon,
|
||||
options.counter,
|
||||
options.width,
|
||||
options.height,
|
||||
options.showMenuBar,
|
||||
options.userAgent,
|
||||
options.honest,
|
||||
options.insecure,
|
||||
callback);
|
||||
optionsFactory(options, callback);
|
||||
},
|
||||
(options, callback) => {
|
||||
copyPlaceholderApp(options.dir, tmpPath, options.name, options.targetUrl, options.counter, options.width, options.height, options.showMenuBar, options.userAgent, options.insecure, (error, tempDirPath) => {
|
||||
|
@ -70,7 +53,6 @@ function buildApp(options, callback) {
|
|||
|
||||
// maybe skip passing icon parameter to electron packager
|
||||
const packageOptions = maybeNoIconOption(options);
|
||||
|
||||
packager(packageOptions, (error, appPathArray) => {
|
||||
// pass options which still contains the icon to waterfall
|
||||
callback(error, options, appPathArray);
|
||||
|
|
|
@ -13,9 +13,9 @@ if (require.main === module) {
|
|||
.arguments('<targetUrl> [dest]')
|
||||
.action(function(targetUrl, appDir) {
|
||||
program.targetUrl = targetUrl;
|
||||
program.outDir = appDir;
|
||||
program.out = appDir;
|
||||
})
|
||||
.option('-n, --app-name <value>', 'app name')
|
||||
.option('-n, --name <value>', 'app name')
|
||||
.option('-p, --platform <value>', '\'linux\', \'win32\', or \'darwin\'')
|
||||
.option('-a, --arch <value>', '\'ia32\' or \'x64\'')
|
||||
.option('-e, --electron-version <value>', 'electron version to package, without the \'v\', see https://github.com/atom/electron/releases')
|
||||
|
|
|
@ -7,6 +7,7 @@ function isOSX() {
|
|||
function isWindows() {
|
||||
return os.platform() === 'windows';
|
||||
}
|
||||
|
||||
export default {
|
||||
isOSX: isOSX,
|
||||
isWindows: isWindows
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import os from 'os';
|
||||
|
||||
function inferPlatform() {
|
||||
const platform = os.platform();
|
||||
if (platform === 'darwin' || platform === 'win32' || platform === 'linux') {
|
||||
return platform;
|
||||
}
|
||||
|
||||
console.warn(`Warning: Untested platform ${platform} detected, assuming linux`);
|
||||
return 'linux';
|
||||
}
|
||||
|
||||
function inferArch() {
|
||||
const arch = os.arch();
|
||||
if (arch !== 'ia32' && arch !== 'x64') {
|
||||
throw `Incompatible architecture ${arch} detected`;
|
||||
}
|
||||
return arch;
|
||||
}
|
||||
|
||||
export default {
|
||||
inferPlatform: inferPlatform,
|
||||
inferArch: inferArch
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
import request from 'request';
|
||||
import cheerio from 'cheerio';
|
||||
|
||||
function inferTitle(url, callback) {
|
||||
const options = {
|
||||
url: url,
|
||||
headers: {
|
||||
// fake a user agent because pages like http://messenger.com will throw 404 error
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36'
|
||||
}
|
||||
};
|
||||
|
||||
request(options, (error, response, body) => {
|
||||
if (error || response.statusCode !== 200) {
|
||||
callback(`Request Error: ${error}, Status Code ${response ? response.statusCode : 'No Response'}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const $ = cheerio.load(body);
|
||||
const pageTitle = $('title').text().replace(/\//g, '');
|
||||
callback(null, pageTitle);
|
||||
});
|
||||
}
|
||||
|
||||
export default inferTitle;
|
154
src/options.js
154
src/options.js
|
@ -1,80 +1,61 @@
|
|||
import os from 'os';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
import request from 'request';
|
||||
import cheerio from 'cheerio';
|
||||
import validator from 'validator';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import sanitizeFilename from 'sanitize-filename';
|
||||
import _ from 'lodash';
|
||||
import async from 'async';
|
||||
import inferIcon from './inferIcon';
|
||||
|
||||
import inferIcon from './infer/inferIcon';
|
||||
import inferTitle from './infer/inferTitle';
|
||||
import inferOs from './infer/inferOs';
|
||||
|
||||
const {inferPlatform, inferArch} = inferOs;
|
||||
|
||||
const TEMPLATE_APP_DIR = path.join(__dirname, '../', 'app');
|
||||
const ELECTRON_VERSION = '0.36.4';
|
||||
const DEFAULT_APP_NAME = 'APP';
|
||||
|
||||
function optionsFactory(name,
|
||||
targetUrl,
|
||||
platform = detectPlatform(),
|
||||
arch = detectArch(),
|
||||
version = ELECTRON_VERSION,
|
||||
outDir = process.cwd(),
|
||||
overwrite = false,
|
||||
conceal = false,
|
||||
icon,
|
||||
counter = false,
|
||||
width = 1280,
|
||||
height = 800,
|
||||
showMenuBar = false,
|
||||
userAgent,
|
||||
honest = false,
|
||||
insecure = false,
|
||||
callback) {
|
||||
targetUrl = normalizeUrl(targetUrl);
|
||||
/**
|
||||
* @callback optionsCallback
|
||||
* @param error
|
||||
* @param options augmented options
|
||||
*/
|
||||
|
||||
if (!width) {
|
||||
width = 1280;
|
||||
}
|
||||
|
||||
if (!height) {
|
||||
height = 800;
|
||||
}
|
||||
|
||||
if (!userAgent && !honest) {
|
||||
userAgent = getFakeUserAgent();
|
||||
}
|
||||
/**
|
||||
* Extracts only desired keys from inpOptions and augments it with defaults
|
||||
* @param inpOptions
|
||||
* @param {optionsCallback} callback
|
||||
*/
|
||||
function optionsFactory(inpOptions, callback) {
|
||||
|
||||
const options = {
|
||||
dir: TEMPLATE_APP_DIR,
|
||||
|
||||
name: name,
|
||||
targetUrl: targetUrl,
|
||||
|
||||
platform: platform,
|
||||
arch: arch,
|
||||
version: version,
|
||||
|
||||
out: outDir,
|
||||
|
||||
// optionals
|
||||
overwrite: overwrite,
|
||||
asar: conceal,
|
||||
icon: icon,
|
||||
|
||||
// app configuration
|
||||
counter: counter,
|
||||
width: width,
|
||||
height: height,
|
||||
showMenuBar: showMenuBar,
|
||||
userAgent: userAgent,
|
||||
insecure: insecure
|
||||
name: inpOptions.name,
|
||||
targetUrl: normalizeUrl(inpOptions.targetUrl),
|
||||
platform: inpOptions.platform || inferPlatform(),
|
||||
arch: inpOptions.arch || inferArch(),
|
||||
version: ELECTRON_VERSION,
|
||||
out: inpOptions.out|| process.cwd(),
|
||||
overwrite: inpOptions.overwrite || false,
|
||||
asar: inpOptions.conceal || false,
|
||||
icon: inpOptions.icon,
|
||||
counter: inpOptions.counter || false,
|
||||
width: inpOptions.width || 1280,
|
||||
height: inpOptions.height || 800,
|
||||
showMenuBar: inpOptions.showMenuBar || false,
|
||||
userAgent: inpOptions.userAgent || getFakeUserAgent(),
|
||||
insecure: inpOptions.insecure || false
|
||||
};
|
||||
|
||||
if (inpOptions.honest) {
|
||||
options.userAgent = null;
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
callback => {
|
||||
if (options.icon) {
|
||||
callback(null, options);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
inferIcon(options.targetUrl, (error, pngPath) => {
|
||||
|
@ -83,80 +64,41 @@ function optionsFactory(name,
|
|||
} else {
|
||||
options.icon = pngPath;
|
||||
}
|
||||
callback(null, options);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
(options, callback) => {
|
||||
if (name && name.length > 0) {
|
||||
options.name = name;
|
||||
callback(null, options);
|
||||
callback => {
|
||||
if (options.name && options.name.length > 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
getTitle(options.targetUrl, function(error, pageTitle) {
|
||||
inferTitle(options.targetUrl, function(error, pageTitle) {
|
||||
if (error) {
|
||||
console.warn(`Unable to automatically determine app name, falling back to '${DEFAULT_APP_NAME}'`);
|
||||
options.name = DEFAULT_APP_NAME;
|
||||
} else {
|
||||
options.name = pageTitle;
|
||||
}
|
||||
|
||||
callback(null, options);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], (error, options) => {
|
||||
], error => {
|
||||
callback(error, sanitizeOptions(options));
|
||||
console.log(options);
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeOptions(options) {
|
||||
options.name = sanitize(options.name);
|
||||
options.name = sanitizeFilename(options.name);
|
||||
|
||||
if (options.platform === 'linux') {
|
||||
// spaces will cause problems with Ubuntu when pinned to the dock
|
||||
options.name = _.kebabCase(options.name);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function detectPlatform() {
|
||||
const platform = os.platform();
|
||||
if (platform === 'darwin' || platform === 'win32' || platform === 'linux') {
|
||||
return platform;
|
||||
}
|
||||
|
||||
console.warn(`Warning: Untested platform ${platform} detected, assuming linux`);
|
||||
return 'linux';
|
||||
}
|
||||
|
||||
function detectArch() {
|
||||
const arch = os.arch();
|
||||
if (arch !== 'ia32' && arch !== 'x64') {
|
||||
throw `Incompatible architecture ${arch} detected`;
|
||||
}
|
||||
return os.arch();
|
||||
}
|
||||
|
||||
function getTitle(url, callback) {
|
||||
const options = {
|
||||
url: url,
|
||||
headers: {
|
||||
// fake a user agent because pages like http://messenger.com will throw 404 error
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36'
|
||||
}
|
||||
};
|
||||
|
||||
request(options, (error, response, body) => {
|
||||
if (error || response.statusCode !== 200) {
|
||||
callback(`Request Error: ${error}, Status Code ${response ? response.statusCode : 'No Response'}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const $ = cheerio.load(body);
|
||||
const pageTitle = $('title').text().replace(/\//g, '');
|
||||
callback(null, pageTitle);
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeUrl(testUrl) {
|
||||
// add protocol if protocol not found
|
||||
let normalized = testUrl;
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('Nativefier Module', function() {
|
|||
|
||||
const tmpPath = tmpObj.name;
|
||||
const options = {
|
||||
appName: 'google-test-app',
|
||||
name: 'google-test-app',
|
||||
targetUrl: 'http://google.com',
|
||||
outDir: tmpPath,
|
||||
overwrite: true,
|
||||
|
|
Loading…
Reference in New Issue