230 lines
7.4 KiB
JavaScript
230 lines
7.4 KiB
JavaScript
Vue.component('music-mpd-search', {
|
|
template: '#tmpl-music-mpd-search',
|
|
props: ['mpd'],
|
|
data: function() {
|
|
return {
|
|
visible: false,
|
|
showResults: false,
|
|
results: [],
|
|
filter: '',
|
|
selectionMode: false,
|
|
selectedItems: {},
|
|
|
|
query: {
|
|
any: '',
|
|
file: '',
|
|
artist: '',
|
|
title: '',
|
|
album: '',
|
|
},
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
dropdownItems: function() {
|
|
var self = this;
|
|
var items = [];
|
|
|
|
if (Object.keys(this.selectedItems).length === 1) {
|
|
items.push(
|
|
{
|
|
text: 'Play',
|
|
icon: 'play',
|
|
click: async function() {
|
|
const item = Object.values(self.selectedItems)[0];
|
|
await self.mpd.add(item.file, position=0);
|
|
await self.mpd.playpos(0);
|
|
self.selectedItems = {};
|
|
},
|
|
},
|
|
{
|
|
text: 'Replace and play',
|
|
icon: 'play',
|
|
click: async function() {
|
|
await self.mpd.clear();
|
|
|
|
const item = Object.values(self.selectedItems)[0];
|
|
await self.mpd.add(item.file, position=0);
|
|
await self.mpd.playpos(0);
|
|
self.selectedItems = {};
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
items.push(
|
|
{
|
|
text: 'Add to queue',
|
|
icon: 'plus',
|
|
click: async function() {
|
|
const items = Object.values(self.selectedItems);
|
|
const promises = items.map(item => self.mpd.add(item.file));
|
|
|
|
await Promise.all(promises);
|
|
self.selectedItems = {};
|
|
},
|
|
},
|
|
);
|
|
|
|
if (Object.values(this.selectedItems).filter(_ => _.time != null).length === Object.values(this.selectedItems).length) {
|
|
items.push(
|
|
{
|
|
text: 'Add to playlist',
|
|
icon: 'list',
|
|
click: async function() {
|
|
self.mpd.addToPlaylistItems = Object.values(self.selectedItems).map(_ => _.file);
|
|
self.mpd.modalVisible.playlistAdd = true;
|
|
await self.mpd.listplaylists();
|
|
self.selectedItems = {};
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
if (Object.keys(this.selectedItems).length === 1) {
|
|
const item = Object.values(this.selectedItems)[0];
|
|
|
|
if (item.artist && item.artist.length) {
|
|
items.push({
|
|
text: 'View artist',
|
|
icon: 'user',
|
|
click: async function() {
|
|
await self.mpd.searchArtist(item);
|
|
self.selectedItems = {};
|
|
}
|
|
});
|
|
}
|
|
|
|
if (item.album && item.album.length) {
|
|
items.push({
|
|
text: 'View album',
|
|
icon: 'compact-disc',
|
|
click: async function() {
|
|
await self.mpd.searchAlbum(item);
|
|
self.selectedItems = {};
|
|
},
|
|
});
|
|
}
|
|
|
|
items.push({
|
|
text: 'View info',
|
|
icon: 'info',
|
|
click: function() {
|
|
self.$emit('info', item);
|
|
},
|
|
});
|
|
}
|
|
|
|
return items;
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
search: async function() {
|
|
const filter = Object.keys(this.query).reduce((query, key) => {
|
|
if (this.query[key].length) {
|
|
query[key] = this.query[key];
|
|
}
|
|
|
|
return query;
|
|
}, {});
|
|
|
|
this.results = [];
|
|
var results = await request('music.mpd.search', {filter: filter});
|
|
|
|
this.results = results.sort((a,b) => {
|
|
if (a.artist != b.artist)
|
|
return (a.artist || '').localeCompare(b.artist || '');
|
|
if (a.album != b.album)
|
|
return (a.album || '').localeCompare(b.album || '');
|
|
if (a.track != b.track)
|
|
return parseInt(a.track || 0) > parseInt(b.track || 0);
|
|
if (a.title != b.title)
|
|
return (a.title || '').localeCompare(b.title || '');
|
|
if (a.file != b.file)
|
|
return (a.file || '').localeCompare(b.file || '');
|
|
return 0;
|
|
});
|
|
|
|
this.showResults = true;
|
|
},
|
|
|
|
matchesFilter: function(item) {
|
|
if (this.filter.length === 0)
|
|
return true;
|
|
|
|
const filter = this.filter.split(' ').filter(_ => _.length > 0).map(_ => _.toLocaleLowerCase()).join(' ');
|
|
return [item.file || '', item.artist || '', item.title || '', item.album || ''].join(' ').toLocaleLowerCase().indexOf(filter) >= 0;
|
|
},
|
|
|
|
onItemClick: function(item) {
|
|
if (this.selectionMode) {
|
|
if (item.file in this.selectedItems) {
|
|
Vue.delete(this.selectedItems, item.file);
|
|
} else {
|
|
Vue.set(this.selectedItems, item.file, item);
|
|
}
|
|
} else if (item.file in this.selectedItems) {
|
|
Vue.delete(this.selectedItems, item.file);
|
|
} else {
|
|
this.selectedItems = {};
|
|
Vue.set(this.selectedItems, item.file, item);
|
|
openDropdown(this.$refs.dropdown.$el);
|
|
}
|
|
},
|
|
|
|
toggleSelectionMode: function() {
|
|
if (this.selectionMode && Object.keys(this.selectedItems).length) {
|
|
openDropdown(this.$refs.dropdown.$el);
|
|
}
|
|
|
|
this.selectionMode = !this.selectionMode;
|
|
},
|
|
|
|
selectAll: function() {
|
|
this.selectedItems = {};
|
|
this.selectionMode = true;
|
|
|
|
for (var item of this.results) {
|
|
this.selectedItems[item.file] = item;
|
|
}
|
|
|
|
openDropdown(this.$refs.dropdown.$el);
|
|
},
|
|
|
|
resetQuery: function() {
|
|
this.filter = '';
|
|
for (const attr of Object.keys(this.query)) {
|
|
this.query[attr] = '';
|
|
}
|
|
},
|
|
|
|
resetForm: function() {
|
|
this.resetQuery();
|
|
this.showResults = false;
|
|
var self = this;
|
|
|
|
setTimeout(() => {
|
|
self.$refs.form.querySelector('input[type=text]:first-child').focus()
|
|
}, 100)
|
|
},
|
|
},
|
|
});
|
|
|
|
Vue.component('music-mpd-search-item', {
|
|
template: '#tmpl-music-mpd-search-item',
|
|
mixins: [utils],
|
|
props: {
|
|
item: {
|
|
type: Object,
|
|
default: {},
|
|
},
|
|
|
|
selected: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
});
|
|
|