1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-07-27 01:14:36 +02:00

fix: Video要素をpropsで渡すのをやめる

This commit is contained in:
kakkokari-gtyih
2026-07-11 19:08:33 +09:00
parent 82961c4272
commit 541c5f6687
3 changed files with 51 additions and 42 deletions

View File

@@ -173,7 +173,8 @@ export function calculateSourceTransform({
</script>
<script lang="ts" setup>
import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
import { computed, nextTick, ref, useTemplateRef, watch, provide } from 'vue';
import { DI } from '@/di.js';
import MkVideoContol from './MkVideoContol.vue';
import * as os from '@/os.js';
import { prefer } from '@/preferences.js';
@@ -205,6 +206,8 @@ const mainEl = useTemplateRef('mainEl');
const videoEl = useTemplateRef('videoEl');
const videoControl = useTemplateRef('videoControl');
provide(DI.mkImageGalleryItemVideoEl, videoEl);
const originalContentLoaded = ref(false);
const thumbnailContentLoaded = ref(false);
const enableTransition = ref(false);

View File

@@ -39,17 +39,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { ref, computed, watch, onActivated, onMounted, onBeforeUnmount } from 'vue';
import { ref, shallowRef, inject, computed, watch, onBeforeUnmount } from 'vue';
import type { MenuItem } from '@/types/menu.js';
import { DI } from '@/di.js';
import { hms } from '@/filters/hms.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import hasAudio from '@/utility/media-has-audio.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
const props = defineProps<{
videoEl: HTMLVideoElement;
}>();
const videoEl = inject(DI.mkImageGalleryItemVideoEl, shallowRef(null));
// Menu
const menuShowing = ref(false);
@@ -119,7 +118,8 @@ const rangePercent = computed({
return (elapsedTimeMs.value / durationMs.value) || 0;
},
set: (to) => {
props.videoEl.currentTime = to * durationMs.value / 1000;
if (videoEl.value == null) return;
videoEl.value.currentTime = to * durationMs.value / 1000;
},
});
const volume = ref(.25);
@@ -127,17 +127,18 @@ const speed = ref(1);
const loop = ref(false); // TODO: ドライブファイルのフラグに置き換える
const bufferedEnd = ref(0);
const bufferedDataRatio = computed(() => {
return bufferedEnd.value / props.videoEl.duration;
if (videoEl.value == null || videoEl.value.duration === 0) return 0;
return bufferedEnd.value / videoEl.value.duration;
});
function togglePlayPause() {
if (!isReady.value) return;
if (isPlaying.value) {
props.videoEl.pause();
videoEl.value?.pause();
isPlaying.value = false;
} else {
props.videoEl.play();
videoEl.value?.play();
isPlaying.value = true;
oncePlayed.value = true;
}
@@ -147,7 +148,7 @@ function togglePictureInPicture() {
if (window.document.pictureInPictureElement) {
window.document.exitPictureInPicture();
} else {
props.videoEl.requestPictureInPicture();
videoEl.value?.requestPictureInPicture();
}
}
@@ -159,30 +160,32 @@ function toggleMute() {
}
}
let onceInit = false;
let abortController: AbortController | null = null;
let mediaTickFrameId: number | null = null;
function init() {
if (onceInit) return;
onceInit = true;
if (videoEl.value == null) return;
isReady.value = true;
abortController = new AbortController();
function updateMediaTick() {
if (videoEl.value == null) return;
try {
bufferedEnd.value = props.videoEl.buffered.end(0);
bufferedEnd.value = videoEl.value.buffered.end(0);
} catch (err) {
bufferedEnd.value = 0;
}
elapsedTimeMs.value = props.videoEl.currentTime * 1000;
elapsedTimeMs.value = videoEl.value.currentTime * 1000;
if (props.videoEl.loop !== loop.value) {
loop.value = props.videoEl.loop;
if (videoEl.value.loop !== loop.value) {
loop.value = videoEl.value.loop;
}
if (props.videoEl.paused !== !isPlaying.value) {
isPlaying.value = !props.videoEl.paused;
if (videoEl.value.paused !== !isPlaying.value) {
isPlaying.value = !videoEl.value.paused;
}
mediaTickFrameId = window.requestAnimationFrame(updateMediaTick);
@@ -190,54 +193,56 @@ function init() {
updateMediaTick();
props.videoEl.addEventListener('play', () => {
videoEl.value.addEventListener('play', () => {
isActuallyPlaying.value = true;
});
}, { signal: abortController.signal });
props.videoEl.addEventListener('pause', () => {
videoEl.value.addEventListener('pause', () => {
isActuallyPlaying.value = false;
isPlaying.value = false;
});
}, { signal: abortController.signal });
props.videoEl.addEventListener('ended', () => {
videoEl.value.addEventListener('ended', () => {
oncePlayed.value = false;
isActuallyPlaying.value = false;
isPlaying.value = false;
});
}, { signal: abortController.signal });
durationMs.value = props.videoEl.duration * 1000;
props.videoEl.addEventListener('durationchange', () => {
durationMs.value = props.videoEl.duration * 1000;
});
durationMs.value = videoEl.value.duration * 1000;
videoEl.value.addEventListener('durationchange', () => {
durationMs.value = videoEl.value!.duration * 1000;
}, { signal: abortController.signal });
props.videoEl.volume = volume.value;
hasAudio(props.videoEl).then(had => {
videoEl.value.volume = volume.value;
hasAudio(videoEl.value).then(had => {
if (!had) {
props.videoEl.loop = props.videoEl.muted = true;
props.videoEl.play();
videoEl.value!.loop = videoEl.value!.muted = true;
videoEl.value!.play();
}
});
}
watch(volume, (to) => {
props.videoEl.volume = to;
if (videoEl.value == null) return;
videoEl.value.volume = to;
});
watch(speed, (to) => {
props.videoEl.playbackRate = to;
if (videoEl.value == null) return;
videoEl.value.playbackRate = to;
});
watch(loop, (to) => {
props.videoEl.loop = to;
if (videoEl.value == null) return;
videoEl.value.loop = to;
});
onMounted(() => {
watch(videoEl, () => {
if (abortController != null) {
abortController.abort();
}
init();
});
onActivated(() => {
init();
});
}, { immediate: true });
onBeforeUnmount(() => {
if (mediaTickFrameId != null) {

View File

@@ -19,4 +19,5 @@ export const DI = {
inModal: Symbol() as InjectionKey<boolean>,
inAppSearchMarkerId: Symbol() as InjectionKey<Ref<string | null>>,
inChannel: Symbol() as InjectionKey<ComputedRef<string | null> | null>, // 現在開いているチャンネルのID
mkImageGalleryItemVideoEl: Symbol() as InjectionKey<Ref<HTMLVideoElement | null>>,
};