forked from platypush/platypush
[#414] Added support for photo collections in Jellyfin UI.
This commit is contained in:
parent
3ffb061e2a
commit
7b8d92b120
4 changed files with 116 additions and 12 deletions
|
@ -2,11 +2,11 @@
|
|||
<div
|
||||
class="item media-item"
|
||||
:class="{selected: selected, 'list': listView}"
|
||||
@click.right.prevent="$refs.dropdown.toggle()"
|
||||
@click.right="onContextClick"
|
||||
v-if="!hidden">
|
||||
|
||||
<div class="thumbnail" v-if="!listView">
|
||||
<MediaImage :item="item" @play="$emit('play')" @select="$emit('select')" />
|
||||
<MediaImage :item="item" @play="$emit('play')" @select="onMediaSelect" />
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
|
@ -29,10 +29,12 @@
|
|||
<span class="actions">
|
||||
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" ref="dropdown">
|
||||
<DropdownItem icon-class="fa fa-play" text="Play" @input="$emit('play')"
|
||||
v-if="item.type !== 'torrent'" />
|
||||
v-if="item.type !== 'torrent' && item.item_type !== 'photo'" />
|
||||
<DropdownItem icon-class="fa fa-play" text="Play (With Cache)"
|
||||
@input="$emit('play-with-opts', {item: item, opts: {cache: true}})"
|
||||
v-if="item.type === 'youtube'" />
|
||||
<DropdownItem icon-class="fa fa-eye" text="View" @input="showPhoto = true"
|
||||
v-if="item.item_type === 'photo'" />
|
||||
<DropdownItem icon-class="fa fa-download" text="Download" @input="$emit('download')"
|
||||
v-if="(item.type === 'torrent' || item.type === 'youtube') && item.item_type !== 'channel' && item.item_type !== 'playlist'" />
|
||||
<DropdownItem icon-class="fa fa-volume-high" text="Download Audio" @input="$emit('download-audio')"
|
||||
|
@ -74,6 +76,12 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="photo-container" v-if="item.item_type === 'photo' && showPhoto">
|
||||
<Modal :title="item.title || item.name" :visible="true" @close="showPhoto = false">
|
||||
<img :src="item.url" ref="image" @load="onImgLoad" />
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -82,11 +90,18 @@ import Dropdown from "@/components/elements/Dropdown";
|
|||
import DropdownItem from "@/components/elements/DropdownItem";
|
||||
import Icons from "./icons.json";
|
||||
import MediaImage from "./MediaImage";
|
||||
import Modal from "@/components/Modal";
|
||||
import Utils from "@/Utils";
|
||||
|
||||
export default {
|
||||
components: {Dropdown, DropdownItem, MediaImage},
|
||||
mixins: [Utils],
|
||||
components: {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
MediaImage,
|
||||
Modal,
|
||||
},
|
||||
|
||||
emits: [
|
||||
'add-to-playlist',
|
||||
'download',
|
||||
|
@ -130,8 +145,39 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onContextClick(e) {
|
||||
if (this.item?.item_type === 'photo') {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
this.$refs.dropdown.toggle()
|
||||
},
|
||||
|
||||
onImgLoad() {
|
||||
const width = this.$refs.image.naturalWidth
|
||||
const height = this.$refs.image.naturalHeight
|
||||
|
||||
if (width > height) {
|
||||
this.$refs.image.classList.add('horizontal')
|
||||
} else {
|
||||
this.$refs.image.classList.add('vertical')
|
||||
}
|
||||
},
|
||||
|
||||
onMediaSelect() {
|
||||
if (this.item?.item_type === 'photo') {
|
||||
this.showPhoto = true
|
||||
} else {
|
||||
this.$emit('select')
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showPhoto: false,
|
||||
typeIcons: Icons,
|
||||
}
|
||||
},
|
||||
|
@ -329,5 +375,31 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.photo-container {
|
||||
:deep(.modal) {
|
||||
.body {
|
||||
max-width: 95vh;
|
||||
max-height: 90vh;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
&.horizontal {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-width: 95vh;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 90vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="image-container"
|
||||
:class="{ 'with-image': !!item?.image }">
|
||||
<div class="play-overlay" @click="$emit(clickEvent, item)" v-if="hasPlay">
|
||||
:class="{ 'with-image': !!item?.image, 'photo': item?.item_type === 'photo' }">
|
||||
<div class="play-overlay" @click.stop="onItemClick" v-if="hasPlay || item?.item_type === 'photo'">
|
||||
<i :class="overlayIconClass" />
|
||||
</div>
|
||||
|
||||
<div class="backdrop" v-if="item?.image"
|
||||
:style="{ backgroundImage: `url(${item.image})` }" />
|
||||
<div class="backdrop" v-if="item?.image || item?.preview_url"
|
||||
:style="{ backgroundImage: `url(${item.image || item.preview_url})` }" />
|
||||
|
||||
<span class="icon type-icon" v-if="typeIcons[item?.type]">
|
||||
<a :href="item.url" target="_blank" v-if="item.url">
|
||||
|
@ -17,6 +17,7 @@
|
|||
</span>
|
||||
|
||||
<img class="image" :src="imgUrl" :alt="item.title" v-if="imgUrl" />
|
||||
|
||||
<div class="image" v-else>
|
||||
<div class="inner">
|
||||
<i :class="iconClass" />
|
||||
|
@ -68,6 +69,7 @@ export default {
|
|||
case 'channel':
|
||||
case 'playlist':
|
||||
case 'folder':
|
||||
case 'photo':
|
||||
return 'select'
|
||||
default:
|
||||
return 'play'
|
||||
|
@ -88,6 +90,10 @@ export default {
|
|||
},
|
||||
|
||||
imgUrl() {
|
||||
if (this.item?.item_type === 'photo') {
|
||||
return this.item?.preview_url || this.item?.url
|
||||
}
|
||||
|
||||
let img = this.item?.image
|
||||
if (!img) {
|
||||
img = this.item?.images?.[0]?.url
|
||||
|
@ -103,11 +109,19 @@ export default {
|
|||
this.item?.item_type === 'folder'
|
||||
) {
|
||||
return 'fas fa-folder-open'
|
||||
} else if (this.item?.item_type === 'photo') {
|
||||
return 'fas fa-eye'
|
||||
}
|
||||
|
||||
return 'fas fa-play'
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onItemClick() {
|
||||
this.$emit(this.clickEvent, this.item)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -67,7 +67,25 @@ export default {
|
|||
},
|
||||
|
||||
mediaItems() {
|
||||
return this.sortedItems?.filter((item) => item.item_type !== 'collection') ?? []
|
||||
const items = this.sortedItems?.filter((item) => item.item_type !== 'collection') ?? []
|
||||
|
||||
if (this.collection && !this.collection.collection_type) {
|
||||
return items.sort((a, b) => {
|
||||
if (a.created_at && b.created_at)
|
||||
return (new Date(a.created_at)) < (new Date(b.created_at))
|
||||
|
||||
if (a.created_at)
|
||||
return -1
|
||||
|
||||
if (b.created_at)
|
||||
return 1
|
||||
|
||||
let names = [a.name || a.title || '', b.name || b.title || '']
|
||||
return names[0].localeCompare(names[1])
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -120,7 +138,7 @@ export default {
|
|||
(
|
||||
await this.request('media.jellyfin.get_items', {
|
||||
parent_id: this.collection.id,
|
||||
limit: 5000,
|
||||
limit: 25000,
|
||||
})
|
||||
) : (await this.request('media.jellyfin.get_collections')).map((collection) => ({
|
||||
...collection,
|
||||
|
|
|
@ -212,7 +212,7 @@ export default {
|
|||
'media.jellyfin.get_items',
|
||||
{
|
||||
parent_id: this.collection.id,
|
||||
limit: 5000,
|
||||
limit: 25000,
|
||||
}
|
||||
)
|
||||
).map((item) => {
|
||||
|
@ -234,7 +234,7 @@ export default {
|
|||
'media.jellyfin.get_items',
|
||||
{
|
||||
parent_id: this.collection.id,
|
||||
limit: 5000,
|
||||
limit: 25000,
|
||||
}
|
||||
)
|
||||
break
|
||||
|
|
Loading…
Reference in a new issue