Skip to content

Commit db279b6

Browse files
committed
Vue3 migration
1 parent 03f34c5 commit db279b6

File tree

4 files changed

+137
-45
lines changed

4 files changed

+137
-45
lines changed

package-lock.json

Lines changed: 93 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
"fast-xml-parser": "^3.19.0",
7373
"node-ssdp": "^4.0.1",
7474
"soap": "^0.40.0",
75-
"vue": "^2.6.14"
75+
"vue": "^3.2.2"
7676
},
7777
"devDependencies": {
7878
"@electron-forge/cli": "^6.0.0-beta.59",

src/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ <h2 v-if="currentMediaServer">
6060
<ol id="libraryObjects" v-if="libraryObjects">
6161
<li v-for="item in libraryObjects" @click="selectItem(item)"
6262
:class="{ playing: item['@_id'] === currentPlayingItem?.['@_id'] }">
63-
<div class="icon .standardized-emoji" v-if="!item['upnp:albumArtURI']">{{ item | toIcon }}</div>
64-
<img class="icon icon-size" v-if="item['upnp:albumArtURI']" :src="item['upnp:albumArtURI']['#text']" :alt="$options.filters.toIcon(item)"/>
63+
<div class="icon .standardized-emoji" v-if="!item['upnp:albumArtURI']">{{ toIcon(item) }}</div>
64+
<img class="icon icon-size" v-if="item['upnp:albumArtURI']" :src="item['upnp:albumArtURI']['#text']" :alt="toIcon(item)"/>
6565
<div>
6666
<div>{{ item['dc:title'] }}</div>
6767
<div class="font-italic font-xsmall" v-if="item['upnp:artist'] || item['upnp:album']">

src/index.js

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// Since we declared the script as type=module in the HTML file,
2-
// we can use ES Modules (adapted from the Vue 2 Introduction
3-
// https://vuejs.org/v2/guide/#Declarative-Rendering
2+
// we can use ES Modules
43

5-
// Alternatively, omit the .min from the path for Vue debugging purposes.
6-
import Vue from '../node_modules/vue/dist/vue.esm.browser.min.js';
4+
// Alternatively, omit the .prod from the path for Vue debugging purposes.
5+
import {createApp} from '../node_modules/vue/dist/vue.esm-browser.prod.js';
76

87
let api = window.muspnpapi;
98
dayjs.extend(dayjs_plugin_duration);
@@ -22,38 +21,42 @@ function toDuration(strDuration) {
2221
});
2322
}
2423

25-
window.app = new Vue({
26-
el: '#app',
27-
data: {
28-
showSpinner: true,
29-
error: null,
30-
refreshErrors: 0,
31-
libraryObjectsCache: null,
32-
selectedItem: [],
33-
playlist: null,
34-
currentPlayingItem: null,
35-
currentPositionInfo: null,
36-
currentMediaServer: '',
37-
currentMediaRenderer: '',
38-
availableMediaServers: null,
39-
availableMediaRenderers: null,
40-
refreshTimer: null,
41-
transportInfo: null,
42-
currentVolume: null,
43-
searchCapabilities: null,
44-
search: null,
45-
searchResults: null,
24+
window.app = createApp({
25+
data: function() {
26+
return {
27+
showSpinner: true,
28+
error: null,
29+
refreshErrors: 0,
30+
libraryObjectsCache: null,
31+
selectedItem: [],
32+
playlist: null,
33+
currentPlayingItem: null,
34+
currentPositionInfo: null,
35+
currentMediaServer: '',
36+
currentMediaRenderer: '',
37+
availableMediaServers: null,
38+
availableMediaRenderers: null,
39+
refreshTimer: null,
40+
transportInfo: null,
41+
currentVolume: null,
42+
searchCapabilities: null,
43+
search: null,
44+
searchResults: null,
45+
}
4646
},
4747
watch: {
4848
currentMediaServer: function (device) {
49+
this.showSpinner = true;
4950
this.libraryObjectsCache = null;
5051
this.selectedItem = [];
51-
this.showSpinner = true;
52+
this.searchCapabilities = null;
5253
api.selectServer({usn: device.usn})
5354
.then(() => this.browse({id: 0, start: 0, count: 0}))
54-
.then(() => api.getSearchCapabilities())
55+
.then(() => api.getSearchCapabilities().catch(() => null))
5556
.then((searchCapabilities) => {
56-
this.searchCapabilities = searchCapabilities.split(',').filter((prop) => ['dc:title','upnp:album','upnp:artist'].includes(prop))
57+
if (searchCapabilities) {
58+
this.searchCapabilities = searchCapabilities.split(',').filter((prop) => ['dc:title','upnp:album','upnp:artist'].includes(prop))
59+
}
5760
})
5861
.then(() => this.showSpinner = false)
5962
.catch(err => this.error = err);
@@ -82,6 +85,9 @@ window.app = new Vue({
8285
}
8386
},
8487
search: function (search) {
88+
if (! search) {
89+
return;
90+
}
8591
const searchStr = this.searchCapabilities.map(sc => `${sc} contains "${search}"`).join(' or ')
8692
this.searchResults = null;
8793
return api
@@ -148,6 +154,9 @@ window.app = new Vue({
148154
if (this._currentPosition_currentPosition == null || this._currentPosition_duration == null) {
149155
return 0;
150156
}
157+
if (this._currentPosition_duration.asSeconds() === 0) {
158+
return 0;
159+
}
151160
return Math.round(100 * this._currentPosition_currentPosition.asSeconds() / this._currentPosition_duration.asSeconds());
152161
},
153162
currentPositionRemaining: function () {
@@ -186,15 +195,15 @@ window.app = new Vue({
186195
// Update cache if cache miss or UpdateID changed
187196
if (res.UpdateID == null || this.libraryObjectsCache.data?.[id]?.UpdateID !== res.UpdateID) {
188197
// Also freeze res because we don't need reactivity on this potentially big structure
189-
this.$set(this.libraryObjectsCache.data, id, Object.freeze(res));
198+
this.libraryObjectsCache.data[id] = Object.freeze(res);
190199
}
191200
// Always keep track of effective cache use & remove old entries
192201
// This is suboptimal because we will fill the fifo with duplicates, but it should work well enough in most cases
193202
this.libraryObjectsCache.fifo.push(String(id));
194203
if (this.libraryObjectsCache.fifo.length > 20) {
195204
const removeId = this.libraryObjectsCache.fifo.shift();
196205
if (!this.libraryObjectsCache.fifo.includes(removeId)) {
197-
this.$delete(this.libraryObjectsCache.data, removeId);
206+
delete this.libraryObjectsCache.data[removeId]
198207
}
199208
}
200209
})
@@ -299,9 +308,7 @@ window.app = new Vue({
299308
const volumePercent = Math.round(x * e.target.max / e.target.offsetWidth);
300309
this.currentVolume = volumePercent;
301310
api.setVolume({desiredVolume: volumePercent});
302-
}
303-
},
304-
filters: {
311+
},
305312
toIcon: function (item) {
306313
if (item['upnp:class'].startsWith('object.container')) {
307314
return '📁';
@@ -318,5 +325,5 @@ window.app = new Vue({
318325
return '[]';
319326
}
320327
}
321-
})
328+
}).mount('#app')
322329

0 commit comments

Comments
 (0)