diff --git a/platypush/backend/http/static/css/source/common/elements/text.scss b/platypush/backend/http/static/css/source/common/elements/text.scss
index b9fb2d0c..e8bd0f73 100644
--- a/platypush/backend/http/static/css/source/common/elements/text.scss
+++ b/platypush/backend/http/static/css/source/common/elements/text.scss
@@ -8,6 +8,8 @@
}
input[type=text] {
+ border-radius: 5rem;
+
&:hover {
border: $border-hover;
}
diff --git a/platypush/backend/http/static/css/source/common/modal.scss b/platypush/backend/http/static/css/source/common/modal.scss
index da02356d..c9f5edd0 100644
--- a/platypush/backend/http/static/css/source/common/modal.scss
+++ b/platypush/backend/http/static/css/source/common/modal.scss
@@ -1,36 +1,40 @@
-.modal {
- display: none;
+.modal-container {
position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
- overflow: hidden;
- z-index: 999;
- background-color: rgba(10,10,10,0.85);
-}
+ z-index: var(--z-index);
+ background: rgba(10,10,10,0.9);
- .modal-container {
- margin: 5% auto auto auto;
- width: 70%;
- background: white;
- border-radius: 10px;
- }
+ .modal {
+ --width: auto;
+ --height: auto;
+ width: var(--width);
+ height: var(--height);
- .modal-header {
- border-bottom: 1px solid #ccc;
- margin: 0.5rem auto;
- padding: 0.5rem;
+ div:first-child { border-radius: 1rem 1rem 0 0; }
+ div:last-child { border-radius: 0 0 1rem 1rem; }
+
+ .header {
+ border-bottom: $modal-header-border;
+ padding: .5rem;
text-align: center;
- background-color: $modal-bg;
- border-radius: 10px 10px 0 0;
+ background: $modal-header-bg;
text-transform: uppercase;
letter-spacing: .1rem;
- line-height: 38px;
+ line-height: 3.8rem;
}
- .modal-body {
+ .body {
+ max-height: 75vh;
+ overflow: auto;
padding: 2.5rem 2rem 1.5rem 2rem;
+ background: $modal-body-bg;
}
-
+ }
+}
diff --git a/platypush/backend/http/static/css/source/common/vars.scss b/platypush/backend/http/static/css/source/common/vars.scss
index 76c0cdc6..7f6a1b3d 100644
--- a/platypush/backend/http/static/css/source/common/vars.scss
+++ b/platypush/backend/http/static/css/source/common/vars.scss
@@ -23,8 +23,6 @@ $nav-bg: #e8e8e8 !default;
$nav-fg: $default-link-fg;
$nav-date-time-shadow: 2px 2px 2px #ccc !default;
-$modal-bg: #f0f0f0 !default;
-
//// Animations defaults
$transition-duration: .5s !default;
$fade-transition-duration: .5s !default;
@@ -88,5 +86,10 @@ $header-bottom: $default-bottom;
//// Dropdown element
$dropdown-bg: rgba(241,243,242,0.9) !default;
-$dropdown-shadow: 1px 1px 1px #bbb;
+$dropdown-shadow: 1px 1px 1px #bbb !default;
+
+//// Modal element
+$modal-header-bg: #f0f0f0 !default;
+$modal-header-border: 1px solid #ccc !default;
+$modal-body-bg: white !default;
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/index.scss b/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/index.scss
index b2457971..b7e5e25d 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/index.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/index.scss
@@ -49,96 +49,97 @@
}
}
+ .spacer {
+ height: 5rem;
+ }
+
.panels {
display: flex;
+ }
- .spacer {
+ .browser, .playlist {
+ overflow: auto;
+ }
+
+ .browser {
+ background: $browser-panel-bg;
+ border-right: $default-border-2;
+ padding: .3rem 1rem 6rem 1rem;
+ font-size: $browser-font-size;
+
+ .item {
+ background: none;
+ }
+
+ .fa {
+ color: #666;
+ }
+ }
+
+ .browser,
+ .search,
+ .playlist {
+ position: relative; // For the dropdown menu
+ padding: .5rem 1rem 6rem 1rem;
+
+ .browser-controls,
+ .results-controls,
+ .playlist-controls {
+ position: fixed;
height: 5rem;
- }
+ background: $playlist-controls-bg;
+ border-bottom: $playlist-controls-border;
+ margin: -.5rem 0 0 -1rem;
+ padding: .5rem;
- .browser, .playlist {
- overflow: auto;
- }
-
- .browser {
- background: $browser-panel-bg;
- border-right: $default-border-2;
- padding: .3rem 1rem 6rem 1rem;
- font-size: $browser-font-size;
-
- .item {
- background: none;
+ input[type=text] {
+ width: 100%;
}
- .fa {
- color: #666;
+ * > button {
+ border: 0;
+ padding: 0 1.5rem;
+
+ &:disabled {
+ background: none;
+ }
+
+ &.enabled {
+ color: $button-enabled-color;
+ }
+
+ .fa-search {
+ color: $button-hover-color;
+ }
+ }
+
+ button {
+ padding: 0 .75rem;
+
}
}
- .browser,
- .playlist {
- position: relative; // For the dropdown menu
- padding: .5rem 1rem 6rem 1rem;
+ .empty {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ font-size: 5rem;
+ color: $empty-playlist-color;
+ text-shadow: $empty-playlist-shadow;
+ }
- .browser-controls,
- .playlist-controls {
- position: fixed;
- height: 5rem;
- background: $playlist-controls-bg;
- border-bottom: $playlist-controls-border;
- margin: -.5rem 0 0 -1rem;
- padding: .5rem;
-
- input[type=text] {
- width: 100%;
- border-radius: 5rem;
- }
-
- * > button {
- border: 0;
- padding: 0 1.5rem;
-
- &:disabled {
- background: none;
- }
-
- &.enabled {
- color: $button-enabled-color;
- }
-
- .fa-search {
- color: $button-hover-color;
- }
- }
-
- button {
- padding: 0 .75rem;
-
- }
+ .item {
+ &.active {
+ height: 4rem;
+ @include animation(active-track 5s infinite);
}
- .empty {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
- font-size: 5rem;
- color: $empty-playlist-color;
- text-shadow: $empty-playlist-shadow;
- }
-
- .item {
- &.active {
- height: 4rem;
- @include animation(active-track 5s infinite);
- }
-
- &.move:hover {
- background: $move-mode-track-bg !important;
- border-top: $move-mode-track-border;
- border-bottom: $move-mode-track-border;
- cursor: move;
- }
+ &.move:hover {
+ background: $move-mode-track-bg !important;
+ border-top: $move-mode-track-border;
+ border-bottom: $move-mode-track-border;
+ cursor: move;
}
}
}
@@ -237,12 +238,114 @@
margin-left: 1.5rem;
}
}
+
+ .search {
+ --width: 90vw;
+ position: relative;
+ padding: 0;
+
+ form {
+ margin-bottom: 0;
+
+ .row {
+ padding: .5rem;
+ }
+
+ .footer {
+ padding-top: 1.5rem;
+ margin-top: 1.5rem;
+ border-top: $search-modal-footer-border;
+
+ .left {
+ display: flex;
+ justify-content: left;
+ }
+ }
+
+ button, input[type=submit] {
+ border-radius: 5rem;
+ }
+ }
+
+ .dropdown {
+ z-index: 503;
+ }
+
+ .results-controls {
+ position: fixed;
+ padding: 0;
+ margin: -2.45rem auto 0 -2rem;
+ border-bottom: $default-border-2;
+ width: var(--width);
+ height: 3em;
+ display: flex;
+ align-items: center;
+ z-index: 502;
+ }
+
+ .results {
+ padding-top: 2.7rem;
+ }
+
+ form, .results {
+ position: relative;
+ }
+ }
}
.dropdown {
width: 20rem;
}
+#music-mpd-info {
+ .modal {
+ .body {
+ .row {
+ margin: .5rem;
+ padding: .5rem;
+ border-bottom: $info-modal-row-border;
+
+ &:hover {
+ border-radius: 1rem;
+ background: $hover-bg;
+ }
+
+ .attr {
+ color: $info-modal-attr-color;
+ }
+
+ .value {
+ text-align: right;
+ }
+ }
+ }
+ }
+}
+
+@media #{map-get($widths, 's')} {
+ #music-mpd-info {
+ .modal {
+ width: 80vw;
+ }
+ }
+}
+
+@media #{map-get($widths, 'm')} {
+ #music-mpd-info {
+ .modal {
+ width: 70vw;
+ }
+ }
+}
+
+@media #{map-get($widths, 'l')} {
+ #music-mpd-info {
+ .modal {
+ width: 45vw;
+ }
+ }
+}
+
@keyframes active-track {
0% { background: $active-track-bg-1; }
50% { background: $active-track-bg-2; }
@@ -260,3 +363,4 @@
50% { background: $active-track-bg-2; }
100% { background: $active-track-bg-1; }
}
+
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/vars.scss b/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/vars.scss
index 2ce8bdb4..ea7803d9 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/vars.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/music.mpd/vars.scss
@@ -26,3 +26,8 @@ $active-track-bg-2: #9cdfb0;
$move-mode-track-border: 3px dotted rgb(216,156,136);
$move-mode-track-bg: rgba(216,156,136,0.3);
+$search-modal-footer-border: 1px solid #ccc;
+
+$info-modal-row-border: 1px solid #ddd;
+$info-modal-attr-color: #777;
+
diff --git a/platypush/backend/http/static/js/elements/common.js b/platypush/backend/http/static/js/elements/common.js
new file mode 100644
index 00000000..48b0505a
--- /dev/null
+++ b/platypush/backend/http/static/js/elements/common.js
@@ -0,0 +1,15 @@
+var parseElement = function(element) {
+ if (element instanceof Object) {
+ if (element.$el) {
+ element = element.$el;
+ }
+ } else if (element instanceof String || typeof(element) === 'string') {
+ element = document.getElementById(element);
+ } else {
+ console.error('Got unexpected type ' + typeof(element) + ' for DOM element');
+ return;
+ }
+
+ return element;
+};
+
diff --git a/platypush/backend/http/static/js/elements/dropdown.js b/platypush/backend/http/static/js/elements/dropdown.js
index eb8f7f90..0f652460 100644
--- a/platypush/backend/http/static/js/elements/dropdown.js
+++ b/platypush/backend/http/static/js/elements/dropdown.js
@@ -29,21 +29,6 @@ Vue.component('dropdown', {
var openedDropdown;
-var _parseElement = function(element) {
- if (element instanceof Object) {
- if (element.$el) {
- element = element.$el;
- }
- } else if (element instanceof String || typeof(element) === 'string') {
- element = document.getElementById(element);
- } else {
- console.error('Got unexpected type ' + typeof(element) + ' for dropdown element');
- return;
- }
-
- return element;
-};
-
var clickHndl = function(event) {
if (!openedDropdown) {
return;
@@ -53,7 +38,7 @@ var clickHndl = function(event) {
while (element) {
if (element == openedDropdown) {
- return; // TODO dropdown click
+ return;
}
element = element.parentElement;
@@ -78,7 +63,7 @@ function closeDropdown() {
}
function openDropdown(element) {
- element = _parseElement(element);
+ element = parseElement(element);
if (!element) {
console.error('Invalid dropdown element');
return;
diff --git a/platypush/backend/http/static/js/elements/modal.js b/platypush/backend/http/static/js/elements/modal.js
new file mode 100644
index 00000000..6d600782
--- /dev/null
+++ b/platypush/backend/http/static/js/elements/modal.js
@@ -0,0 +1,84 @@
+Vue.component('modal', {
+ template: '#tmpl-modal',
+ props: {
+ id: {
+ type: String,
+ },
+
+ title: {
+ type: String,
+ },
+
+ width: {
+ type: [Number, String],
+ },
+
+ height: {
+ type: [Number, String],
+ },
+
+ // Modal visibility value
+ value: {
+ type: Boolean,
+ default: false,
+ },
+
+ timeout: {
+ type: [Number, String],
+ },
+
+ level: {
+ type: Number,
+ default: 1,
+ },
+ },
+
+ data: function() {
+ return {
+ timeoutId: undefined,
+ prevValue: this.value,
+ };
+ },
+
+ computed: {
+ zIndex: function() {
+ return 500 + this.level;
+ },
+ },
+
+ methods: {
+ modalClicked: function(event) {
+ // Close any opened dropdowns before stopping the click propagation
+ const dropdowns = this.$el.querySelectorAll('.dropdown:not(.hidden)');
+ for (const dropdown of dropdowns) {
+ closeDropdown(dropdown);
+ }
+
+ event.stopPropagation();
+ },
+
+ modalClose: function() {
+ event.stopPropagation();
+ this.$emit('input', false);
+ },
+ },
+
+ updated: function() {
+ if (this.value != this.prevValue) {
+ this.$emit((this.value ? 'open' : 'close'), this);
+ this.prevValue = this.value;
+ }
+
+ if (this.value && this.timeout && !this.timeoutId) {
+ var handler = (self) => {
+ return () => {
+ self.modalClose();
+ self.timeoutId = undefined;
+ };
+ };
+
+ this.timeoutId = setTimeout(handler(this), 0+this.timeout);
+ }
+ },
+});
+
diff --git a/platypush/backend/http/static/js/plugins/music.mpd/index.js b/platypush/backend/http/static/js/plugins/music.mpd/index.js
index 8cce55b8..c3068728 100644
--- a/platypush/backend/http/static/js/plugins/music.mpd/index.js
+++ b/platypush/backend/http/static/js/plugins/music.mpd/index.js
@@ -1,6 +1,7 @@
Vue.component('music-mpd', {
template: '#tmpl-music-mpd',
props: ['config'],
+ mixins: [utils],
data: function() {
return {
track: {},
@@ -22,6 +23,11 @@ Vue.component('music-mpd', {
editor: false,
},
+ infoItem: {},
+ modalVisible: {
+ info: false,
+ },
+
selectedPlaylistItems: {},
selectedBrowserItems: {},
@@ -78,6 +84,10 @@ Vue.component('music-mpd', {
items.push({
text: 'View track info',
icon: 'info',
+ click: async function() {
+ self.infoItem = Object.values(self.selectedPlaylistItems)[0];
+ self.modalVisible.info = true;
+ },
});
}
@@ -103,7 +113,7 @@ Vue.component('music-mpd', {
if (Object.keys(this.selectedBrowserItems).length === 1) {
items.push(
{
- text: 'Add and play',
+ text: 'Play',
icon: 'play',
click: async function() {
const item = Object.values(self.selectedBrowserItems)[0];
@@ -340,28 +350,6 @@ Vue.component('music-mpd', {
}
},
- convertTime: function(time) {
- time = parseFloat(time); // Normalize strings
- var t = {};
- t.h = '' + parseInt(time/3600);
- t.m = '' + parseInt(time/60 - t.h*60);
- t.s = '' + parseInt(time - t.m*60);
-
- for (var attr of ['m','s']) {
- if (parseInt(t[attr]) < 10) {
- t[attr] = '0' + t[attr];
- }
- }
-
- var ret = [];
- if (parseInt(t.h)) {
- ret.push(t.h);
- }
-
- ret.push(t.m, t.s);
- return ret.join(':');
- },
-
previous: async function() {
await request('music.mpd.previous');
let track = await request('music.mpd.currentsong');
@@ -697,18 +685,16 @@ Vue.component('music-mpd', {
if (this.playlistFilter.length === 0)
return true;
- return [track.artist || '', track.title || '', track.album || '']
- .join(' ').toLocaleLowerCase().indexOf(
- this.playlistFilter.split(' ').filter(_ => _.length > 0).map(_ => _.toLocaleLowerCase()).join(' ')
- ) >= 0;
+ const filter = this.playlistFilter.split(' ').filter(_ => _.length > 0).map(_ => _.toLocaleLowerCase()).join(' ');
+ return [track.artist || '', track.title || '', track.album || ''].join(' ').toLocaleLowerCase().indexOf() >= 0;
},
matchesBrowserFilter: function(item) {
if (this.browserFilter.length === 0)
return true;
- return item.name.toLocaleLowerCase().indexOf(
- this.browserFilter.toLocaleLowerCase().split(' ').filter(_ => _.length > 0).join(' ')) >= 0;
+ const filter = this.browserFilter.toLocaleLowerCase().split(' ').filter(_ => _.length > 0).join(' ');
+ return item.name.toLocaleLowerCase().indexOf(filter) >= 0;
},
onPlaylistItemClick: async function(track) {
diff --git a/platypush/backend/http/static/js/plugins/music.mpd/playlist.js b/platypush/backend/http/static/js/plugins/music.mpd/playlist.js
index 463381b4..99a0eca7 100644
--- a/platypush/backend/http/static/js/plugins/music.mpd/playlist.js
+++ b/platypush/backend/http/static/js/plugins/music.mpd/playlist.js
@@ -1,5 +1,6 @@
Vue.component('music-mpd-playlist-item', {
template: '#tmpl-music-mpd-playlist-item',
+ mixins: [utils],
props: {
track: {
type: Object,
diff --git a/platypush/backend/http/static/js/plugins/music.mpd/search.js b/platypush/backend/http/static/js/plugins/music.mpd/search.js
new file mode 100644
index 00000000..c9abb07d
--- /dev/null
+++ b/platypush/backend/http/static/js/plugins/music.mpd/search.js
@@ -0,0 +1,161 @@
+Vue.component('music-mpd-search', {
+ template: '#tmpl-music-mpd-search',
+ props: ['mpd'],
+ data: function() {
+ return {
+ visible: false,
+ showResults: false,
+ results: false,
+ filter: '',
+ selectionMode: false,
+ selectedItems: {},
+
+ query: {
+ any: '',
+ 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.keys(this.selectedItems).length === 1) {
+ items.push({
+ text: 'View info',
+ icon: 'info',
+ });
+ }
+
+ return items;
+ },
+ },
+
+ methods: {
+ search: async function() {
+ const filter = Object.keys(this.query).reduce((items, key) => {
+ if (this.query[key].length) {
+ items.push(key, this.query[key]);
+ }
+
+ return items;
+ }, []);
+
+ var results = await request('music.mpd.search', {filter: filter});
+ this.results = results.sort((a,b) => {
+ const tokenize = (t) => {
+ return ''.concat(t.artist || '', '-', t.album || '', '-', t.disc || '', '-', t.track || '', t.title || '').toLocaleLowerCase();
+ };
+
+ return tokenize(a).localeCompare(tokenize(b));
+ });
+
+ 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.id] = item;
+ }
+
+ openDropdown(this.$refs.dropdown.$el);
+ },
+ },
+});
+
+Vue.component('music-mpd-search-item', {
+ template: '#tmpl-music-mpd-search-item',
+ mixins: [utils],
+ props: {
+ item: {
+ type: Object,
+ default: {},
+ },
+
+ selected: {
+ type: Boolean,
+ default: false,
+ },
+ },
+});
+
diff --git a/platypush/backend/http/static/js/plugins/music.mpd/utils.js b/platypush/backend/http/static/js/plugins/music.mpd/utils.js
new file mode 100644
index 00000000..6fc0c496
--- /dev/null
+++ b/platypush/backend/http/static/js/plugins/music.mpd/utils.js
@@ -0,0 +1,26 @@
+var utils = {
+ methods: {
+ convertTime: function(time) {
+ time = parseFloat(time); // Normalize strings
+ var t = {};
+ t.h = '' + parseInt(time/3600);
+ t.m = '' + parseInt(time/60 - t.h*60);
+ t.s = '' + parseInt(time - t.m*60);
+
+ for (var attr of ['m','s']) {
+ if (parseInt(t[attr]) < 10) {
+ t[attr] = '0' + t[attr];
+ }
+ }
+
+ var ret = [];
+ if (parseInt(t.h)) {
+ ret.push(t.h);
+ }
+
+ ret.push(t.m, t.s);
+ return ret.join(':');
+ },
+ },
+};
+
diff --git a/platypush/backend/http/templates/elements.html b/platypush/backend/http/templates/elements.html
index 08658df8..a9a6dc3d 100644
--- a/platypush/backend/http/templates/elements.html
+++ b/platypush/backend/http/templates/elements.html
@@ -1,4 +1,6 @@
+{% include 'elements/common.html' %}
{% include 'elements/switch.html' %}
{% include 'elements/range-slider.html' %}
{% include 'elements/dropdown.html' %}
+{% include 'elements/modal.html' %}
diff --git a/platypush/backend/http/templates/elements/common.html b/platypush/backend/http/templates/elements/common.html
new file mode 100644
index 00000000..23ee1261
--- /dev/null
+++ b/platypush/backend/http/templates/elements/common.html
@@ -0,0 +1,2 @@
+
+
diff --git a/platypush/backend/http/templates/elements/modal.html b/platypush/backend/http/templates/elements/modal.html
new file mode 100644
index 00000000..299d2851
--- /dev/null
+++ b/platypush/backend/http/templates/elements/modal.html
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/platypush/backend/http/templates/plugins/music.mpd/index.html b/platypush/backend/http/templates/plugins/music.mpd/index.html
index 36b30fd0..fd735ebf 100644
--- a/platypush/backend/http/templates/plugins/music.mpd/index.html
+++ b/platypush/backend/http/templates/plugins/music.mpd/index.html
@@ -1,8 +1,52 @@
+
+
{% include 'plugins/music.mpd/browser.html' %}
{% include 'plugins/music.mpd/playlist.html' %}
+{% include 'plugins/music.mpd/search.html' %}
diff --git a/platypush/backend/http/templates/plugins/music.mpd/search.html b/platypush/backend/http/templates/plugins/music.mpd/search.html
new file mode 100644
index 00000000..3cb06128
--- /dev/null
+++ b/platypush/backend/http/templates/plugins/music.mpd/search.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+