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
|
<div
|
||||||
class="item media-item"
|
class="item media-item"
|
||||||
:class="{selected: selected, 'list': listView}"
|
:class="{selected: selected, 'list': listView}"
|
||||||
@click.right.prevent="$refs.dropdown.toggle()"
|
@click.right="onContextClick"
|
||||||
v-if="!hidden">
|
v-if="!hidden">
|
||||||
|
|
||||||
<div class="thumbnail" v-if="!listView">
|
<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>
|
||||||
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
|
@ -29,10 +29,12 @@
|
||||||
<span class="actions">
|
<span class="actions">
|
||||||
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" ref="dropdown">
|
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" ref="dropdown">
|
||||||
<DropdownItem icon-class="fa fa-play" text="Play" @input="$emit('play')"
|
<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)"
|
<DropdownItem icon-class="fa fa-play" text="Play (With Cache)"
|
||||||
@input="$emit('play-with-opts', {item: item, opts: {cache: true}})"
|
@input="$emit('play-with-opts', {item: item, opts: {cache: true}})"
|
||||||
v-if="item.type === 'youtube'" />
|
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')"
|
<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'" />
|
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')"
|
<DropdownItem icon-class="fa fa-volume-high" text="Download Audio" @input="$emit('download-audio')"
|
||||||
|
@ -74,6 +76,12 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -82,11 +90,18 @@ import Dropdown from "@/components/elements/Dropdown";
|
||||||
import DropdownItem from "@/components/elements/DropdownItem";
|
import DropdownItem from "@/components/elements/DropdownItem";
|
||||||
import Icons from "./icons.json";
|
import Icons from "./icons.json";
|
||||||
import MediaImage from "./MediaImage";
|
import MediaImage from "./MediaImage";
|
||||||
|
import Modal from "@/components/Modal";
|
||||||
import Utils from "@/Utils";
|
import Utils from "@/Utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Dropdown, DropdownItem, MediaImage},
|
|
||||||
mixins: [Utils],
|
mixins: [Utils],
|
||||||
|
components: {
|
||||||
|
Dropdown,
|
||||||
|
DropdownItem,
|
||||||
|
MediaImage,
|
||||||
|
Modal,
|
||||||
|
},
|
||||||
|
|
||||||
emits: [
|
emits: [
|
||||||
'add-to-playlist',
|
'add-to-playlist',
|
||||||
'download',
|
'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() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
showPhoto: false,
|
||||||
typeIcons: Icons,
|
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>
|
</style>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="image-container"
|
<div class="image-container"
|
||||||
:class="{ 'with-image': !!item?.image }">
|
:class="{ 'with-image': !!item?.image, 'photo': item?.item_type === 'photo' }">
|
||||||
<div class="play-overlay" @click="$emit(clickEvent, item)" v-if="hasPlay">
|
<div class="play-overlay" @click.stop="onItemClick" v-if="hasPlay || item?.item_type === 'photo'">
|
||||||
<i :class="overlayIconClass" />
|
<i :class="overlayIconClass" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="backdrop" v-if="item?.image"
|
<div class="backdrop" v-if="item?.image || item?.preview_url"
|
||||||
:style="{ backgroundImage: `url(${item.image})` }" />
|
:style="{ backgroundImage: `url(${item.image || item.preview_url})` }" />
|
||||||
|
|
||||||
<span class="icon type-icon" v-if="typeIcons[item?.type]">
|
<span class="icon type-icon" v-if="typeIcons[item?.type]">
|
||||||
<a :href="item.url" target="_blank" v-if="item.url">
|
<a :href="item.url" target="_blank" v-if="item.url">
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<img class="image" :src="imgUrl" :alt="item.title" v-if="imgUrl" />
|
<img class="image" :src="imgUrl" :alt="item.title" v-if="imgUrl" />
|
||||||
|
|
||||||
<div class="image" v-else>
|
<div class="image" v-else>
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<i :class="iconClass" />
|
<i :class="iconClass" />
|
||||||
|
@ -68,6 +69,7 @@ export default {
|
||||||
case 'channel':
|
case 'channel':
|
||||||
case 'playlist':
|
case 'playlist':
|
||||||
case 'folder':
|
case 'folder':
|
||||||
|
case 'photo':
|
||||||
return 'select'
|
return 'select'
|
||||||
default:
|
default:
|
||||||
return 'play'
|
return 'play'
|
||||||
|
@ -88,6 +90,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
imgUrl() {
|
imgUrl() {
|
||||||
|
if (this.item?.item_type === 'photo') {
|
||||||
|
return this.item?.preview_url || this.item?.url
|
||||||
|
}
|
||||||
|
|
||||||
let img = this.item?.image
|
let img = this.item?.image
|
||||||
if (!img) {
|
if (!img) {
|
||||||
img = this.item?.images?.[0]?.url
|
img = this.item?.images?.[0]?.url
|
||||||
|
@ -103,11 +109,19 @@ export default {
|
||||||
this.item?.item_type === 'folder'
|
this.item?.item_type === 'folder'
|
||||||
) {
|
) {
|
||||||
return 'fas fa-folder-open'
|
return 'fas fa-folder-open'
|
||||||
|
} else if (this.item?.item_type === 'photo') {
|
||||||
|
return 'fas fa-eye'
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'fas fa-play'
|
return 'fas fa-play'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onItemClick() {
|
||||||
|
this.$emit(this.clickEvent, this.item)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,25 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
mediaItems() {
|
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', {
|
await this.request('media.jellyfin.get_items', {
|
||||||
parent_id: this.collection.id,
|
parent_id: this.collection.id,
|
||||||
limit: 5000,
|
limit: 25000,
|
||||||
})
|
})
|
||||||
) : (await this.request('media.jellyfin.get_collections')).map((collection) => ({
|
) : (await this.request('media.jellyfin.get_collections')).map((collection) => ({
|
||||||
...collection,
|
...collection,
|
||||||
|
|
|
@ -212,7 +212,7 @@ export default {
|
||||||
'media.jellyfin.get_items',
|
'media.jellyfin.get_items',
|
||||||
{
|
{
|
||||||
parent_id: this.collection.id,
|
parent_id: this.collection.id,
|
||||||
limit: 5000,
|
limit: 25000,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
).map((item) => {
|
).map((item) => {
|
||||||
|
@ -234,7 +234,7 @@ export default {
|
||||||
'media.jellyfin.get_items',
|
'media.jellyfin.get_items',
|
||||||
{
|
{
|
||||||
parent_id: this.collection.id,
|
parent_id: this.collection.id,
|
||||||
limit: 5000,
|
limit: 25000,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in a new issue