From d60f645d1dc731d7ef6eff16081d2b5615412690 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Sun, 26 Nov 2023 16:15:24 +0900
Subject: [PATCH] chore(frontend/MkMediaVideo): loop and autoplay silent videos
 (#12392)

---
 packages/frontend/src/components/MkMediaVideo.vue | 7 +++++++
 packages/frontend/src/scripts/media-has-audio.ts  | 9 +++++++++
 2 files changed, 16 insertions(+)
 create mode 100644 packages/frontend/src/scripts/media-has-audio.ts

diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index 43c64b4c85..b6e8f1ff22 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -37,6 +37,7 @@ import * as Misskey from 'misskey-js';
 import bytes from '@/filters/bytes.js';
 import { defaultStore } from '@/store.js';
 import { i18n } from '@/i18n.js';
+import hasAudio from '@/scripts/media-has-audio.js';
 
 const props = defineProps<{
 	video: Misskey.entities.DriveFile;
@@ -49,6 +50,12 @@ const videoEl = shallowRef<HTMLVideoElement>();
 watch(videoEl, () => {
 	if (videoEl.value) {
 		videoEl.value.volume = 0.3;
+		hasAudio(videoEl.value).then(had => {
+			if (!had) {
+				videoEl.value.loop = videoEl.value.muted = true;
+				videoEl.value.play();
+			}
+		});
 	}
 });
 </script>
diff --git a/packages/frontend/src/scripts/media-has-audio.ts b/packages/frontend/src/scripts/media-has-audio.ts
new file mode 100644
index 0000000000..3421a38a76
--- /dev/null
+++ b/packages/frontend/src/scripts/media-has-audio.ts
@@ -0,0 +1,9 @@
+export default async function hasAudio(media: HTMLMediaElement) {
+	const cloned = media.cloneNode() as HTMLMediaElement;
+	cloned.muted = (cloned as typeof cloned & Partial<HTMLVideoElement>).playsInline = true;
+	cloned.play();
+	await new Promise((resolve) => cloned.addEventListener('playing', resolve));
+	const result = !!(cloned as any).audioTracks?.length || (cloned as any).mozHasAudio || !!(cloned as any).webkitAudioDecodedByteCount;
+	cloned.remove();
+	return result;
+}