Added playlist editor in music.mpd web panel
This commit is contained in:
parent
1ad72a2695
commit
b7a625097d
6 changed files with 464 additions and 37 deletions
|
@ -76,6 +76,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
%ctrl-button {
|
||||
border: 0;
|
||||
padding: 0 1.5rem;
|
||||
|
||||
&:disabled {
|
||||
background: none;
|
||||
}
|
||||
|
||||
&.enabled {
|
||||
color: $button-enabled-color;
|
||||
}
|
||||
|
||||
.fa-search {
|
||||
color: $button-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
%move {
|
||||
background: $move-mode-track-bg !important;
|
||||
border-top: $move-mode-track-border;
|
||||
border-bottom: $move-mode-track-border;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.browser,
|
||||
.search,
|
||||
.playlist {
|
||||
|
@ -97,25 +121,11 @@
|
|||
}
|
||||
|
||||
* > button {
|
||||
border: 0;
|
||||
padding: 0 1.5rem;
|
||||
|
||||
&:disabled {
|
||||
background: none;
|
||||
}
|
||||
|
||||
&.enabled {
|
||||
color: $button-enabled-color;
|
||||
}
|
||||
|
||||
.fa-search {
|
||||
color: $button-hover-color;
|
||||
}
|
||||
@extend %ctrl-button;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0 .75rem;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,15 +152,14 @@
|
|||
}
|
||||
|
||||
&.move:hover {
|
||||
background: $move-mode-track-bg !important;
|
||||
border-top: $move-mode-track-border;
|
||||
border-bottom: $move-mode-track-border;
|
||||
cursor: move;
|
||||
@extend %move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.playlist-add {
|
||||
.playlist-add,
|
||||
.editor {
|
||||
.editor-controls,
|
||||
.playlist-add-controls {
|
||||
background: $playlist-controls-bg;
|
||||
border-bottom: $playlist-controls-border;
|
||||
|
@ -160,12 +169,35 @@
|
|||
padding: .5rem;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
@extend %ctrl-button;
|
||||
padding: 0 .75rem;
|
||||
}
|
||||
|
||||
.editor-container,
|
||||
.playlists-container {
|
||||
max-height: 70vh;
|
||||
overflow: auto;
|
||||
margin: 0 -2rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.playlists-container {
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
max-height: 65vh;
|
||||
|
||||
.item {
|
||||
&.move:hover {
|
||||
@extend %move;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
|
@ -355,7 +387,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
#music-mpd-search-modal {
|
||||
#music-mpd-search-modal,
|
||||
#music-mpd-playlist-edit {
|
||||
.dropdown {
|
||||
z-index: 503;
|
||||
}
|
||||
|
@ -367,6 +400,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
#music-mpd-playlist-edit {
|
||||
.modal {
|
||||
min-width: 80rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media #{map-get($widths, 's')} {
|
||||
#music-mpd-info {
|
||||
.modal {
|
||||
|
|
|
@ -12,12 +12,14 @@ Vue.component('music-mpd', {
|
|||
playlistFilter: '',
|
||||
browserFilter: '',
|
||||
playlistAddFilter: '',
|
||||
editorFilter: '',
|
||||
browserPath: [],
|
||||
browserItems: [],
|
||||
|
||||
selectionMode: {
|
||||
playlist: false,
|
||||
browser: false,
|
||||
editor: false,
|
||||
},
|
||||
|
||||
moveMode: {
|
||||
|
@ -28,12 +30,15 @@ Vue.component('music-mpd', {
|
|||
infoItem: {},
|
||||
modalVisible: {
|
||||
info: false,
|
||||
editor: false,
|
||||
playlistAdd: false,
|
||||
},
|
||||
|
||||
addToPlaylistItems: [],
|
||||
selectedPlaylist: {},
|
||||
selectedPlaylistItems: {},
|
||||
selectedPlaylistAddItems: {},
|
||||
selectedEditorItems: {},
|
||||
selectedBrowserItems: {},
|
||||
|
||||
syncTime: {
|
||||
|
@ -213,7 +218,7 @@ Vue.component('music-mpd', {
|
|||
icon: 'user',
|
||||
click: async function() {
|
||||
await self.searchArtist(item);
|
||||
self.selectedPlaylistItems = {};
|
||||
self.selectedBrowserItems = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -224,7 +229,7 @@ Vue.component('music-mpd', {
|
|||
icon: 'compact-disc',
|
||||
click: async function() {
|
||||
await self.searchAlbum(item);
|
||||
self.selectedPlaylistItems = {};
|
||||
self.selectedBrowserItems = {};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -264,6 +269,13 @@ Vue.component('music-mpd', {
|
|||
items.push({
|
||||
text: 'Edit',
|
||||
icon: 'pen',
|
||||
click: async function() {
|
||||
const item = Object.values(self.selectedBrowserItems)[0];
|
||||
self.selectedPlaylist.name = item.name;
|
||||
await self.refreshSelectedPlaylist();
|
||||
self.modalVisible.editor = true;
|
||||
self.selectedBrowserItems = {};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -297,6 +309,124 @@ Vue.component('music-mpd', {
|
|||
|
||||
return items;
|
||||
},
|
||||
|
||||
editorDropdownItems: function() {
|
||||
var self = this;
|
||||
var items = [];
|
||||
|
||||
if (Object.keys(this.selectedEditorItems).length === 1) {
|
||||
const item = Object.values(this.selectedEditorItems)[0];
|
||||
|
||||
items.push(
|
||||
{
|
||||
text: 'Play',
|
||||
icon: 'play',
|
||||
click: async function() {
|
||||
await self.add(item.file, position=0);
|
||||
await self.playpos(0);
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Replace and play',
|
||||
icon: 'play',
|
||||
click: async function() {
|
||||
await self.clear();
|
||||
await self.add(item.file, position=0);
|
||||
await self.playpos(0);
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (item.artist && item.artist.length) {
|
||||
items.push({
|
||||
text: 'View artist',
|
||||
icon: 'user',
|
||||
click: async function() {
|
||||
await self.searchArtist(item);
|
||||
self.selectedEditorItems = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (item.album && item.album.length) {
|
||||
items.push({
|
||||
text: 'View album',
|
||||
icon: 'compact-disc',
|
||||
click: async function() {
|
||||
await self.searchAlbum(item);
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.push(
|
||||
{
|
||||
text: 'Add to queue',
|
||||
icon: 'plus',
|
||||
click: async function() {
|
||||
const items = Object.values(self.selectedEditorItems);
|
||||
const promises = items.map(item => self.add(item.file));
|
||||
|
||||
await Promise.all(promises);
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Add to playlist',
|
||||
icon: 'list',
|
||||
click: async function() {
|
||||
self.addToPlaylistItems = Object.keys(self.selectedEditorItems);
|
||||
self.modalVisible.playlistAdd = true;
|
||||
await self.listplaylists();
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (Object.keys(this.selectedEditorItems).length < this.selectedPlaylist.items.length) {
|
||||
items.push({
|
||||
text: 'Move',
|
||||
icon: 'retweet',
|
||||
click: function() {
|
||||
self.moveMode.editor = true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
items.push(
|
||||
{
|
||||
text: 'Remove',
|
||||
icon: 'trash',
|
||||
click: async function() {
|
||||
if (!confirm('Are you sure you want to remove the selected track' +
|
||||
(Object.values(self.selectedEditorItems).length > 1 ? 's' : '') + ' from the playlist?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const items = Object.values(self.selectedEditorItems);
|
||||
await self.playlistdelete(items.map(_ => _.pos));
|
||||
self.selectedEditorItems = {};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (Object.keys(this.selectedEditorItems).length === 1) {
|
||||
const item = Object.values(self.selectedEditorItems)[0];
|
||||
|
||||
items.push({
|
||||
text: 'View info',
|
||||
icon: 'info',
|
||||
click: async function() {
|
||||
await self.info(item.file);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -594,6 +724,14 @@ Vue.component('music-mpd', {
|
|||
}
|
||||
},
|
||||
|
||||
playlistmove: async function(fromPos, toPos) {
|
||||
if (!this.selectedPlaylist.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
await request('music.mpd.playlistmove', {name: this.selectedPlaylist.name, from_pos: fromPos, to_pos: toPos});
|
||||
},
|
||||
|
||||
swap: async function() {
|
||||
if (Object.keys(this.selectedPlaylistItems).length !== 2) {
|
||||
return;
|
||||
|
@ -669,6 +807,14 @@ Vue.component('music-mpd', {
|
|||
}
|
||||
},
|
||||
|
||||
listplaylist: async function(name) {
|
||||
return await request('music.mpd.listplaylist', {name: name});
|
||||
},
|
||||
|
||||
listplaylistinfo: async function(name) {
|
||||
return await request('music.mpd.listplaylistinfo', {name: name});
|
||||
},
|
||||
|
||||
playlistadd: async function(items=[], playlists=[]) {
|
||||
if (!playlists.length) {
|
||||
if (this.modalVisible.playlistAdd) {
|
||||
|
@ -696,6 +842,50 @@ Vue.component('music-mpd', {
|
|||
this.addToPlaylistItems = [];
|
||||
},
|
||||
|
||||
playlistdelete: async function(items=[]) {
|
||||
if (!items.length) {
|
||||
items = Object.keys(this.selectedEditorItems);
|
||||
}
|
||||
|
||||
if (!items.length || !this.selectedPlaylist.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
await request('music.mpd.playlistdelete', {name: this.selectedPlaylist.name, pos: items});
|
||||
await this.refreshSelectedPlaylist();
|
||||
},
|
||||
|
||||
playlistclear: async function() {
|
||||
if (!confirm('Are you sure that you want to clear this playlist? This operation is NOT REVERSIBLE')) {
|
||||
return;
|
||||
}
|
||||
|
||||
await request('music.mpd.playlistclear', {name: this.selectedPlaylist.name});
|
||||
await this.refreshSelectedPlaylist();
|
||||
},
|
||||
|
||||
rename: async function() {
|
||||
if (!this.selectedPlaylist.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newName = prompt('New name for the playlist', this.selectedPlaylist.name);
|
||||
if (!newName.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await request('music.mpd.rename', {name: this.selectedPlaylist.name, new_name: newName});
|
||||
await this.listplaylists();
|
||||
|
||||
for (var item of this.browserItems) {
|
||||
if (item.type === 'playlist' && item.name === this.selectedPlaylist.name) {
|
||||
item.name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedPlaylist.name = newName;
|
||||
},
|
||||
|
||||
onNewPlayingTrack: async function(event) {
|
||||
var previousTrack = {
|
||||
file: this.track.file,
|
||||
|
@ -835,7 +1025,15 @@ Vue.component('music-mpd', {
|
|||
return true;
|
||||
|
||||
const filter = this.playlistFilter.split(' ').filter(_ => _.length > 0).map(_ => _.toLocaleLowerCase()).join(' ');
|
||||
return [track.artist || '', track.title || '', track.album || ''].join(' ').toLocaleLowerCase().indexOf() >= 0;
|
||||
return [track.artist || '', track.title || '', track.album || ''].join(' ').toLocaleLowerCase().indexOf(filter) >= 0;
|
||||
},
|
||||
|
||||
matchesEditorFilter: function(track) {
|
||||
if (this.editorFilter.length === 0)
|
||||
return true;
|
||||
|
||||
const filter = this.editorFilter.split(' ').filter(_ => _.length > 0).map(_ => _.toLocaleLowerCase()).join(' ');
|
||||
return [track.artist || '', track.title || '', track.album || ''].join(' ').toLocaleLowerCase().indexOf(filter) >= 0;
|
||||
},
|
||||
|
||||
matchesBrowserFilter: function(item) {
|
||||
|
@ -881,6 +1079,30 @@ Vue.component('music-mpd', {
|
|||
}
|
||||
},
|
||||
|
||||
onEditorItemClick: async function(track) {
|
||||
if (this.selectionMode.editor) {
|
||||
if (track.pos in this.selectedEditorItems) {
|
||||
Vue.delete(this.selectedEditorItems, track.pos);
|
||||
} else {
|
||||
Vue.set(this.selectedEditorItems, track.pos, track);
|
||||
}
|
||||
} else if (this.moveMode.editor) {
|
||||
var fromPos = Object.values(this.selectedEditorItems).map(_ => _.pos);
|
||||
var toPos = track.pos;
|
||||
this.moveMode.editor = false;
|
||||
|
||||
const promises = fromPos.map((pos,i) => this.playlistmove(pos, toPos+i));
|
||||
await Promise.all(promises);
|
||||
await this.refreshSelectedPlaylist();
|
||||
} else if (track.pos in this.selectedEditorItems) {
|
||||
Vue.delete(this.selectedEditorItems, track.pos);
|
||||
} else {
|
||||
this.selectedEditorItems = {};
|
||||
Vue.set(this.selectedEditorItems, track.pos, track);
|
||||
openDropdown(this.$refs.editorDropdown.$el);
|
||||
}
|
||||
},
|
||||
|
||||
onBrowserItemClick: function(item) {
|
||||
if (item.type === 'directory' && item.name === '..') {
|
||||
this.selectedBrowserItems = {};
|
||||
|
@ -940,6 +1162,14 @@ Vue.component('music-mpd', {
|
|||
this.selectionMode.browser = !this.selectionMode.browser;
|
||||
},
|
||||
|
||||
toggleEditorSelectionMode: function() {
|
||||
if (this.selectionMode.editor && Object.keys(this.selectedEditorItems).length) {
|
||||
openDropdown(this.$refs.editorDropdown.$el);
|
||||
}
|
||||
|
||||
this.selectionMode.editor = !this.selectionMode.editor;
|
||||
},
|
||||
|
||||
browserSelectAll: function() {
|
||||
this.selectedBrowserItems = {};
|
||||
this.selectionMode.browser = true;
|
||||
|
@ -953,6 +1183,17 @@ Vue.component('music-mpd', {
|
|||
openDropdown(this.$refs.browserDropdown.$el);
|
||||
},
|
||||
|
||||
editorSelectAll: function() {
|
||||
this.selectedEditorItems = {};
|
||||
this.selectionMode.editor = true;
|
||||
|
||||
for (var item of this.selectedPlaylist.items) {
|
||||
Vue.set(this.selectedEditorItems, item.pos, item);
|
||||
}
|
||||
|
||||
openDropdown(this.$refs.editorDropdown.$el);
|
||||
},
|
||||
|
||||
scrollToActiveTrack: function() {
|
||||
if (this.$refs.activePlaylistTrack && this.$refs.activePlaylistTrack.length) {
|
||||
this.$refs.activePlaylistTrack[0].$el.scrollIntoView({behavior: 'smooth'});
|
||||
|
@ -979,7 +1220,17 @@ Vue.component('music-mpd', {
|
|||
return;
|
||||
}
|
||||
|
||||
this.add(resource);
|
||||
await this.add(resource);
|
||||
},
|
||||
|
||||
addToPlaylistEditorPrompt: async function() {
|
||||
var resource = prompt('Path or URI of the resource to add');
|
||||
if (!resource.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await request('music.mpd.playlistadd', {name: this.selectedPlaylist.name, uri: resource});
|
||||
await this.refreshSelectedPlaylist();
|
||||
},
|
||||
|
||||
savePlaylistPrompt: async function() {
|
||||
|
@ -994,6 +1245,18 @@ Vue.component('music-mpd', {
|
|||
let items = await request('music.mpd.lsinfo', {uri: this.browserPath.join('/')});
|
||||
this._parseBrowserItems(items);
|
||||
},
|
||||
|
||||
refreshSelectedPlaylist: async function() {
|
||||
if (!this.selectedPlaylist.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
let items = (await this.listplaylistinfo(this.selectedPlaylist.name)).map((_, i) => {
|
||||
return { ..._, pos: i }
|
||||
});
|
||||
|
||||
Vue.set(this.selectedPlaylist, 'items', items);
|
||||
},
|
||||
},
|
||||
|
||||
created: function() {
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
<script type="text/x-template" id="tmpl-music-mpd">
|
||||
<div class="row music-mpd-container">
|
||||
<music-mpd-search ref="search"
|
||||
@info="info"
|
||||
:mpd="this">
|
||||
<music-mpd-search ref="search" @info="info" :mpd="this">
|
||||
</music-mpd-search>
|
||||
|
||||
<modal id="music-mpd-info" title="Info" v-model="modalVisible.info" ref="modal">
|
||||
|
@ -33,9 +31,9 @@
|
|||
<div class="col-8 value" v-text="infoItem.album"></div>
|
||||
</div>
|
||||
|
||||
<div class="row" v-if="infoItem.year">
|
||||
<div class="col-4 attr">Year</div>
|
||||
<div class="col-8 value" v-text="infoItem.year"></div>
|
||||
<div class="row" v-if="infoItem.year || infoItem.date">
|
||||
<div class="col-4 attr">Date</div>
|
||||
<div class="col-8 value" v-text="infoItem.year || infoItem.date"></div>
|
||||
</div>
|
||||
|
||||
<div class="row" v-if="infoItem.disc">
|
||||
|
@ -85,6 +83,57 @@
|
|||
</div>
|
||||
</modal>
|
||||
|
||||
<modal id="music-mpd-playlist-edit" title="Edit/view playlist" v-model="modalVisible.editor" ref="modalEditor">
|
||||
<div class="editor">
|
||||
<div class="editor-controls">
|
||||
<div class="row">
|
||||
<div class="col-7 filter-container">
|
||||
<i class="fa fa-filter input-icon"></i>
|
||||
<input type="text" class="with-icon" v-model="editorFilter">
|
||||
</div>
|
||||
<div class="col-5 pull-right">
|
||||
<button title="Add item" @click="addToPlaylistEditorPrompt">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
<button title="Rename playlist" @click="rename">
|
||||
<i class="fa fa-edit"></i>
|
||||
</button>
|
||||
<button :class="{enabled: selectionMode.editor}"
|
||||
:title="selectionMode.editor ? 'End selection' : 'Start selection'"
|
||||
@click="toggleEditorSelectionMode">
|
||||
<i class="fa fa-check"></i>
|
||||
</button>
|
||||
<button title="Select all"
|
||||
@click="editorSelectAll">
|
||||
<i class="fa fa-check-double"></i>
|
||||
</button>
|
||||
<button title="Clear playlist" @click="playlistclear">
|
||||
<i class="fa fa-ban"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-container">
|
||||
<dropdown id="music-mpd-editor-dropdown"
|
||||
v-if="selectedPlaylist.items"
|
||||
ref="editorDropdown"
|
||||
:items="editorDropdownItems">
|
||||
</dropdown>
|
||||
|
||||
<music-mpd-playlist-item
|
||||
v-for="item in selectedPlaylist.items"
|
||||
v-if="matchesEditorFilter(item)"
|
||||
:key="item.pos"
|
||||
:track="item"
|
||||
:selected="item.pos in selectedEditorItems"
|
||||
:move="moveMode.editor"
|
||||
@input="onEditorItemClick">
|
||||
</music-mpd-playlist-item>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
|
||||
<div class="row panels">
|
||||
<!-- Browser section -->
|
||||
<div class="col-no-margin-l-3 col-no-margin-m-3 s-hidden panel browser">
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
<div class="footer">
|
||||
<div class="left col-6">
|
||||
<button class="btn-default" v-if="results.length" @click="$event.preventDefault(); showResults = true" title="Show results">
|
||||
<button class="btn-default" type="button" v-if="results.length"
|
||||
@click="$event.preventDefault(); showResults = true" title="Show results">
|
||||
<i class="fa fa-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -33,10 +33,6 @@ class MusicPlugin(Plugin):
|
|||
def add(self, content):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def playlistadd(self, playlist):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def clear(self):
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -564,6 +564,26 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
return sorted(self._exec('listplaylists', return_status=False),
|
||||
key=lambda p: p['playlist'])
|
||||
|
||||
@action
|
||||
def listplaylist(self, name):
|
||||
"""
|
||||
List the items in the specified playlist (without metadata)
|
||||
|
||||
:param name: Name of the playlist
|
||||
:type name: str
|
||||
"""
|
||||
return self._exec('listplaylist', name, return_status=False)
|
||||
|
||||
@action
|
||||
def listplaylistinfo(self, name):
|
||||
"""
|
||||
List the items in the specified playlist (with metadata)
|
||||
|
||||
:param name: Name of the playlist
|
||||
:type name: str
|
||||
"""
|
||||
return self._exec('listplaylistinfo', name, return_status=False)
|
||||
|
||||
@action
|
||||
def playlistadd(self, name, uri):
|
||||
"""
|
||||
|
@ -582,6 +602,65 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
for res in uri:
|
||||
self._exec('playlistadd', name, res)
|
||||
|
||||
@action
|
||||
def playlistdelete(self, name, pos):
|
||||
"""
|
||||
Remove one or multiple tracks from a playlist.
|
||||
|
||||
:param name: Playlist name
|
||||
:type name: str
|
||||
|
||||
:param pos: Position or list of positions to remove
|
||||
:type pos: int or list[int]
|
||||
"""
|
||||
|
||||
if isinstance(pos, str):
|
||||
pos = int(pos)
|
||||
if isinstance(pos, int):
|
||||
pos = [pos]
|
||||
|
||||
for p in pos:
|
||||
self._exec('playlistdelete', name, p)
|
||||
|
||||
@action
|
||||
def playlistmove(self, name, from_pos, to_pos):
|
||||
"""
|
||||
Change the position of a track in the specified playlist
|
||||
|
||||
:param name: Playlist name
|
||||
:type name: str
|
||||
|
||||
:param from_pos: Original track position
|
||||
:type from_pos: int
|
||||
|
||||
:param to_pos: New track position
|
||||
:type to_pos: int
|
||||
"""
|
||||
self._exec('playlistmove', name, from_pos, to_pos)
|
||||
|
||||
@action
|
||||
def playlistclear(self, name):
|
||||
"""
|
||||
Clears all the elements from the specified playlist
|
||||
|
||||
:param name: Playlist name
|
||||
:type name: str
|
||||
"""
|
||||
self._exec('playlistclear', name)
|
||||
|
||||
@action
|
||||
def rename(self, name, new_name):
|
||||
"""
|
||||
Rename a playlist
|
||||
|
||||
:param name: Original playlist name
|
||||
:type name: str
|
||||
|
||||
:param new_name: New playlist name
|
||||
:type name: str
|
||||
"""
|
||||
self._exec('rename', name, new_name)
|
||||
|
||||
@action
|
||||
def lsinfo(self, uri=None):
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue