forked from external-repos/noisedash
Add profile import and export
This commit is contained in:
@@ -77,6 +77,66 @@ router.post('/profiles', (req, res) => {
|
||||
})
|
||||
})
|
||||
|
||||
router.post('/profiles/import', (req, res) => {
|
||||
if (!req.user) {
|
||||
return res.sendStatus(401)
|
||||
}
|
||||
|
||||
let profileID = 0
|
||||
|
||||
db.serialize(() => {
|
||||
db.run(`INSERT INTO profiles (
|
||||
name,
|
||||
user,
|
||||
timer_enabled,
|
||||
duration,
|
||||
volume,
|
||||
noise_color,
|
||||
filter_enabled,
|
||||
filter_type,
|
||||
filter_cutoff,
|
||||
lfo_filter_cutoff_enabled,
|
||||
lfo_filter_cutoff_frequency,
|
||||
lfo_filter_cutoff_low,
|
||||
lfo_filter_cutoff_high,
|
||||
tremolo_enabled,
|
||||
tremolo_frequency,
|
||||
tremolo_depth)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
||||
req.body.name,
|
||||
req.user.id,
|
||||
req.body.isTimerEnabled ? 1 : 0,
|
||||
req.body.duration,
|
||||
req.body.volume,
|
||||
req.body.noiseColor,
|
||||
req.body.isFilterEnabled ? 1 : 0,
|
||||
req.body.filterType,
|
||||
req.body.filterCutoff,
|
||||
req.body.isLFOFilterCutoffEnabled ? 1 : 0,
|
||||
req.body.lfoFilterCutoffFrequency,
|
||||
req.body.lfoFilterCutoffLow,
|
||||
req.body.lfoFilterCutoffHigh,
|
||||
req.body.isTremoloEnabled ? 1 : 0,
|
||||
req.body.tremoloFrequency,
|
||||
req.body.tremoloDepth
|
||||
],
|
||||
function (err) {
|
||||
if (err) {
|
||||
logger.error(err)
|
||||
if (err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.sendStatus(409)
|
||||
} else {
|
||||
return res.sendStatus(500)
|
||||
}
|
||||
}
|
||||
|
||||
profileID = this.lastID
|
||||
|
||||
return res.json({ id: profileID })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
router.put('/profiles/:profileId', (req, res) => {
|
||||
if (!req.user) {
|
||||
return res.sendStatus(401)
|
||||
|
||||
@@ -123,6 +123,149 @@
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
|
||||
<v-dialog
|
||||
v-model="profileMoreDialog"
|
||||
max-width="600px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-bind="attrs"
|
||||
class="mx-3 my-3"
|
||||
:disabled="playDisabled"
|
||||
v-on="on"
|
||||
>
|
||||
More...
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">More Profile Options</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-list-item-group>
|
||||
<v-list-item
|
||||
@click="openImportDialog"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-file-import</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>
|
||||
Import Profile
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="openExportDialog"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-file-export</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>
|
||||
Export Profile
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
text
|
||||
@click="profileMoreDialog = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-dialog
|
||||
v-model="importDialog"
|
||||
max-width="600px"
|
||||
>
|
||||
<v-form
|
||||
ref="importForm"
|
||||
v-model="isImportValid"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">Import Profile</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-file-input
|
||||
v-model="importedProfile"
|
||||
accept=".json"
|
||||
label="Upload a profile file!"
|
||||
:rules="[rules.required()]"
|
||||
/>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
text
|
||||
@click="importDialog = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
:disabled="!isImportValid"
|
||||
@click="importProfile"
|
||||
>
|
||||
Import
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
|
||||
<v-dialog
|
||||
v-model="exportDialog"
|
||||
max-width="600px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">Export Profile</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-select
|
||||
v-model="exportedProfile"
|
||||
:items="profileItems"
|
||||
return-object
|
||||
label="Profiles"
|
||||
class="mx-3 mb-5"
|
||||
/>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
text
|
||||
@click="exportDialog = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
@click="exportProfile"
|
||||
>
|
||||
Export
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
|
||||
@@ -10,6 +10,12 @@ export default {
|
||||
profileDialog: false,
|
||||
profileName: '',
|
||||
isProfileValid: false,
|
||||
profileMoreDialog: false,
|
||||
importDialog: false,
|
||||
isImportValid: false,
|
||||
exportDialog: false,
|
||||
importedProfile: null,
|
||||
exportedProfile: {},
|
||||
infoSnackbar: false,
|
||||
infoSnackbarText: '',
|
||||
playDisabled: false,
|
||||
@@ -213,6 +219,7 @@ export default {
|
||||
} else {
|
||||
this.selectedProfile = this.profileItems.find(p => p.id === profileId)
|
||||
}
|
||||
this.exportedProfile = this.profileItems[0]
|
||||
this.loadProfile()
|
||||
}
|
||||
}
|
||||
@@ -311,6 +318,10 @@ export default {
|
||||
this.loadedSamples = profile.samples
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.errorSnackbarText = 'Error Loading Profile'
|
||||
this.errorSnackbar = true
|
||||
})
|
||||
},
|
||||
deleteProfile () {
|
||||
this.$http.delete('/profiles/'.concat(this.selectedProfile.id))
|
||||
@@ -403,6 +414,102 @@ export default {
|
||||
if (this.$refs.uploadSampleForm) {
|
||||
this.$refs.uploadSampleForm.reset()
|
||||
}
|
||||
},
|
||||
openImportDialog () {
|
||||
this.profileMoreDialog = false
|
||||
this.importDialog = true
|
||||
},
|
||||
openExportDialog () {
|
||||
this.profileMoreDialog = false
|
||||
this.exportDialog = true
|
||||
},
|
||||
async importProfile () {
|
||||
const fileContents = await this.readFile(this.importedProfile)
|
||||
const profileJSON = JSON.parse(fileContents)
|
||||
|
||||
this.$http.post('/profiles/import', {
|
||||
name: profileJSON.name,
|
||||
isTimerEnabled: profileJSON.isTimerEnabled,
|
||||
duration: profileJSON.duration,
|
||||
volume: profileJSON.volume,
|
||||
noiseColor: profileJSON.noiseColor,
|
||||
isFilterEnabled: profileJSON.isFilterEnabled,
|
||||
filterType: profileJSON.filterType,
|
||||
filterCutoff: profileJSON.filterCutoff,
|
||||
isLFOFilterCutoffEnabled: profileJSON.isLFOFilterCutoffEnabled,
|
||||
lfoFilterCutoffFrequency: profileJSON.lfoFilterCutoffFrequency,
|
||||
lfoFilterCutoffLow: profileJSON.lfoFilterCutoffLow,
|
||||
lfoFilterCutoffHigh: profileJSON.lfoFilterCutoffHigh,
|
||||
isTremoloEnabled: profileJSON.isTremoloEnabled,
|
||||
tremoloFrequency: profileJSON.tremoloFrequency,
|
||||
tremoloDepth: profileJSON.tremoloDepth
|
||||
}).then(response => {
|
||||
if (response.status === 200) {
|
||||
this.importDialog = false
|
||||
this.populateProfileItems(response.data.id)
|
||||
this.infoSnackbarText = 'Profile Imported and Saved'
|
||||
this.infoSnackbar = true
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.errorSnackbarText = 'Error Saving Profile'
|
||||
this.errorSnackbar = true
|
||||
})
|
||||
|
||||
if (this.$refs.importForm) {
|
||||
this.$refs.importForm.reset()
|
||||
}
|
||||
},
|
||||
readFile (file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = res => {
|
||||
resolve(res.target.result)
|
||||
}
|
||||
reader.onerror = err => reject(err)
|
||||
|
||||
reader.readAsText(file)
|
||||
})
|
||||
},
|
||||
exportProfile () {
|
||||
this.$http.get('/profiles/'.concat(this.exportedProfile.id))
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
const profile = response.data.profile
|
||||
|
||||
const profileJSON = {}
|
||||
profileJSON.name = this.exportedProfile.text
|
||||
profileJSON.isTimerEnabled = profile.isTimerEnabled
|
||||
profileJSON.duration = profile.duration
|
||||
profileJSON.volume = profile.volume
|
||||
profileJSON.noiseColor = profile.noiseColor
|
||||
profileJSON.isFilterEnabled = profile.isFilterEnabled
|
||||
profileJSON.filterType = profile.filterType
|
||||
profileJSON.filterCutoff = profile.filterCutoff
|
||||
profileJSON.isLFOFilterCutoffEnabled = profile.isLFOFilterCutoffEnabled
|
||||
profileJSON.lfoFilterCutoffFrequency = profile.lfoFilterCutoffFrequency
|
||||
profileJSON.lfoFilterCutoffLow = profile.lfoFilterCutoffLow
|
||||
profileJSON.lfoFilterCutoffHigh = profile.lfoFilterCutoffHigh
|
||||
profileJSON.isTremoloEnabled = profile.isTremoloEnabled
|
||||
profileJSON.tremoloFrequency = profile.tremoloFrequency
|
||||
profileJSON.tremoloDepth = profile.tremoloDepth
|
||||
|
||||
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(profileJSON))
|
||||
const downloadAnchorNode = document.createElement('a')
|
||||
downloadAnchorNode.setAttribute('href', dataStr)
|
||||
downloadAnchorNode.setAttribute('download', profileJSON.name + '.json')
|
||||
document.body.appendChild(downloadAnchorNode) // required for firefox
|
||||
downloadAnchorNode.click()
|
||||
downloadAnchorNode.remove()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.errorSnackbarText = 'Error Loading Profile'
|
||||
this.errorSnackbar = true
|
||||
})
|
||||
|
||||
this.exportDialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user