├── .gitignore
├── README.md
├── api.js
├── fileIo.js
├── modules
├── commands.js
├── error.js
├── execute.js
├── group.js
├── help.js
├── list.js
└── print.js
├── package.json
├── scripts
└── preuninstall.js
└── web
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | store.json
3 | local.txt
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Web Launcher
4 |
5 | A CLI for quickly launching the websites you use.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | **Requires Node version 6 or higher. Tested on Mac.**
14 |
15 |
16 |
17 | Open and manage your web environments from the command line. Like using a bunch of aliases/Bash scripts or installing a chrome extension that supports link sets, but in a command line interface.
18 |
19 | ## Installation
20 |
21 | ```shell
22 |
23 | npm install -g web-launcher
24 |
25 | ```
26 |
27 | ## Usage
28 |
29 | Run the help command at any level to get instructions.
30 |
31 | ```shell
32 |
33 | web help
34 |
35 | ```
36 |
37 | would output
38 |
39 | ```
40 | list [ls] List all groups.
41 |
42 |
43 | groups Add or remove a group.
44 |
45 |
46 | run [open] {groupName} Open group in default browser.
47 |
48 |
49 | help Print help menu.
50 |
51 |
52 | {groupName} Run, add or remove sites from specified group.
53 |
54 | Key: [alias] {arg} ?{optionalArg}
55 | ```
56 |
--------------------------------------------------------------------------------
/api.js:
--------------------------------------------------------------------------------
1 | const fileIo = require('./fileIo')
2 | const error = require('./modules/error')
3 | const chalk = require('chalk')
4 |
5 | class api {
6 | constructor () {
7 | this.state = fileIo.readInitialState()
8 | }
9 |
10 | save () {
11 | return fileIo.writeState(this.state)
12 | }
13 |
14 | // lists
15 |
16 | getList (name) {
17 | const results = this.state.filter( (list) => {
18 | return list.name === name
19 | })
20 |
21 | return results.length ? results[0] : null
22 | }
23 |
24 | listExists (name) {
25 | return !!this.getList(name)
26 | }
27 |
28 | addList (name) {
29 | const list = this.getList(name)
30 |
31 | if (!list) {
32 | this.state.push({ name, sites: [] })
33 | } else {
34 | throw 'List already exists.'
35 | }
36 | }
37 |
38 | removeList (name) {
39 | const listExists = this.listExists(name)
40 | if (listExists) {
41 | this.state = this.state.filter( list => (list.name !== name))
42 | } else {
43 | throw 'List does not exist.'
44 | }
45 | }
46 |
47 | // list items
48 |
49 | get (name) {
50 | const list = this.getList(name)
51 |
52 | if (list) {
53 | return list
54 | } else {
55 | return this.state
56 | }
57 | }
58 |
59 | addItems (name, items) {
60 | const list = this.getList(name)
61 |
62 | if (list) {
63 | list.sites = list.sites.concat(items.map((site) => {
64 | // replace https:// with http://
65 | if (site.indexOf('https://') === 0) {
66 | return `http://${site.slice('https://'.length)}`
67 | } else if (site.indexOf('http://') === 0){
68 | return site
69 | }
70 | return `http://${site}`
71 | }));
72 | } else {
73 | throw 'List not found.'
74 | }
75 | }
76 |
77 | removeItems (name, indexes) {
78 | const list = this.getList(name)
79 |
80 | if (list) {
81 | if (indexes) {
82 | list.sites = list.sites.filter( (item, index) => {
83 | return !indexes.includes(index)
84 | })
85 | } else {
86 | list.sites = [];
87 | }
88 | } else {
89 | throw 'List not found.'
90 | }
91 | }
92 | }
93 |
94 | module.exports = new api();
95 |
--------------------------------------------------------------------------------
/fileIo.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | function getUserHome() {
4 | return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
5 | }
6 |
7 | function readInitialState() {
8 | try {
9 | return JSON.parse(fs.readFileSync(`${getUserHome()}/.web-launcher/store.json`, 'utf8'))
10 | } catch (err) {
11 | switch (err.code) {
12 | case 'ENOENT':
13 | return []
14 | case 'EACCES':
15 | throw 'Error: Cannot read store file.'
16 | default:
17 | throw `Error: ${err}`
18 | }
19 | }
20 | }
21 |
22 | function writeState (state) {
23 |
24 | if (!fs.existsSync(`${getUserHome()}/.web-launcher`)){
25 | fs.mkdirSync(`${getUserHome()}/.web-launcher`);
26 | }
27 |
28 | return new Promise( (resolve, reject) => {
29 | fs.writeFile(`${getUserHome()}/.web-launcher/store.json`, JSON.stringify(state), (err) => {
30 | if (!err) {
31 | resolve(true)
32 | } else {
33 | reject(err)
34 | }
35 | })
36 | })
37 | }
38 |
39 | function deleteState () {
40 | if (fs.existsSync(`${getUserHome()}/.web-launcher`)) {
41 | return new Promise( (resolve, reject) => {
42 | fs.unlink(`${getUserHome()}/.web-launcher/store.json`, (err) => {
43 | if (!err) {
44 | fs.rmdir(`${getUserHome()}/.web-launcher`, (err) => {
45 | if (!err) {
46 | resolve(true)
47 | } else {
48 | reject(err)
49 | }
50 | })
51 | } else {
52 | reject(err)
53 | }
54 | })
55 | })
56 | }
57 | return Promise.resolve(true)
58 | }
59 |
60 | module.exports = { readInitialState, writeState, deleteState };
61 |
--------------------------------------------------------------------------------
/modules/commands.js:
--------------------------------------------------------------------------------
1 | module.exports = () => 2
2 |
--------------------------------------------------------------------------------
/modules/error.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk')
2 |
3 | module.exports = (message) => {
4 | console.log(chalk.red('///////////'))
5 | console.log(chalk.red(message))
6 | console.log(chalk.red('///////////'))
7 | }
8 |
--------------------------------------------------------------------------------
/modules/execute.js:
--------------------------------------------------------------------------------
1 | const exec = require('child_process').exec
2 | const chalk = require('chalk')
3 | const error = require('./error')
4 |
5 | module.exports = (api, list) => {
6 |
7 | try {
8 | if (list) {
9 | executeList(api, api.get(list))
10 | } else {
11 | api.get().forEach(executeList.bind(api))
12 | }
13 | } catch (e) {
14 | error(e)
15 | }
16 |
17 | }
18 |
19 | function executeList (api, list) {
20 | const openCommands = {
21 | darwin: 'open',
22 | linux: 'xdg-open'
23 | }
24 |
25 | function getCommandString(platform, sites) {
26 | // run commands separated by & for windows
27 | if (platform === 'win32') return sites.map(site => `start ${site}`).join(' & ')
28 | return `${openCommands[process.platform]} ${sites.join(' ')}`
29 | }
30 |
31 | if (list.sites.length) {
32 | console.log(chalk.yellow('\launching...'))
33 | exec(getCommandString(process.platform, list.sites))
34 | console.log(chalk.green('Done.'))
35 | } else {
36 | console.log(chalk.green(`No sites to run in `) + chalk.cyan(list.name))
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/modules/group.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk')
2 | const print = require('./print')
3 | const error = require('./error')
4 | const execute = require('./execute')
5 | const help = require('./help')
6 |
7 | module.exports = (api, args, collection) => {
8 |
9 | const command = args.splice(0, 1)[0]
10 |
11 | switch (command) {
12 | case 'list':
13 | case 'ls':
14 | print(api, collection)
15 | break
16 |
17 | case 'add':
18 | case '-a':
19 | addSites(api, args, collection)
20 | break
21 |
22 | case 'clear':
23 | case 'remove':
24 | case 'delete':
25 | case '-d':
26 | clearSites(api, args, collection)
27 | break
28 |
29 | case 'run':
30 | case 'open':
31 | execute(api, collection)
32 | break
33 |
34 | default:
35 | error('Not sure what to do there.')
36 | help('group')
37 | }
38 | }
39 |
40 | function addSites (api, args, collection) {
41 | if (args.length) {
42 | api.addItems(collection, args)
43 | } else {
44 | error(`${chalk.underline.bgRed('add')} must be followed by URLS to be added.`)
45 | }
46 | }
47 |
48 | function clearSites (api, args, collection) {
49 | const validatedArgs = args
50 | .map( arg => parseInt(arg))
51 | .filter( arg => !isNaN(arg))
52 |
53 | if (args.length && validatedArgs.length === args.length) {
54 | api.removeItems(collection, validatedArgs)
55 | } else if (!args.length) {
56 | api.removeItems(collection)
57 | } else {
58 | error(`${chalk.underline.bgRed('clear')} must have 0 or more integer arguments.`)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/modules/help.js:
--------------------------------------------------------------------------------
1 | const error = require('./error')
2 | const chalk = require('chalk')
3 |
4 | module.exports = (section) => {
5 | switch (section) {
6 | case 'root':
7 | case undefined:
8 | printTopLevel()
9 | break
10 |
11 | case 'groups':
12 | printGroup()
13 | break
14 |
15 | case 'group':
16 | printGroupInstance()
17 | break
18 | }
19 | }
20 |
21 | function printTopLevel () {
22 | console.log(chalk.yellow(`
23 |
24 | list [ls] \t\t\t List all groups.
25 | \n
26 | groups \t\t\t Add or remove a group.
27 | \n
28 | run [open] {groupName} \t\t Open group in default browser.
29 | \n
30 | help \t\t\t Print help menu.
31 | \n
32 | {groupName} \t\t\t Run, add or remove sites from specified group.
33 | `))
34 | printKey()
35 | }
36 |
37 | function printGroupInstance () {
38 | console.log(chalk.green('> web {groupName} :'))
39 | console.log(chalk.yellow(`
40 | list [ls] \t\t\t\t List all sites in the group.
41 | \n
42 | add [-a] {site1} {site2} ... \t Add sites to group.
43 | \n
44 | clear [delete] [-d] ?{siteIndex} \t Remove sites. If no args, removes all.
45 | \n
46 | run [open] \t\t\t\t Open group in default browser.
47 | \n
48 | help \t\t\t\t Print this help menu.
49 | `))
50 | printKey()
51 | }
52 |
53 | function printGroup () {
54 | console.log(chalk.green('> web groups :'))
55 | console.log(chalk.yellow(`
56 | list [ls] \t\t\t\t List all sites in the group.
57 | \n
58 | add [-a] {groupName} \t\t\t Add group with specified name.
59 | \n
60 | clear [delete] [-d] {groupName}\t\t Remove group with specified name.
61 | \n
62 | help \t\t\t\t Print this help menu.
63 | `))
64 | printKey()
65 | }
66 |
67 | function printKey () {
68 | console.log(chalk.cyan('Key: [alias] {arg} ?{optionalArg}\n'))
69 | }
70 |
--------------------------------------------------------------------------------
/modules/list.js:
--------------------------------------------------------------------------------
1 | const error = require('./error')
2 | const help = require('./help')
3 |
4 | module.exports = (api, args) => {
5 |
6 | const command = args.splice(0, 1)[0]
7 |
8 | switch (command) {
9 | case 'add':
10 | case '-a':
11 | addList(api, args)
12 | break
13 |
14 | case 'clear':
15 | case 'delete':
16 | case '-d':
17 | removeList(api, args)
18 | break
19 |
20 | case 'help':
21 | default:
22 | error('Not sure what to do there.')
23 | help('groups')
24 | }
25 | }
26 |
27 | function addList (api, args) {
28 | try {
29 | api.addList(args[0])
30 | } catch (e) {
31 | error(e)
32 | }
33 | }
34 |
35 | function removeList (api, args) {
36 | try {
37 | api.removeList(args[0])
38 | } catch (e) {
39 | error(e)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/modules/print.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk')
2 | const error = require('./error')
3 |
4 | module.exports = (api, list) => {
5 |
6 | try {
7 | if (list) {
8 | printCollection(api.get(list))
9 | console.log('\n')
10 | } else {
11 | const lists = api.get()
12 | if (lists.length) {
13 | lists.forEach(printCollection)
14 | console.log('\n')
15 | } else {
16 | console.log(chalk.green('\nNo groups found.\n'))
17 | }
18 | }
19 | } catch (e) {
20 | error(e)
21 | }
22 | }
23 |
24 | function printCollection (list) {
25 | console.log(chalk.green(`\n${list.name}:\n`))
26 |
27 | if (list.sites.length) {
28 | list.sites.forEach( (item, index) => {
29 | console.log(`${chalk.yellow(`${index}:`)}\t${chalk.cyan(item)}`)
30 | })
31 | } else {
32 | console.log(chalk.cyan('No sites stored.'))
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-launcher",
3 | "version": "0.0.19",
4 | "description": "Easily open and manage website lists from the command line",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "preuninstall" : "node scripts/preuninstall.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/briandennis/WebLauncher"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/briandennis/GoodMorning/issues"
18 | },
19 | "homepage": "https://github.com/briandennis/GoodMorning#readme",
20 | "dependencies": {
21 | "chalk": "^1.1.3"
22 | },
23 | "bin": {
24 | "web": "web"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/preuninstall.js:
--------------------------------------------------------------------------------
1 | const { deleteState } = require('../fileIo');
2 | const chalk = require('chalk')
3 |
4 | deleteState().then(() => {
5 | console.log(chalk.yellow('Removing WebLauncher files.'));
6 | console.log(chalk.green('Beginning uninstall.'));
7 | }).catch((err) => {
8 | console.log(`${chalk.red("Failure")} uninstalling WebLauncher with error: ${err}. Exiting.`)
9 | });
10 |
--------------------------------------------------------------------------------
/web:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const chalk = require('chalk')
4 | const api = require('./api')
5 |
6 | const group = require('./modules/group')
7 | const commands = require('./modules/commands')
8 | const execute = require('./modules/execute')
9 | const help = require('./modules/help')
10 | const print = require('./modules/print')
11 | const list = require('./modules/list')
12 | const error = require('./modules/error')
13 |
14 | const command = process.argv[2]
15 | const args = process.argv.slice(3)
16 |
17 | switch (command) {
18 |
19 | case 'ls':
20 | case 'list':
21 | if(args.length !== 0) {
22 | error('Nope, not using that right!')
23 | help()
24 | break
25 | }
26 | print(api)
27 | break
28 |
29 | case 'groups':
30 | list(api, args)
31 | break
32 |
33 | case 'open':
34 | case 'run':
35 | if (args.length === 1) {
36 | if (api.listExists(args[0])) {
37 | execute(api, args[0])
38 | break
39 | } else {
40 | error('Group not found.')
41 | break
42 | }
43 | } else {
44 | error('Nope, not using that right!')
45 | help()
46 | break
47 | }
48 |
49 | case 'help':
50 | case undefined:
51 | help()
52 | break
53 |
54 | default:
55 | if (api.listExists(command)) {
56 | group(api, args, command)
57 | } else {
58 | error('Group not found. Did you mean to do something else?')
59 | help('root')
60 | }
61 | }
62 |
63 | api.save()
64 |
--------------------------------------------------------------------------------