forked from platypush/platypush
parent
2df88c1911
commit
d799d50391
5 changed files with 153 additions and 45 deletions
|
@ -5,15 +5,25 @@
|
|||
Playlist name
|
||||
</TextPrompt>
|
||||
|
||||
<div class="playlists">
|
||||
<div class="playlists-container">
|
||||
<div class="header">
|
||||
<div class="filter">
|
||||
<input type="text"
|
||||
placeholder="Filter playlists"
|
||||
ref="playlistFilter"
|
||||
@input="filter = $event.target.value">
|
||||
</div>
|
||||
|
||||
<div class="playlist new-playlist">
|
||||
<button @click="showNewPlaylist = true">
|
||||
<i class="fa fa-plus" />
|
||||
Create new playlist
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="playlist" v-for="playlist in playlists" :key="playlist.id">
|
||||
<div class="playlists">
|
||||
<div class="playlist" v-for="playlist in sortedPlaylists" :key="playlist.id">
|
||||
<button @click="addToPlaylist(playlist.id)">
|
||||
<i class="fa fa-list" />
|
||||
{{ playlist.name }}
|
||||
|
@ -21,6 +31,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -41,13 +52,53 @@ export default {
|
|||
|
||||
data() {
|
||||
return {
|
||||
filter: '',
|
||||
loading: false,
|
||||
playlists: [],
|
||||
showNewPlaylist: false,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginName() {
|
||||
switch (this.item.type) {
|
||||
case 'youtube':
|
||||
return 'youtube'
|
||||
|
||||
case 'jellyfin':
|
||||
return 'media.jellyfin'
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
sortedPlaylists() {
|
||||
return this.playlists
|
||||
.filter((playlist) => playlist.name.toLowerCase().includes(this.filter.toLowerCase()))
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkPlugin() {
|
||||
if (!this.pluginName) {
|
||||
this.notify({
|
||||
title: 'Unsupported item type',
|
||||
text: `Item type ${this.item.type} does not support playlists`,
|
||||
warning: true,
|
||||
image: {
|
||||
icon: 'exclamation-triangle',
|
||||
}
|
||||
})
|
||||
|
||||
console.warn(`Unsupported item type: ${this.item.type}`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
async createPlaylist(name) {
|
||||
name = name?.trim()
|
||||
if (!name?.length)
|
||||
|
@ -56,23 +107,11 @@ export default {
|
|||
this.loading = true
|
||||
|
||||
try {
|
||||
const playlist = await this.request('youtube.create_playlist', {
|
||||
const playlist = await this.request(`${this.pluginName}.create_playlist`, {
|
||||
name: name,
|
||||
})
|
||||
|
||||
await this.request('youtube.add_to_playlist', {
|
||||
playlist_id: playlist.id,
|
||||
video_id: this.item.id || this.item.url,
|
||||
})
|
||||
|
||||
this.$emit('done')
|
||||
this.notify({
|
||||
text: 'Playlist created and video added',
|
||||
image: {
|
||||
icon: 'check',
|
||||
}
|
||||
})
|
||||
|
||||
await this.addToPlaylist(playlist.id)
|
||||
} finally {
|
||||
this.loading = false
|
||||
this.showNewPlaylist = false
|
||||
|
@ -80,26 +119,30 @@ export default {
|
|||
},
|
||||
|
||||
async refreshPlaylists() {
|
||||
this.loading = true
|
||||
if (!this.checkPlugin())
|
||||
return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
this.playlists = await this.request('youtube.get_playlists')
|
||||
this.playlists = await this.request(`${this.pluginName}.get_playlists`)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
async addToPlaylist(playlistId) {
|
||||
this.loading = true
|
||||
if (!this.checkPlugin())
|
||||
return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
await this.request('youtube.add_to_playlist', {
|
||||
await this.request(`${this.pluginName}.add_to_playlist`, {
|
||||
playlist_id: playlistId,
|
||||
video_id: this.item.id || this.item.url,
|
||||
item_ids: [this.item.id || this.item.url],
|
||||
})
|
||||
|
||||
this.notify({
|
||||
text: 'Video added to playlist',
|
||||
text: 'Item added to playlist',
|
||||
image: {
|
||||
icon: 'check',
|
||||
}
|
||||
|
@ -112,6 +155,15 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
loading() {
|
||||
if (this.loading)
|
||||
return
|
||||
|
||||
this.$nextTick(() => this.$refs.playlistFilter.focus())
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.refreshPlaylists()
|
||||
},
|
||||
|
@ -119,19 +171,47 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$header-height: 6.5em;
|
||||
|
||||
.playlist-adder-container {
|
||||
min-width: 300px;
|
||||
height: 100%;
|
||||
width: 30em;
|
||||
height: fit-content;
|
||||
max-width: 90vw;
|
||||
max-height: 70vh;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.playlists-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: $header-height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.playlists {
|
||||
width: 100%;
|
||||
height: calc(100% - #{$header-height});
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.filter {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
margin: 0.5em 0.5em 0.25em 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.playlist {
|
||||
button {
|
||||
width: 100%;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<Media v-bind="componentData.props"
|
||||
v-on="componentData.on"
|
||||
:collection="collection"
|
||||
@add-to-playlist="$emit('add-to-playlist', $event)"
|
||||
@delete="deleteItem"
|
||||
@select="select"
|
||||
@select-collection="selectCollection"
|
||||
|
|
|
@ -131,8 +131,8 @@ export default {
|
|||
|
||||
try {
|
||||
await this.request('media.jellyfin.playlist_move', {
|
||||
playlist: this.collection.id,
|
||||
playlist_item_id: item.playlist_item_id,
|
||||
playlist_id: this.collection.id,
|
||||
item_id: item.playlist_item_id,
|
||||
to_pos: to,
|
||||
})
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
@move="$emit('playlist-move', $event)"
|
||||
@play="$emit('play', $event)"
|
||||
@play-with-opts="$emit('play-with-opts', $event)"
|
||||
@remove-from-playlist="$emit('remove-from-playlist', $event)"
|
||||
@remove-from-playlist="removeFromPlaylist"
|
||||
@select="selectedResult = $event"
|
||||
@view="$emit('view', $event)"
|
||||
v-if="mediaItems?.length > 0" />
|
||||
|
@ -131,7 +131,6 @@ export default {
|
|||
'play',
|
||||
'play-with-opts',
|
||||
'playlist-move',
|
||||
'remove-from-playlist',
|
||||
'select',
|
||||
'select-collection',
|
||||
'view',
|
||||
|
@ -178,7 +177,11 @@ export default {
|
|||
mediaItems() {
|
||||
return (
|
||||
this.sortedItems?.filter((item) => !['collection', 'artist', 'album'].includes(item.item_type)) ?? []
|
||||
).sort((a, b) => {
|
||||
).map((item) => {
|
||||
item.media_type = item.type
|
||||
item.type = 'jellyfin'
|
||||
return item
|
||||
}).sort((a, b) => {
|
||||
if (this.view === 'playlist') {
|
||||
// Skip sorting if this is a playlist
|
||||
return 0
|
||||
|
@ -219,6 +222,20 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
async removeFromPlaylist(item) {
|
||||
this.loading_ = true
|
||||
try {
|
||||
await this.request('media.jellyfin.remove_from_playlist', {
|
||||
playlist_id: this.collection.id,
|
||||
item_ids: [item.playlist_item_id],
|
||||
})
|
||||
|
||||
await this.refresh()
|
||||
} finally {
|
||||
this.loading_ = false
|
||||
}
|
||||
},
|
||||
|
||||
async selectArtist() {
|
||||
const artistId = this.displayedArtist?.id || this.getUrlArgs().artist
|
||||
if (!artistId?.length)
|
||||
|
@ -319,13 +336,23 @@ export default {
|
|||
break
|
||||
|
||||
case 'playlist':
|
||||
this.items = await this.request(
|
||||
this.items = this.collection?.item_type === 'playlist' ? (
|
||||
await this.request(
|
||||
'media.jellyfin.get_playlist_items',
|
||||
{
|
||||
playlist: this.collection.id,
|
||||
playlist_id: this.collection.id,
|
||||
limit: 25000,
|
||||
}
|
||||
)
|
||||
) : (
|
||||
await this.request(
|
||||
'media.jellyfin.get_items',
|
||||
{
|
||||
parent_id: this.collection.id,
|
||||
limit: 25000,
|
||||
}
|
||||
)
|
||||
)
|
||||
break
|
||||
|
||||
default:
|
||||
|
|
|
@ -133,7 +133,7 @@ export default {
|
|||
try {
|
||||
await this.request('youtube.remove_from_playlist', {
|
||||
playlist_id: playlistId,
|
||||
video_id: videoId,
|
||||
item_ids: [videoId],
|
||||
})
|
||||
} finally {
|
||||
this.loading_ = false
|
||||
|
|
Loading…
Reference in a new issue