added add to playlist for list item songs
This commit is contained in:
parent
2c3535fcdc
commit
00e032a0ec
6 changed files with 173 additions and 19 deletions
|
@ -239,23 +239,60 @@ const app = new Vue({
|
||||||
hangtimer: null,
|
hangtimer: null,
|
||||||
selectedMediaItems: [],
|
selectedMediaItems: [],
|
||||||
routes: ["browse", "listen_now", "radio"],
|
routes: ["browse", "listen_now", "radio"],
|
||||||
musicBaseUrl: "https://api.music.apple.com/"
|
musicBaseUrl: "https://api.music.apple.com/",
|
||||||
|
modals: {
|
||||||
|
addToPlaylist: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
page: () => {
|
page: () => {
|
||||||
document.getElementById("app-content").scrollTo(0, 0);
|
document.getElementById("app-content").scrollTo(0, 0);
|
||||||
app.selectedMediaItems = [];
|
app.resetState()
|
||||||
},
|
},
|
||||||
showingPlaylist: () => {
|
showingPlaylist: () => {
|
||||||
document.getElementById("app-content").scrollTo(0, 0);
|
document.getElementById("app-content").scrollTo(0, 0);
|
||||||
app.selectedMediaItems = [];
|
app.resetState()
|
||||||
},
|
},
|
||||||
artistPage: () => {
|
artistPage: () => {
|
||||||
document.getElementById("app-content").scrollTo(0, 0);
|
document.getElementById("app-content").scrollTo(0, 0);
|
||||||
app.selectedMediaItems = [];
|
app.resetState()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
resetState() {
|
||||||
|
app.selectedMediaItems = [];
|
||||||
|
for (let key in app.modals) {
|
||||||
|
app.modals[key] = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
promptAddToPlaylist() {
|
||||||
|
app.modals.addToPlaylist = true;
|
||||||
|
},
|
||||||
|
addSelectedToPlaylist(playlist_id) {
|
||||||
|
let self = this
|
||||||
|
let pl_items = []
|
||||||
|
for (let i = 0; i < self.selectedMediaItems.length; i++) {
|
||||||
|
if(self.selectedMediaItems[i].kind == "song") {
|
||||||
|
self.selectedMediaItems[i].kind = "songs"
|
||||||
|
}else if(self.selectedMediaItems[i].kind == "album") {
|
||||||
|
self.selectedMediaItems[i].kind = "albums"
|
||||||
|
} else if(self.selectedMediaItems[i].kind == "library-song") {
|
||||||
|
self.selectedMediaItems[i].kind = "library-songs"
|
||||||
|
} else if(self.selectedMediaItems[i].kind == "library-album") {
|
||||||
|
self.selectedMediaItems[i].kind = "library-albums"
|
||||||
|
}
|
||||||
|
pl_items.push({
|
||||||
|
id: self.selectedMediaItems[i].id,
|
||||||
|
type: self.selectedMediaItems[i].kind
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.modals.addToPlaylist = false
|
||||||
|
this.mk.api.library.appendTracksToPlaylist(playlist_id, pl_items).then(()=>{
|
||||||
|
if(this.page == 'playlist_' + this.showingPlaylist.id) {
|
||||||
|
this.getPlaylistFromID(this.showingPlaylist.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
async init() {
|
async init() {
|
||||||
let self = this
|
let self = this
|
||||||
clearTimeout(this.hangtimer)
|
clearTimeout(this.hangtimer)
|
||||||
|
@ -366,7 +403,6 @@ const app = new Vue({
|
||||||
this.appRoute(window.location.hash)
|
this.appRoute(window.location.hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() =>{
|
setTimeout(() =>{
|
||||||
this.getBrowsePage();
|
this.getBrowsePage();
|
||||||
this.$forceUpdate()}, 500)
|
this.$forceUpdate()}, 500)
|
||||||
|
@ -401,13 +437,14 @@ const app = new Vue({
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
select_selectMediaItem(id, kind, index, guid) {
|
select_selectMediaItem(id, kind, index, guid, library) {
|
||||||
if (!this.select_hasMediaItem(guid)) {
|
if (!this.select_hasMediaItem(guid)) {
|
||||||
this.selectedMediaItems.push({
|
this.selectedMediaItems.push({
|
||||||
id: id,
|
id: id,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
index: index,
|
index: index,
|
||||||
guid: guid
|
guid: guid,
|
||||||
|
isLibrary: library
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -470,6 +507,7 @@ const app = new Vue({
|
||||||
this.playlists.loadingState = 1
|
this.playlists.loadingState = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlaylistTracks(next) {
|
function getPlaylistTracks(next) {
|
||||||
app.apiCall(app.musicBaseUrl + next, res => {
|
app.apiCall(app.musicBaseUrl + next, res => {
|
||||||
if (self.showingPlaylist.id != playlistId) {
|
if (self.showingPlaylist.id != playlistId) {
|
||||||
|
@ -669,7 +707,6 @@ const app = new Vue({
|
||||||
window.location.hash = `${kind}/${id}`
|
window.location.hash = `${kind}/${id}`
|
||||||
document.querySelector("#app-content").scrollTop = 0
|
document.querySelector("#app-content").scrollTop = 0
|
||||||
} else if (!kind.toString().includes("radioStation") && !kind.toString().includes("song") && !kind.toString().includes("musicVideo") && !kind.toString().includes("uploadedVideo") && !kind.toString().includes("music-movie")) {
|
} else if (!kind.toString().includes("radioStation") && !kind.toString().includes("song") && !kind.toString().includes("musicVideo") && !kind.toString().includes("uploadedVideo") && !kind.toString().includes("music-movie")) {
|
||||||
if (kind.toString().includes("music-movie")){kind = "musicMovie"}
|
|
||||||
app.page = (kind) + "_" + (id);
|
app.page = (kind) + "_" + (id);
|
||||||
app.getTypeFromID((kind), (id), (isLibrary), {extend: "editorialVideo"});
|
app.getTypeFromID((kind), (id), (isLibrary), {extend: "editorialVideo"});
|
||||||
window.location.hash = `${kind}/${id}`
|
window.location.hash = `${kind}/${id}`
|
||||||
|
|
|
@ -1520,6 +1520,49 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
|
||||||
|
|
||||||
/* Cider */
|
/* Cider */
|
||||||
|
|
||||||
|
.modal-fullscreen {
|
||||||
|
display:flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 9999;
|
||||||
|
.modal-window {
|
||||||
|
background: #333;
|
||||||
|
border-radius: var(--mediaItemRadius);
|
||||||
|
box-shadow: var(--mediaItemShadow-Shadow);
|
||||||
|
display:flex;
|
||||||
|
flex-flow: column;
|
||||||
|
.modal-header {
|
||||||
|
width:100%;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.addtoplaylist-panel {
|
||||||
|
.modal-header {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.modal-window {
|
||||||
|
max-height: 500px;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#navigation-bar {
|
#navigation-bar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: rgba(0, 0, 0, 0.25);
|
background: rgba(0, 0, 0, 0.25);
|
||||||
|
|
36
src/renderer/views/components/add-to-playlist.ejs
Normal file
36
src/renderer/views/components/add-to-playlist.ejs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script type="text/x-template" id="add-to-playlist">
|
||||||
|
<template>
|
||||||
|
<div class="modal-fullscreen addtoplaylist-panel" @click.self="app.resetState()">
|
||||||
|
<div class="modal-window">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col flex-center">
|
||||||
|
Add To Playlist
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button class="md-btn" @click="app.resetState()">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-content">
|
||||||
|
<button class="md-btn" @click="app.addSelectedToPlaylist(playlist.id)" style="width:100%;" v-for="playlist in playlists" v-if="playlist.attributes.canEdit && playlist.type != 'library-playlist-folders'">{{ playlist.attributes.name }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('add-to-playlist', {
|
||||||
|
template: '#add-to-playlist',
|
||||||
|
props: {
|
||||||
|
playlists: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -4,9 +4,10 @@
|
||||||
@contextmenu="contextMenu"
|
@contextmenu="contextMenu"
|
||||||
@click="select"
|
@click="select"
|
||||||
:data-id="item.attributes.playParams.id ?? item.id"
|
:data-id="item.attributes.playParams.id ?? item.id"
|
||||||
:data-type="item.type ?? item.attributes.playParams.kind"
|
:data-type="getDataType()"
|
||||||
:data-index="index"
|
:data-index="index"
|
||||||
:data-guid="guid"
|
:data-guid="guid"
|
||||||
|
:data-islibrary="this.item.attributes.playParams.isLibrary ?? false"
|
||||||
class="cd-mediaitem-list-item"
|
class="cd-mediaitem-list-item"
|
||||||
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}">
|
:class="{'mediaitem-selected': app.select_hasMediaItem(guid)}">
|
||||||
<template v-if="isVisible">
|
<template v-if="isVisible">
|
||||||
|
@ -84,11 +85,23 @@
|
||||||
'contextExt': {type: Object, required: false},
|
'contextExt': {type: Object, required: false},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getDataType() {
|
||||||
|
if(this.item.attributes.playParams.isLibrary) {
|
||||||
|
return this.item.type
|
||||||
|
}else{
|
||||||
|
return this.item.attributes.playParams.kind
|
||||||
|
}
|
||||||
|
},
|
||||||
select(e) {
|
select(e) {
|
||||||
|
let data_type = this.getDataType()
|
||||||
|
let item_id = this.item.attributes.playParams.id ?? this.item.id
|
||||||
|
let isLibrary = this.item.attributes.playParams.isLibrary ?? false
|
||||||
|
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
if (this.index != -1) {
|
if (this.index != -1) {
|
||||||
|
|
||||||
if(app.selectedMediaItems.length == 0) {
|
if(app.selectedMediaItems.length == 0) {
|
||||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
|
app.select_selectMediaItem(item_id, this.getDataType(), this.index, this.guid, isLibrary)
|
||||||
}
|
}
|
||||||
let allMediaItems = document.querySelectorAll(".cd-mediaitem-list-item[data-index]")
|
let allMediaItems = document.querySelectorAll(".cd-mediaitem-list-item[data-index]")
|
||||||
let startIndex = Math.min(...app.selectedMediaItems.map(item => item.index))
|
let startIndex = Math.min(...app.selectedMediaItems.map(item => item.index))
|
||||||
|
@ -100,7 +113,8 @@
|
||||||
app.select_selectMediaItem(item.getAttribute("data-id"),
|
app.select_selectMediaItem(item.getAttribute("data-id"),
|
||||||
item.getAttribute("data-type"),
|
item.getAttribute("data-type"),
|
||||||
item.getAttribute("data-index"),
|
item.getAttribute("data-index"),
|
||||||
item.getAttribute("data-guid"))
|
item.getAttribute("data-guid")),
|
||||||
|
item.getAttribute("data-islibrary")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.index > endIndex) {
|
} else if (this.index > endIndex) {
|
||||||
|
@ -110,7 +124,8 @@
|
||||||
app.select_selectMediaItem(item.getAttribute("data-id"),
|
app.select_selectMediaItem(item.getAttribute("data-id"),
|
||||||
item.getAttribute("data-type"),
|
item.getAttribute("data-type"),
|
||||||
item.getAttribute("data-index"),
|
item.getAttribute("data-index"),
|
||||||
item.getAttribute("data-guid"))
|
item.getAttribute("data-guid")),
|
||||||
|
item.getAttribute("data-islibrary")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,7 +135,8 @@
|
||||||
app.select_selectMediaItem(item.getAttribute("data-id"),
|
app.select_selectMediaItem(item.getAttribute("data-id"),
|
||||||
item.getAttribute("data-type"),
|
item.getAttribute("data-type"),
|
||||||
item.getAttribute("data-index"),
|
item.getAttribute("data-index"),
|
||||||
item.getAttribute("data-guid"))
|
item.getAttribute("data-guid")),
|
||||||
|
item.getAttribute("data-islibrary")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,29 +145,39 @@
|
||||||
if (app.select_hasMediaItem(this.guid)) {
|
if (app.select_hasMediaItem(this.guid)) {
|
||||||
app.select_removeMediaItem(this.guid)
|
app.select_removeMediaItem(this.guid)
|
||||||
} else {
|
} else {
|
||||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
|
app.select_selectMediaItem(item_id, this.getDataType(), this.index, this.guid, isLibrary)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (app.select_hasMediaItem(this.guid)) {
|
if (app.select_hasMediaItem(this.guid)) {
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
} else {
|
} else {
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
|
app.select_selectMediaItem(item_id, this.getDataType(), this.index, this.guid, isLibrary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contextMenu(event) {
|
contextMenu(event) {
|
||||||
let self = this
|
let self = this
|
||||||
|
let data_type = this.getDataType()
|
||||||
|
let item_id = this.item.attributes.playParams.id ?? this.item.id
|
||||||
|
let isLibrary = this.item.attributes.playParams.isLibrary ?? false
|
||||||
|
|
||||||
let useMenu = "normal"
|
let useMenu = "normal"
|
||||||
if (app.selectedMediaItems.length <= 1) {
|
if (app.selectedMediaItems.length <= 1) {
|
||||||
app.selectedMediaItems = []
|
app.selectedMediaItems = []
|
||||||
app.select_selectMediaItem(this.item.attributes.playParams.id ?? this.item.id, this.item.attributes.playParams.kind ?? this.item.type, this.index, this.guid)
|
app.select_selectMediaItem(item_id, data_type, this.index, this.guid, isLibrary)
|
||||||
} else {
|
} else {
|
||||||
useMenu = "multiple"
|
useMenu = "multiple"
|
||||||
}
|
}
|
||||||
let menus = {
|
let menus = {
|
||||||
multiple: {
|
multiple: {
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
"name": "Add to Playlist...",
|
||||||
|
"action": function () {
|
||||||
|
app.promptAddToPlaylist()
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: `Play ${app.selectedMediaItems.length} tracks next`,
|
name: `Play ${app.selectedMediaItems.length} tracks next`,
|
||||||
action: () => {
|
action: () => {
|
||||||
|
@ -197,6 +223,12 @@
|
||||||
},
|
},
|
||||||
normal: {
|
normal: {
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
"name": "Add to Playlist...",
|
||||||
|
"action": function () {
|
||||||
|
app.promptAddToPlaylist()
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Start Radio",
|
"name": "Start Radio",
|
||||||
"action": function () {
|
"action": function () {
|
||||||
|
|
|
@ -173,6 +173,7 @@
|
||||||
Playlists
|
Playlists
|
||||||
</div>
|
</div>
|
||||||
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id"
|
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id"
|
||||||
|
@dragover="()=>{}"
|
||||||
:href="item.href"
|
:href="item.href"
|
||||||
@click='appRoute(`playlist_` + item.id); showingPlaylist = [];getPlaylistFromID(app.page.substring(9))'>
|
@click='appRoute(`playlist_` + item.id); showingPlaylist = [];getPlaylistFromID(app.page.substring(9))'>
|
||||||
{{ item.attributes.name }}
|
{{ item.attributes.name }}
|
||||||
|
@ -408,6 +409,9 @@
|
||||||
<transition name="wpfade">
|
<transition name="wpfade">
|
||||||
<div class="bg-artwork--placeholder" v-else></div>
|
<div class="bg-artwork--placeholder" v-else></div>
|
||||||
</transition>
|
</transition>
|
||||||
|
<transition name="wpfade">
|
||||||
|
<add-to-playlist :playlists="playlists.listing" v-if="modals.addToPlaylist"></add-to-playlist>
|
||||||
|
</transition>
|
||||||
<div id="apple-music-video-container">
|
<div id="apple-music-video-container">
|
||||||
<div id="apple-music-video-player-controls">
|
<div id="apple-music-video-player-controls">
|
||||||
<div id="player-exit" title="Close" onclick="app.exitMV()">
|
<div id="player-exit" title="Close" onclick="app.exitMV()">
|
||||||
|
@ -485,6 +489,8 @@
|
||||||
</button>
|
</button>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Add to playlist -->
|
||||||
|
<%- include('components/add-to-playlist') %>
|
||||||
<!-- Queue -->
|
<!-- Queue -->
|
||||||
<%- include('components/queue') %>
|
<%- include('components/queue') %>
|
||||||
<!-- Queue Item -->
|
<!-- Queue Item -->
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
<div class="playlist-body">
|
<div class="playlist-body">
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<div style="width:100%">
|
<div style="width:100%">
|
||||||
<draggable :sort="data.attributes.canEdit" v-model="data.relationships.tracks.data" @start="drag=true" @end="drag=false;put()">
|
<draggable :sort="data.attributes.canEdit && data.type == 'library-playlists'" v-model="data.relationships.tracks.data" @start="drag=true" @end="drag=false;put()">
|
||||||
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" :context-ext="buildContextMenu()"
|
<mediaitem-list-item :item="item" :parent="getItemParent(data)" :index="index" :context-ext="buildContextMenu()"
|
||||||
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
|
v-for="(item,index) in data.relationships.tracks.data"></mediaitem-list-item>
|
||||||
</draggable>
|
</draggable>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue