Playback error fix, downloading on windows crash fix, logging POC

This commit is contained in:
exttex 2020-09-01 20:37:02 +02:00
parent 736fa01161
commit 96db2c3753
10 changed files with 116 additions and 11 deletions

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<v-dialog v-model='show' max-width='420'> <v-dialog v-model='dShow' max-width='420'>
<v-card> <v-card>
<v-card-title class='headline'> <v-card-title class='headline'>
@ -57,6 +57,7 @@ export default {
], ],
qualityString: 'Settings quality', qualityString: 'Settings quality',
autostart: true, autostart: true,
dShow: this.show
} }
}, },
methods: { methods: {
@ -98,6 +99,15 @@ export default {
return duration * this.$root.settings.downloadsQuality; return duration * this.$root.settings.downloadsQuality;
} }
},
watch: {
//Prevent errors on closing with mouse
show() {
this.dShow = this.show;
},
dShow() {
if (!this.dShow) this.$emit('close');
}
} }
} }
</script> </script>

View File

@ -49,7 +49,7 @@ export default {
try { try {
let res = await this.$axios.get(`/lyrics/${this.songId}`); let res = await this.$axios.get(`/lyrics/${this.songId}`);
if (res.data) this.lyrics = res.data; if (res.data && res.data.lyrics.length > 0) this.lyrics = res.data;
} catch (e) {true;} } catch (e) {true;}
this.loading = false; this.loading = false;

View File

@ -94,7 +94,10 @@ new Vue({
source: 'none', source: 'none',
data: 'none' data: 'none'
} }
} },
//Used to prevent double listen logging
logListenId: null
}, },
methods: { methods: {
// PLAYBACK METHODS // PLAYBACK METHODS
@ -106,6 +109,8 @@ new Vue({
if (!this.audio || this.state != 1) return; if (!this.audio || this.state != 1) return;
this.audio.play(); this.audio.play();
this.state = 2; this.state = 2;
this.logListen();
}, },
pause() { pause() {
if (!this.audio || this.state != 2) return; if (!this.audio || this.state != 2) return;
@ -217,6 +222,7 @@ new Vue({
//Play //Play
this.state = 2; this.state = 2;
this.audio.play(); this.audio.play();
this.logListen();
await this.savePlaybackInfo(); await this.savePlaybackInfo();
return; return;
} }
@ -326,6 +332,16 @@ new Vue({
async cacheLibrary() { async cacheLibrary() {
let res = await this.$axios.get(`/playlist/${this.profile.favoritesPlaylist}?full=idk`); let res = await this.$axios.get(`/playlist/${this.profile.favoritesPlaylist}?full=idk`);
this.libraryTracks = res.data.tracks.map((t) => t.id); this.libraryTracks = res.data.tracks.map((t) => t.id);
},
//Log song listened to deezer, only if allowed
async logListen() {
if (!this.settings.logListen) return;
if (this.logListenId == this.track.id) return;
if (!this.track || !this.track.id) return;
this.logListenId = this.track.id;
await this.$axios.put(`/log/${this.track.id}`);
} }
}, },
async created() { async created() {

View File

@ -20,8 +20,8 @@
</v-card> </v-card>
<h1 class='pb-2'>Queue:</h1> <h1 class='pb-2'>Queue:</h1>
<div class='text-h6 pb-2 d-flex'>Total: {{$root.downloads.length}} <div class='text-h6 mr-4 pb-2 d-flex'>Total: {{$root.downloads.length}}
<v-btn @click='$root.toggleDownload' class='ml-2' color='primary'> <v-btn @click='$root.toggleDownload' class='ml-4' color='primary'>
<div v-if='$root.downloading'> <div v-if='$root.downloading'>
<v-icon>mdi-stop</v-icon> <v-icon>mdi-stop</v-icon>
Stop Stop
@ -32,15 +32,20 @@
</div> </div>
</v-btn> </v-btn>
<!-- Open dir --> <!-- Open dir -->
<v-btn @click='openDir' class='ml-2' v-if='$root.settings.electron'> <v-btn @click='openDir' class='ml-4' v-if='$root.settings.electron'>
<v-icon>mdi-folder</v-icon> <v-icon>mdi-folder</v-icon>
Show folder Show folder
</v-btn> </v-btn>
<!-- Delete all -->
<v-btn @click='deleteDownload(-1)' class='ml-4' color='red'>
<v-icon>mdi-delete</v-icon>
Clear queue
</v-btn>
</div> </div>
<!-- Downloads --> <!-- Downloads -->
<v-list dense> <v-list dense>
<div v-for='download in $root.downloads' :key='download.id'> <div v-for='(download, index) in $root.downloads' :key='download.id'>
<v-list-item dense> <v-list-item dense>
<v-list-item-avatar> <v-list-item-avatar>
<v-img :src='download.track.albumArt.thumb'></v-img> <v-img :src='download.track.albumArt.thumb'></v-img>
@ -49,6 +54,11 @@
<v-list-item-title>{{download.track.title}}</v-list-item-title> <v-list-item-title>{{download.track.title}}</v-list-item-title>
<v-list-item-subtitle>{{download.track.artistString}}</v-list-item-subtitle> <v-list-item-subtitle>{{download.track.artistString}}</v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
<v-liste-item-action>
<v-btn icon @click='deleteDownload(index)'>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-liste-item-action>
</v-list-item> </v-list-item>
</div> </div>
</v-list> </v-list>
@ -65,6 +75,11 @@ export default {
openDir() { openDir() {
const {ipcRenderer} = window.require('electron'); const {ipcRenderer} = window.require('electron');
ipcRenderer.send('openDownloadsDir'); ipcRenderer.send('openDownloadsDir');
},
//Remove download from queue
async deleteDownload(i) {
await this.$axios.delete(`/downloads/${i}`);
this.$root.getDownloads();
} }
} }
} }

View File

@ -57,6 +57,17 @@
hint='Variables: %title%, %artists%, %artist%, %feats%, %trackNumber%, %0trackNumber%, %album%' hint='Variables: %title%, %artists%, %artist%, %feats%, %trackNumber%, %0trackNumber%, %album%'
></v-text-field> ></v-text-field>
<!-- Log listening -->
<v-list-item>
<v-list-item-action>
<v-checkbox v-model='$root.settings.logListen'></v-checkbox>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>Log track listens to Deezer</v-list-item-title>
<v-list-item-subtitle>This allows listening history, flow and recommendations to work properly.</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<!-- Minimize to tray --> <!-- Minimize to tray -->
<v-list-item v-if='$root.settings.electron'> <v-list-item v-if='$root.settings.electron'>
<v-list-item-action> <v-list-item-action>

View File

@ -1,7 +1,7 @@
{ {
"name": "freezer", "name": "freezer",
"private": true, "private": true,
"version": "1.0.1", "version": "1.0.2",
"description": "", "description": "",
"main": "background.js", "main": "background.js",
"scripts": { "scripts": {

View File

@ -156,6 +156,27 @@ class Downloads {
fs.promises.mkdir(Settings.getTempDownloads(), {recursive: true}); fs.promises.mkdir(Settings.getTempDownloads(), {recursive: true});
} }
} }
//Remove download
async delete(index) {
//Clear all
if (index == -1) {
this.downloads = [];
await new Promise((res, rej) => {
this.db.remove({state: 0}, {}, (e) => {});
res();
})
return;
}
//Remove single
if (index >= this.downloads.length) return;
await new Promise((res, rej) => {
this.db.remove({_id: this.downloads[index].id}, {}, (e) => {});
res();
});
this.downloads.splice(index, 1);
}
} }
class Download { class Download {
@ -263,9 +284,11 @@ class Download {
} catch (e) {}; } catch (e) {};
//Decrypt //Decrypt
decryptor.decryptFile(decryptor.getKey(this.track.id), tmp, this.path); decryptor.decryptFile(decryptor.getKey(this.track.id), tmp, `${tmp}.DEC`);
fs.promises.copyFile(`${tmp}.DEC`, this.path);
//Delete encrypted //Delete encrypted
await fs.promises.unlink(tmp); await fs.promises.unlink(tmp);
await fs.promises.unlink(`${tmp}.DEC`);
//Tags //Tags
await this.tagAudio(this.path, this.track); await this.tagAudio(this.path, this.track);

View File

@ -274,7 +274,7 @@ app.get('/stream/:info', (req, res) => {
let dStart = start - (start % 2048); let dStart = start - (start % 2048);
//Make request to Deezer CDN //Make request to Deezer CDN
https.get(url, {headers: {'Range': `bytes=${dStart}-${end}`}}, (r) => { let _request = https.get(url, {headers: {'Range': `bytes=${dStart}-${end}`}}, (r) => {
//Error from Deezer //Error from Deezer
//TODO: Quality fallback //TODO: Quality fallback
if (r.statusCode < 200 || r.statusCode > 300) { if (r.statusCode < 200 || r.statusCode > 300) {
@ -311,6 +311,13 @@ app.get('/stream/:info', (req, res) => {
//Pipe: Deezer -> Decryptor -> Response //Pipe: Deezer -> Decryptor -> Response
decryptor.pipe(res); decryptor.pipe(res);
r.pipe(decryptor); r.pipe(decryptor);
});
//Internet/Request error
_request.on('error', (e) => {
//console.log('Streaming error: ' + e);
//HTML audio will restart automatically
res.destroy();
}); });
}); });
@ -400,6 +407,27 @@ app.get('/downloads', async (req, res) => {
}); });
}); });
//Delete singel download
app.delete('/downloads/:index', async (req, res) => {
let index = parseInt(req.params.index, 10);
await downloads.delete(index);
res.status(200).end();
});
//Log listen to deezer
app.put('/log/:id', async (req, res) => {
await deezer.callApi('log.listen', {
params: {
timestamp: Math.floor(new Date() / 1000),
ts_listen: Math.floor(new Date() / 1000),
type: 1,
stat: {seek: 0, pause: 0, sync: 0},
media: {id: req.params.id.toString(), type: 'song', format: 'MP3_128'}
}
});
res.status(200).end();
});
//Redirect to index on unknown path //Redirect to index on unknown path
app.all('*', (req, res) => { app.all('*', (req, res) => {
res.redirect('/'); res.redirect('/');

View File

@ -22,6 +22,8 @@ class Settings {
this.createAlbumFolder = true; this.createAlbumFolder = true;
this.createArtistFolder = true; this.createArtistFolder = true;
this.downloadFilename = '%0trackNumber%. %artists% - %title%'; this.downloadFilename = '%0trackNumber%. %artists% - %title%';
this.logListen = false;
} }
//Based on electorn app.getPath //Based on electorn app.getPath

View File

@ -1,7 +1,7 @@
{ {
"name": "freezer", "name": "freezer",
"private": true, "private": true,
"version": "1.0.0", "version": "1.0.2",
"description": "", "description": "",
"scripts": { "scripts": {
"pack": "electron-builder --dir", "pack": "electron-builder --dir",