diff --git a/api-client.js b/api-client.js
index 0246c48..6cac1bc 100644
--- a/api-client.js
+++ b/api-client.js
@@ -7,19 +7,19 @@ 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',
@@ -28,10 +28,12 @@ class ApiClient {
'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,42 +41,42 @@ 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,
@@ -83,18 +85,19 @@ class ApiClient {
'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,
@@ -105,9 +108,13 @@ class ApiClient {
'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..65ab7f3 100644
--- a/front-end.js
+++ b/front-end.js
@@ -1,46 +1,64 @@
-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: ''
- }
+ };
},
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,7 +87,7 @@ app = new Vue({
}
});
},
- logOut: function () {
+ logOut: function() {
api.logOut(() => {
this.$emit('log-out');
});
@@ -84,38 +102,38 @@ app = new Vue({
template: '#browser',
props: ['patches', 'downloading', 'currentListId', 'connected'],
computed: {
- filteredPatches: function () {
+ filteredPatches: function() {
return categoryFilter(this.patches, this.currentListId);
- },
+ }
},
components: {
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';
}
},
@@ -125,15 +143,17 @@ 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'
@@ -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 3f2047e..e0c9956 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 = {
@@ -25,27 +27,24 @@ if (!isDev) {
title: 'Application Update',
message: releaseName,
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";
@@ -62,18 +61,18 @@ const mb = menubar({
});
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,35 +138,37 @@ 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() {
@@ -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();
@@ -229,7 +230,7 @@ async function watchOP1() {
watcher = chokidar.watch(mountpoint, {
ignored: /(^|[\/\\])\../,
- awaitWriteFinish: true,
+ awaitWriteFinish: true
}).on('all', (event, path) => {
if (mountpoint) {
const relPath = path.slice(mountpoint.length);
diff --git a/op1-patch.js b/op1-patch.js
index 87e07a5..85ff1dc 100644
--- a/op1-patch.js
+++ b/op1-patch.js
@@ -1,11 +1,13 @@
const fs = require('fs');
-const wordAlign = function(v) { return v + v % 2; }
+const wordAlign = function(v) {
+ return v + v % 2;
+};
class OP1Patch {
constructor(options) {
this.path = options.path;
this.relPath = options.relPath;
- this._pathParts = this.relPath.split("/");
+ this._pathParts = this.relPath.split('/');
this.name = this._pathParts[this._pathParts.length-1];
this.metadata = null;
this.category = null;
@@ -15,29 +17,29 @@ class OP1Patch {
this._setPackName();
this._setPackDir();
}
-
+
_parse() {
- var bytes = fs.readFileSync(this.path);
+ const bytes = fs.readFileSync(this.path);
if (String.fromCharCode.apply(null, bytes.subarray(0, 4)) !== 'FORM') {
- throw(new Error("FORM header not found"));
+ throw (new Error('FORM header not found'));
}
- var dv = new DataView(bytes.buffer, 0, bytes.byteLength);
- var length = dv.getUint32(4, false);
+ const dv = new DataView(bytes.buffer, 0, bytes.byteLength);
+ const length = dv.getUint32(4, false);
if (bytes.byteLength < 8+length) {
- console.log("invalid length for", this.path);
+ console.log('invalid length for', this.path);
// throw(new Error("invalid data length"));
}
- var header = String.fromCharCode.apply(null, bytes.subarray(8, 12));
+ const header = String.fromCharCode.apply(null, bytes.subarray(8, 12));
if (header !== 'AIFC' && header !== 'AIFF') {
- throw(new Error("AIFC/AIFF header not found"));
+ throw (new Error('AIFC/AIFF header not found'));
}
- for (var pos = 12; pos < length; pos += 8 + wordAlign(dv.getUint32(pos + 4, false))) {
- var chunkName = String.fromCharCode.apply(null, bytes.subarray(pos, pos + 4));
+ for (let pos = 12; pos < length; pos += 8 + wordAlign(dv.getUint32(pos + 4, false))) {
+ const chunkName = String.fromCharCode.apply(null, bytes.subarray(pos, pos + 4));
if (chunkName === 'APPL') {
- var signature = String.fromCharCode.apply(null, bytes.subarray(pos+8, pos+12));
- var appl = String.fromCharCode.apply(null, bytes.subarray(
- pos + 12,
- pos + 8 + dv.getUint32(pos + 4, false)
+ const signature = String.fromCharCode.apply(null, bytes.subarray(pos+8, pos+12));
+ let appl = String.fromCharCode.apply(null, bytes.subarray(
+ pos + 12,
+ pos + 8 + dv.getUint32(pos + 4, false)
));
if (signature === 'op-1') {
appl = appl.replace(/\0/g, ''); // json is NUL padded
@@ -48,26 +50,26 @@ class OP1Patch {
}
}
}
-
+
_setCategory() {
- if (this.metadata.type === "drum") {
- this.category = "drum";
- } else if (this.metadata.type === "sampler") {
- this.category = "sampler";
+ if (this.metadata.type === 'drum') {
+ this.category = 'drum';
+ } else if (this.metadata.type === 'sampler') {
+ this.category = 'sampler';
} else if (this.metadata.type) {
- this.category = "synth";
+ this.category = 'synth';
}
}
-
+
_setPackName() {
if (this._pathParts.length > 3) {
- this.packName = this._pathParts.slice(2,this._pathParts.length-1).join("/");
+ this.packName = this._pathParts.slice(2, this._pathParts.length-1).join('/');
}
}
-
+
_setPackDir() {
if (this._pathParts.length > 3) {
- this.packDir = this._pathParts.slice(0,this._pathParts.length-1).join("/");
+ this.packDir = this._pathParts.slice(0, this._pathParts.length-1).join('/');
}
}
}