diff --git a/api-client.js b/api-client.js index 0246c48..6f32e80 100644 --- a/api-client.js +++ b/api-client.js @@ -7,31 +7,33 @@ class ApiClient { this.config = new ElectronStore(); this.store = new JsonApiDataStore(); } - + token() { return this.config.get('token'); } - + email() { return this.config.get('email'); } - + logIn(email, password, callback) { - var me = this; + const me = this; this.config.set('email', email); - var req = https.request({ + const req = https.request({ method: 'POST', host: 'api.op1.fun', path: '/v1/api_token', headers: { 'Content-Type': 'application/json', - 'Accept': 'application/json' - } + 'Accept': 'application/json', + }, }, function(res) { - var body = ''; - res.on('data', function(d) { body += d; }); + let body = ''; + res.on('data', function(d) { + body += d; + }); res.on('end', function() { - var res = JSON.parse(body); + const res = JSON.parse(body); if (res.api_token) { me.config.set('token', res.api_token); } @@ -39,62 +41,63 @@ class ApiClient { callback(res); }); }); - req.write(JSON.stringify({ email: email, password: password })); + req.write(JSON.stringify({email: email, password: password})); req.end(); } - + enableAppFeatureFlag() { - this._post('feature_flags', { flags: { app: true } }, function() {}); + this._post('feature_flags', {flags: {app: true}}, function() {}); } - + logOut(callback) { this.config.set('email', null); this.config.set('token', null); callback(); } - + isLoggedIn() { return (this.email() && this.token()); } - + getPack(path, id, callback) { - var me = this; + const me = this; this._get(path, function() { - var pack = me.store.find("packs", id); + const pack = me.store.find('packs', id); callback(pack); - }) + }); } - + getPatch(path, id, callback) { - var me = this; + const me = this; this._get(path, function() { - var patch = me.store.find("patches", id); + const patch = me.store.find('patches', id); callback(patch); - }) + }); } - + _get(path, callback) { - var me = this; + const me = this; return https.get({ host: 'api.op1.fun', path: '/v1/' + path, headers: { 'X-User-Email': this.email(), - 'X-User-Token': this.token() - } + 'X-User-Token': this.token(), + }, }, function(res) { - var body = ''; - res.on('data', function(d) { body += d; }); + let body = ''; + res.on('data', function(d) { + body += d; + }); res.on('end', function() { me.store.sync(JSON.parse(body)); callback(); }); }); } - + _post(path, data, callback) { - var me = this; - var req = https.request({ + const req = https.request({ method: 'POST', host: 'api.op1.fun', path: '/v1/' + path, @@ -102,12 +105,16 @@ class ApiClient { 'X-User-Email': this.email(), 'X-User-Token': this.token(), 'Content-Type': 'application/json', - 'Accept': 'application/json' - } + 'Accept': 'application/json', + }, }, function(res) { - var body = ''; - res.on('data', function(d) { body += d; }); - res.on('end', function() { callback(body); }); + let body = ''; + res.on('data', function(d) { + body += d; + }); + res.on('end', function() { + callback(body); + }); }); console.log(data); console.log(JSON.stringify(data)); diff --git a/front-end.js b/front-end.js index 4485070..85f4375 100644 --- a/front-end.js +++ b/front-end.js @@ -1,45 +1,63 @@ -const { ipcRenderer, webFrame } = require('electron'); +const {ipcRenderer, webFrame} = require('electron'); const ApiClient = require('./api-client'); const groupBy = require('./lib/group-by'); const api = new ApiClient(); const version = require('./package.json').version; -var app; - // disable zoom webFrame.setVisualZoomLevelLimits(1, 1); -var categoryFilter = function (patches, category) { - var filtered = patches.filter((p) => { return p.category === category }); - return filtered.sort(function (a, b) { +const categoryFilter = function(patches, category) { + const filtered = patches.filter((p) => { + return p.category === category; + }); + return filtered.sort(function(a, b) { // "/000" makes root level patches sort to the top - var _a = (a.packDir || "/000") + a.name.toLowerCase(); - var _b = (b.packDir || "/000") + b.name.toLowerCase(); - if (_a < _b) { return -1 } else if (_a > _b) { return 1 } + const _a = (a.packDir || '/000') + a.name.toLowerCase(); + const _b = (b.packDir || '/000') + b.name.toLowerCase(); + if (_a < _b) { + return -1; + } else if (_a > _b) { + return 1; + } return 0; }); -} +}; -app = new Vue({ +const app = new Vue({ el: '#app', - data: { - patches: [], - downloading: false, - currentView: api.isLoggedIn() ? 'browser' : 'login', - currentListId: 'synth', - loginError: '', - isLoggedIn: api.isLoggedIn(), - connected: false + data: function() { + return { + patches: [], + downloading: false, + currentView: api.isLoggedIn() ? 'browser' : 'login', + currentListId: 'synth', + loginError: '', + isLoggedIn: api.isLoggedIn(), + connected: false, + }; }, methods: { - goToView: function (e) { this.currentView = e }, - showList: function (e) { this.currentListId = e }, - setLoginError: function (error) { this.loginError = error; }, - setLoggedInFalse: function () { this.isLoggedIn = false; }, - setLoggedInTrue: function () { this.isLoggedIn = true; }, - mountOP1: function () { ipcRenderer.send('mount-op1'); }, - showPopupMenu: function () { - ipcRenderer.send('show-popup-menu', { view: this.currentView }); + goToView: function(e) { + this.currentView = e; + }, + showList: function(e) { + this.currentListId = e; + }, + setLoginError: function(error) { + this.loginError = error; + }, + setLoggedInFalse: function() { + this.isLoggedIn = false; + }, + setLoggedInTrue: function() { + this.isLoggedIn = true; + }, + mountOP1: function() { + ipcRenderer.send('mount-op1'); + }, + showPopupMenu: function() { + ipcRenderer.send('show-popup-menu', {view: this.currentView}); }, }, components: { @@ -49,16 +67,16 @@ app = new Vue({ // login: { template: '#login', - data: function () { + data: function() { return { email: api.email(), version: version, - password: '' - } + password: '', + }; }, props: ['loginError', 'isLoggedIn'], methods: { - logIn: function (e) { + logIn: function(e) { api.logIn(this.email, this.password, (res) => { if (res.error) { this.$emit('error', res.error); @@ -69,12 +87,12 @@ app = new Vue({ } }); }, - logOut: function () { + logOut: function() { api.logOut(() => { this.$emit('log-out'); }); - } - } + }, + }, }, // @@ -84,7 +102,7 @@ app = new Vue({ template: '#browser', props: ['patches', 'downloading', 'currentListId', 'connected'], computed: { - filteredPatches: function () { + filteredPatches: function() { return categoryFilter(this.patches, this.currentListId); }, }, @@ -92,32 +110,32 @@ app = new Vue({ sideNav: { template: '#side-nav', props: ['patches', 'currentListId'], - data: function () { + data: function() { return { - limits: { drum: 42, synth: 100, sampler: 42 }, - } + limits: {drum: 42, synth: 100, sampler: 42}, + }; }, computed: { - navItems: function () { - var sub = (cat) => { - return categoryFilter(this.patches, cat).length + " of " + this.limits[cat]; - } + navItems: function() { + const sub = (cat) => { + return categoryFilter(this.patches, cat).length + ' of ' + this.limits[cat]; + }; return [ - { id: 'synth', title: 'Synth', subtitle: sub('synth') }, - { id: 'drum', title: 'Drum', subtitle: sub('drum') }, - { id: 'sampler', title: 'Sampler', subtitle: sub('sampler') }, + {id: 'synth', title: 'Synth', subtitle: sub('synth')}, + {id: 'drum', title: 'Drum', subtitle: sub('drum')}, + {id: 'sampler', title: 'Sampler', subtitle: sub('sampler')}, // { id: 'backups', title: 'Backups', subtitle: 'ok' }, - ] - } - } + ]; + }, + }, }, contentArea: { - template: "", + template: '', props: ['currentListId', 'patches', 'id'], computed: { - currentComponent: function () { + currentComponent: function() { return (this.currentListId === 'backups') ? 'backups' : 'patch-list'; - } + }, }, components: { @@ -125,29 +143,31 @@ app = new Vue({ template: '#patch-list', props: ['patches', 'id'], computed: { - packs: function () { return groupBy(this.patches, 'packName') } + packs: function() { + return groupBy(this.patches, 'packName'); + }, }, methods: { - showInFinder: function (e) { + showInFinder: function(e) { if (e) { - ipcRenderer.send('show-in-finder', e.target.getAttribute("href")); + ipcRenderer.send('show-in-finder', e.target.getAttribute('href')); } }, }, }, backups: { - template: '#backups' - } + template: '#backups', + }, - } + }, }, disconnected: { - template: '#disconnected' - } - } - } + template: '#disconnected', + }, + }, + }, - } + }, }); @@ -172,9 +192,9 @@ ipcRenderer.on('show-login', (event, data) => { ipcRenderer.on('start-download', (event, message) => { if (message['pack']) { - app.downloading = "Downloading Pack: " + message.pack.name; + app.downloading = 'Downloading Pack: ' + message.pack.name; } else if (message['patch']) { - app.downloading = "Downloading Patch: " + message.patch.name; + app.downloading = 'Downloading Patch: ' + message.patch.name; } }); diff --git a/index.js b/index.js index fb9c920..3084644 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ -const { menubar } = require('menubar'); -const { autoUpdater, dialog, ipcMain, shell, Menu } = require('electron'); -const { download } = require('electron-dl'); +const {menubar} = require('menubar'); +const {autoUpdater, dialog, ipcMain, shell, Menu} = require('electron'); +const {download} = require('electron-dl'); const chokidar = require('chokidar'); const drivelist = require('drivelist'); const Url = require('url'); @@ -13,10 +13,12 @@ const isDev = require('electron-is-dev'); if (!isDev) { const version = require('./package.json').version; - const platform = os.platform() + "_" + os.arch(); + const platform = os.platform() + '_' + os.arch(); autoUpdater.setFeedURL('https://nuts.op1.fun/update/' + platform + '/' + version); autoUpdater.checkForUpdates(); - setInterval(() => { autoUpdater.checkForUpdates() }, 300000); + setInterval(() => { + autoUpdater.checkForUpdates(); + }, 300000); autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { const dialogOpts = { @@ -24,28 +26,25 @@ if (!isDev) { buttons: ['Restart', 'Later'], title: 'Application Update', message: releaseName, - detail: 'A new version of op1.fun.app has been downloaded. Restart the application to apply the update.' - } + detail: 'A new version of op1.fun.app has been downloaded. Restart the application to apply the update.', + }; dialog.showMessageBox(dialogOpts, (response) => { if (response === 0) autoUpdater.quitAndInstall(); }); }); - autoUpdater.on('error', message => { + autoUpdater.on('error', (message) => { console.error('There was a problem updating the application'); console.error(message); }); } -var email, - token, - watcher, - urlToOpen, - mountpoint, - patches = [], - mounted = false, - settingUpWatcher = false; +let watcher; +let mountpoint; +let patches = []; +let mounted = false; +let settingUpWatcher = false; // mountpoint = "/Users/jordan/Documents/OP-1/fakeop1"; @@ -53,27 +52,27 @@ const mb = menubar({ browserWindow: { webPreferences: { nodeIntegration: true, - contextIsolation: false + contextIsolation: false, }, - width: 600 + width: 600, }, preloadWindow: true, - icon: path.join(__dirname, 'icon.png') + icon: path.join(__dirname, 'icon.png'), }); mb.on('ready', function ready() { - ensureConnected().then(function (message) { + ensureConnected().then(function(message) { mb.showWindow(); - }, function (reason) { + }, function(reason) { mb.showWindow(); }); }); -mb.app.on('open-url', function (e, urlStr) { +mb.app.on('open-url', function(e, urlStr) { e.preventDefault(); if (ensureLoggedIn()) { - ensureConnected().then(function () { - var { id, path, type } = parseUrl(urlStr); + ensureConnected().then(function() { + const {id, path, type} = parseUrl(urlStr); if (type === 'packs' && id) { api.getPack(path, id, loadPack); } else if (type === 'patches' && id) { @@ -89,7 +88,7 @@ mb.app.on('open-url', function (e, urlStr) { mb.on('after-show', function show() { if (ensureLoggedIn()) { - ensureConnected().catch(function (reason) { + ensureConnected().catch(function(reason) { // noop }); }; @@ -99,18 +98,18 @@ ipcMain.on('show-popup-menu', (event, args) => { let menu; if (args.view === 'login') { menu = Menu.buildFromTemplate([ - { role: 'quit' } + {role: 'quit'}, ]); } else { menu = Menu.buildFromTemplate([ - { label: 'Account Settings', click: () => { + {label: 'Account Settings', click: () => { mb.window.webContents.send('go-to-view', 'login'); }}, - { type: 'separator' }, - { role: 'quit' } + {type: 'separator'}, + {role: 'quit'}, ]); } - + menu.popup(mb.window); }); @@ -119,7 +118,7 @@ ipcMain.on('show-in-finder', (event, arg) => { }); ipcMain.on('mount-op1', (event, arg) => { - ensureConnected().catch(function (reason) { + ensureConnected().catch(function(reason) { // noop }); }); @@ -130,7 +129,7 @@ ipcMain.on('show-config-menu', (event, arg) => { function loadPatch(patch, packDir) { mb.showWindow(); - var dir = [mountpoint]; + const dir = [mountpoint]; if (patch['patch-type'] === 'drum') { dir.push('drum'); } else { @@ -139,41 +138,43 @@ function loadPatch(patch, packDir) { if (packDir) { dir.push(packDir); } else { - mb.window.webContents.send('start-download', { patch: patch }); + mb.window.webContents.send('start-download', {patch: patch}); } - result = download(mb.window, patch.links.file, { directory: dir.join("/") }); + result = download(mb.window, patch.links.file, {directory: dir.join('/')}); if (!packDir) { - result = result.then(function () { - mb.window.webContents.send('finish-download', { patch: patch }); + result = result.then(function() { + mb.window.webContents.send('finish-download', {patch: patch}); }); } return result; } function loadPack(pack) { - mb.window.webContents.send('start-download', { pack: pack }); - var result = Promise.resolve(); - pack.patches.forEach(function (patch) { + mb.window.webContents.send('start-download', {pack: pack}); + let result = Promise.resolve(); + pack.patches.forEach(function(patch) { result = result.then(() => loadPatch(patch, pack.id)); }); - result = result.then(function () { - mb.window.webContents.send('finish-download', { pack: pack }); - }) + result = result.then(function() { + mb.window.webContents.send('finish-download', {pack: pack}); + }); return result; } function parseUrl(urlStr) { - var parsed = Url.parse(urlStr); - var path = parsed.pathname - while (path.charAt(0) === "/") { path = path.slice(1); } - var parts = path.split("/"); - return { type: parts[2], id: parts[3], path: path }; + const parsed = Url.parse(urlStr); + let path = parsed.pathname; + while (path.charAt(0) === '/') { + path = path.slice(1); + } + const parts = path.split('/'); + return {type: parts[2], id: parts[3], path: path}; } function ensureLoggedIn() { if (!api.isLoggedIn()) { mb.window.webContents.send('show-login', { - message: 'Please login to download packs and patches.' + message: 'Please login to download packs and patches.', }); return false; } @@ -186,10 +187,10 @@ function ensureConnected() { return Promise.resolve(true); } else if (!settingUpWatcher) { settingUpWatcher = true; - return watchOP1().then(function () { + return watchOP1().then(function() { mb.window.webContents.send('op1-connected', true); settingUpWatcher = false; - }, function (error) { + }, function(error) { mb.window.webContents.send('op1-connected', false); settingUpWatcher = false; return Promise.reject(); @@ -212,7 +213,7 @@ async function watchOP1() { const drives = await drivelist.list(); for (let i = 0; i < drives.length; i++) { - if (drives[i].description.indexOf("OP-1") > -1) { + if (drives[i].description.indexOf('OP-1') > -1) { const m = drives[i].mountpoints[0]; if (m) { mountpoint = m.path; @@ -223,25 +224,25 @@ async function watchOP1() { if (!mountpoint) { mounted = false; - throw new Error("OP-1 not found"); + throw new Error('OP-1 not found'); } else { mounted = true; } watcher = chokidar.watch(mountpoint, { ignored: /(^|[\/\\])\../, - awaitWriteFinish: true + awaitWriteFinish: true, }).on('all', (event, path) => { if (mountpoint) { const relPath = path.slice(mountpoint.length); - const parts = relPath.split("/"); + const parts = relPath.split('/'); if ( // ignore album, tape and user preset patches - ((parts[1] === "synth") || (parts[1] === "drum")) && parts[2] != "user" + ((parts[1] === 'synth') || (parts[1] === 'drum')) && parts[2] != 'user' ) { if (event === 'add') { try { - const patch = new OP1Patch({ path: path, relPath: relPath }); + const patch = new OP1Patch({path: path, relPath: relPath}); if (patch.metadata) { patches.push(patch); mb.window.webContents.send('render-patches', patches); @@ -250,14 +251,16 @@ async function watchOP1() { console.log(e); } } else if (event === 'unlink') { - patches = patches.filter(function (p) { return p.relPath !== relPath }); + patches = patches.filter(function(p) { + return p.relPath !== relPath; + }); mb.window.webContents.send('render-patches', patches); } } else { // console.log(event, path); } } - }).on('raw', function (event, path, details) { + }).on('raw', function(event, path, details) { if ( (details.event === 'root-changed') || (details.event === 'deleted' && path === mountpoint)