diff --git a/frontend/src/components/Gallery.vue b/frontend/src/components/Gallery.vue
index 02b57b0..dd2471f 100644
--- a/frontend/src/components/Gallery.vue
+++ b/frontend/src/components/Gallery.vue
@@ -118,7 +118,6 @@ defineExpose({
// Wrapping either end, just land outside the list
if (Math.abs(d) >= N || Math.sign(d) !== Math.sign(moveto - index)) moveto = N
}
- console.log("Gallery cursorMove", d, index, moveto, moveto - index)
store.cursor = docs[moveto]?.key ?? ''
const tr = store.cursor ? document.getElementById(`file-${store.cursor}`) : ''
if (select) {
diff --git a/frontend/src/components/GalleryFigure.vue b/frontend/src/components/GalleryFigure.vue
index f92fab6..46fcdb3 100644
--- a/frontend/src/components/GalleryFigure.vue
+++ b/frontend/src/components/GalleryFigure.vue
@@ -3,20 +3,17 @@
:class="{ file: !doc.dir, folder: doc.dir, cursor: store.cursor === doc.key }"
@contextmenu.stop
@focus.stop="store.cursor = doc.key"
- @click="ev => {
- if (m!.play()) ev.preventDefault()
- store.cursor = doc.key
- }"
+ @click=onclick
>
@@ -33,10 +30,15 @@ const props = defineProps<{
index: number
}>()
const m = ref(null)
+
+const onclick = (ev: Event) => {
+ if (m.value!.play()) ev.preventDefault()
+ store.cursor = props.doc.key
+}
diff --git a/frontend/src/components/MediaPreview.vue b/frontend/src/components/MediaPreview.vue
index 28bd1f8..bd1f5a2 100644
--- a/frontend/src/components/MediaPreview.vue
+++ b/frontend/src/components/MediaPreview.vue
@@ -2,8 +2,10 @@
-
-
+
+
@@ -15,20 +17,83 @@ import type { Doc } from '@/repositories/Document'
const aud = ref(null)
const vid = ref(null)
const media = computed(() => aud.value || vid.value)
+const poster = computed(() => `${props.doc.previewurl}?${props.quality}&t=${props.doc.mtime}`)
const props = defineProps<{
doc: Doc
quality: string
}>()
+const onplay = () => {
+ if (!media.value) return
+ media.value.controls = true
+ media.value.setAttribute('data-playing', '')
+}
+const onpaused = () => {
+ if (!media.value) return
+ media.value.controls = false
+ media.value.removeAttribute('data-playing')
+}
+let fscurrent: HTMLVideoElement | null = null
+const next = () => {
+ if (!media.value) return
+ media.value.load() // Restore poster
+ const medias = Array.from(document.querySelectorAll('video, audio')) as (HTMLAudioElement | HTMLVideoElement)[]
+ if (medias.length === 0) return
+ let el: HTMLAudioElement | HTMLVideoElement | null = null
+ for (const i in medias) {
+ if (medias[i] === (fscurrent || media.value)) {
+ el = medias[+i + 1] || medias[0]
+ break
+ }
+ }
+ if (!el) return
+ if (el.tagName === "VIDEO" && document.fullscreenElement === media.value) {
+ // Fullscreen needs to use the current video element for the next video
+ // because we are not allowed to fullscreen the next one.
+ // FIXME: Write our own player to avoid this problem...
+ const elem = media.value as HTMLVideoElement
+ const playing = el as HTMLVideoElement
+ if (elem === playing) {
+ playing.play() // Only one video, just replay
+ return
+ }
+ if (!fscurrent) {
+ elem.addEventListener('fullscreenchange', ev => {
+ if (!fscurrent) return
+ // Restore the original video element and continue with the one that was playing
+ fscurrent.currentTime = elem.currentTime
+ fscurrent.click()
+ if (!elem.paused) fscurrent.play()
+ fscurrent = null
+ elem.src = props.doc.url
+ elem.poster = poster.value
+ onpaused()
+ }, {once: true})
+ }
+ fscurrent = playing
+ elem.src = playing.src
+ elem.poster = ''
+ elem.play()
+ } else {
+ document.exitFullscreen()
+ el.click()
+ }
+}
defineExpose({
play() {
- if (media.value) {
- if (media.value.paused) media.value.play()
- else media.value.pause()
- return true
+ if (!media.value) return false
+ if (media.value.paused) {
+ media.value.play()
+ for (const el of Array.from(document.querySelectorAll('video, audio')) as (HTMLAudioElement | HTMLVideoElement)[]) {
+ if (el === media.value) continue
+ el.pause()
+ }
+ } else {
+ media.value.pause()
}
- return false
+ return true
},
+ media,
})
@@ -44,20 +109,12 @@ const preview = () => (