soiz1 commited on
Commit
cd9cb7b
·
verified ·
1 Parent(s): 8247010

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +398 -251
index.html CHANGED
@@ -1,5 +1,6 @@
1
  <!DOCTYPE html>
2
  <html lang="ja">
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <title>ラジオ体操動画プレイヤー</title>
@@ -7,9 +8,8 @@
7
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8
  <link href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c&display=swap" rel="stylesheet">
9
  <link rel="icon" href="icon.png" type="image/png">
10
-
11
- <style>
12
- body {
13
  display: flex;
14
  flex-direction: column;
15
  align-items: center;
@@ -290,11 +290,161 @@
290
  .video-container:-ms-fullscreen video::cue {
291
  font-size: calc(16px * var(--subtitle-scale) * var(--fullscreen-scale, 1)) !important;
292
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  </style>
294
  </head>
 
295
  <body>
296
- <h1>ラジオ体操動画プレイヤー<br>For Kushihara</h1>
297
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  <div class="controls">
299
  <div class="control-group">
300
  <label for="videoSelect">動画の音量:</label>
@@ -308,18 +458,15 @@
308
  <input type="range" id="speedRange" min="0.0001" max="20" step="0.0001" value="1" style="width:700px !important;">
309
  <input type="number" id="speedInput" min="0.0001" step="0.0001" value="1">
310
  </div>
311
-
312
  <div class="control-group">
313
  <label for="volumeRange">音量:</label>
314
  <input type="range" id="volumeRange" min="0" max="1" step="0.01" value="1">
315
  <input type="number" id="volumeInput" min="0" max="1" step="0.01" value="1">
316
  </div>
317
-
318
  <div class="control-group">
319
  <label for="loopCheckbox">ループ再生:</label>
320
  <input type="checkbox" id="loopCheckbox" checked>
321
  </div>
322
-
323
  <!-- 字幕設定セクション -->
324
  <div class="subtitle-settings">
325
  <div class="control-group">
@@ -339,17 +486,17 @@
339
  </select>
340
  </div>
341
  </div>
342
-
343
  <button onclick="goFullscreen()">全画面</button>
344
  </div>
345
-
346
  <div class="video-container">
347
  <video id="videoPlayer" src="v.mp4">
348
  <track id="subtitleTrackElement" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
 
349
  </video>
350
  <div class="custom-controls">
351
  <div class="progress-container" id="progressContainer">
352
- <div class="progress-bar" id="progressBar"></div>
 
353
  </div>
354
  <div class="buttons-container">
355
  <div class="left-controls">
@@ -367,260 +514,260 @@
367
  </div>
368
  </div>
369
  </div>
370
-
371
- <script>
372
  const video = document.getElementById('videoPlayer');
373
- const videoSelect = document.getElementById('videoSelect');
374
- const speedRange = document.getElementById('speedRange');
375
- const speedInput = document.getElementById('speedInput');
376
- const volumeRange = document.getElementById('volumeRange');
377
- const volumeInput = document.getElementById('volumeInput');
378
- const loopCheckbox = document.getElementById('loopCheckbox');
379
- const playPauseBtn = document.getElementById('playPauseBtn');
380
- const progressBar = document.getElementById('progressBar');
381
- const progressContainer = document.getElementById('progressContainer');
382
- const timeDisplay = document.getElementById('timeDisplay');
383
- const volumeBtn = document.getElementById('volumeBtn');
384
- const volumeSlider = document.getElementById('volumeSlider');
385
- const fullscreenBtn = document.getElementById('fullscreenBtn');
386
- const subtitleBtn = document.getElementById('subtitleBtn');
387
- const subtitleToggle = document.getElementById('subtitleToggle');
388
- const subtitleSize = document.getElementById('subtitleSize');
389
- const subtitleSizeInput = document.getElementById('subtitleSizeInput');
390
- const subtitleTrack = document.getElementById('subtitleTrack');
391
- const subtitleTrackElement = document.getElementById('subtitleTrackElement');
392
- const videoContainer = document.querySelector('.video-container');
393
-
394
- // 初期設定
395
- video.controls = false;
396
- let isDragging = false;
397
- let subtitlesEnabled = true;
398
- let normalVideoWidth = videoContainer.clientWidth;
399
-
400
- function updatePlaybackRate(value) {
401
- const speed = parseFloat(value);
402
- speedInput.value = speed;
403
- speedRange.value = speed;
404
- video.playbackRate = speed;
405
- }
406
-
407
- function updateVolume(value) {
408
- const volume = parseFloat(value);
409
- volumeInput.value = volume;
410
- volumeRange.value = volume;
411
- volumeSlider.value = volume;
412
- video.volume = volume;
413
-
414
- if (volume === 0) {
415
- volumeBtn.textContent = '🔇';
416
- } else if (volume < 0.5) {
417
- volumeBtn.textContent = '🔈';
418
- } else {
419
- volumeBtn.textContent = '🔊';
420
  }
421
- }
422
-
423
- function handleVideoChange() {
424
- const selected = videoSelect.value;
425
-
426
- if (selected === 'v-2.mp4') {
427
- const confirmPlay = confirm("この動画は音量が大きいです。あらかじめ、デバイスの音量をある程度下げてください。また、音割れが起きます。再生してもよろしいですか?");
428
- if (!confirmPlay) {
429
- videoSelect.value = video.src.split('/').pop();
430
- return;
 
 
 
 
431
  }
432
  }
433
-
434
- video.src = selected;
435
- video.load();
436
- video.play().then(() => {
437
- playPauseBtn.textContent = '';
438
- }).catch(e => console.log(e));
439
- }
440
-
441
- function togglePlayPause() {
442
- if (video.paused) {
443
- video.play();
444
- playPauseBtn.textContent = '⏸';
445
- } else {
446
- video.pause();
447
- playPauseBtn.textContent = '▶';
 
 
448
  }
449
- }
450
-
451
- function updateProgress() {
452
- const percent = (video.currentTime / video.duration) * 100;
453
- progressBar.style.width = `${percent}%`;
454
-
455
- const currentMinutes = Math.floor(video.currentTime / 60);
456
- const currentSeconds = Math.floor(video.currentTime % 60).toString().padStart(2, '0');
457
- const durationMinutes = Math.floor(video.duration / 60);
458
- const durationSeconds = Math.floor(video.duration % 60).toString().padStart(2, '0');
459
-
460
- timeDisplay.textContent = `${currentMinutes}:${currentSeconds} / ${durationMinutes}:${durationSeconds}`;
461
- }
462
-
463
- function setProgress(e) {
464
- const width = progressContainer.clientWidth;
465
- const clickX = e.offsetX;
466
- const duration = video.duration;
467
- video.currentTime = (clickX / width) * duration;
468
- }
469
-
470
- function toggleMute() {
471
- video.muted = !video.muted;
472
- if (video.muted) {
473
- volumeBtn.textContent = '🔇';
474
- volumeSlider.value = 0;
475
- } else {
476
- updateVolume(video.volume);
477
  }
478
- }
479
-
480
- function handleVolumeChange() {
481
- video.muted = false;
482
- updateVolume(volumeSlider.value);
483
- }
484
-
485
- function goFullscreen() {
486
- if (
487
- document.fullscreenElement ||
488
- document.webkitFullscreenElement ||
489
- document.msFullscreenElement
490
- ) {
491
- // フルスクリーンを解除
492
- if (document.exitFullscreen) {
493
- document.exitFullscreen();
494
- } else if (document.webkitExitFullscreen) {
495
- document.webkitExitFullscreen();
496
- } else if (document.msExitFullscreen) {
497
- document.msExitFullscreen();
498
- }
499
- } else {
500
- // フルスクリーンにする
501
- if (videoContainer.requestFullscreen) {
502
- videoContainer.requestFullscreen();
503
- } else if (videoContainer.webkitRequestFullscreen) {
504
- videoContainer.webkitRequestFullscreen();
505
- } else if (videoContainer.msRequestFullscreen) {
506
- videoContainer.msRequestFullscreen();
507
  }
508
- }
509
- }
510
-
511
-
512
- // 全画面変更時の字幕サイズ調整
513
- function updateSubtitleScaleForFullscreen() {
514
- if (document.fullscreenElement || document.webkitFullscreenElement ||
515
- document.mozFullScreenElement || document.msFullscreenElement) {
516
- // 全画面モード
517
- const fullscreenWidth = window.innerWidth;
518
- const scaleFactor = fullscreenWidth / normalVideoWidth;
519
- document.documentElement.style.setProperty('--fullscreen-scale', scaleFactor);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  } else {
521
- // 通常モード
522
- document.documentElement.style.setProperty('--fullscreen-scale', 1);
 
 
 
 
 
 
523
  }
524
  }
525
-
526
- // 字幕関連の関数
527
- function toggleSubtitles() {
528
- subtitlesEnabled = subtitleToggle.checked;
529
- subtitleTrackElement.track.mode = subtitlesEnabled ? 'showing' : 'hidden';
530
- subtitleBtn.style.color = subtitlesEnabled ? '#00ccff' : '#666';
531
- }
532
-
533
- function updateSubtitleSize(value) {
534
- const size = parseFloat(value);
535
- subtitleSizeInput.value = size;
536
- subtitleSize.value = size;
537
-
538
- // CSS変数で字幕サイズを制御
539
- document.documentElement.style.setProperty('--subtitle-scale', size);
540
-
541
- // VTTCueのlineプロパティには数値のみを設定('bottom'は無効)
542
- const track = subtitleTrackElement.track;
543
- if (track && track.cues) {
544
- for (let i = 0; i < track.cues.length; i++) {
545
- // 画面下部に表示するため、適切な数値を設定(例: 90)
546
- track.cues[i].line = 90;
547
- track.cues[i].snapToLines = false; // ラインスナップを無効に
548
  }
549
  }
550
- }
551
 
552
- function changeSubtitleTrack() {
553
- const selectedTrack = subtitleTrack.value;
554
- subtitleTrackElement.src = selectedTrack;
555
- subtitleTrackElement.track.mode = selectedTrack && subtitlesEnabled ? 'showing' : 'hidden';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
- // トラック変更後に再度読み込み
558
- video.textTracks[0].mode = 'hidden';
559
- if (selectedTrack) {
560
- video.textTracks[0].mode = subtitlesEnabled ? 'showing' : 'hidden';
 
 
 
 
 
 
561
  }
562
- }
563
-
564
- function toggleSubtitleMenu() {
565
- document.getElementById('subtitleToggle').checked ^= true;
566
- toggleSubtitles();
567
- }
568
-
569
- // イベントリスナー
570
- videoSelect.addEventListener('change', handleVideoChange);
571
-
572
- ['input', 'change', 'mouseup'].forEach(eventName => {
573
- speedRange.addEventListener(eventName, () => updatePlaybackRate(speedRange.value));
574
- volumeRange.addEventListener(eventName, () => updateVolume(volumeRange.value));
575
- subtitleSize.addEventListener(eventName, () => updateSubtitleSize(subtitleSize.value));
576
- });
577
-
578
- speedInput.addEventListener('input', () => updatePlaybackRate(speedInput.value));
579
- volumeInput.addEventListener('input', () => updateVolume(volumeInput.value));
580
- subtitleSizeInput.addEventListener('input', () => updateSubtitleSize(subtitleSizeInput.value));
581
-
582
- loopCheckbox.addEventListener('change', () => {
583
- video.loop = loopCheckbox.checked;
584
- });
585
-
586
- subtitleToggle.addEventListener('change', toggleSubtitles);
587
- subtitleTrack.addEventListener('change', changeSubtitleTrack);
588
- subtitleBtn.addEventListener('click', toggleSubtitleMenu);
589
-
590
- playPauseBtn.addEventListener('click', togglePlayPause);
591
- video.addEventListener('click', togglePlayPause);
592
- video.addEventListener('play', () => playPauseBtn.textContent = '');
593
- video.addEventListener('pause', () => playPauseBtn.textContent = '▶');
594
- video.addEventListener('timeupdate', updateProgress);
595
- progressContainer.addEventListener('click', setProgress);
596
- progressContainer.addEventListener('mousedown', () => isDragging = true);
597
- document.addEventListener('mouseup', () => isDragging = false);
598
- progressContainer.addEventListener('mousemove', (e) => isDragging && setProgress(e));
599
- volumeBtn.addEventListener('click', toggleMute);
600
- volumeSlider.addEventListener('input', handleVolumeChange);
601
- fullscreenBtn.addEventListener('click', goFullscreen);
602
-
603
- // 全画面変更イベントを監視
604
- document.addEventListener('fullscreenchange', updateSubtitleScaleForFullscreen);
605
- document.addEventListener('webkitfullscreenchange', updateSubtitleScaleForFullscreen);
606
- document.addEventListener('mozfullscreenchange', updateSubtitleScaleForFullscreen);
607
- document.addEventListener('MSFullscreenChange', updateSubtitleScaleForFullscreen);
608
-
609
- video.addEventListener('loadedmetadata', () => {
610
- updatePlaybackRate(speedRange.value);
611
- updateVolume(volumeRange.value);
612
- updateSubtitleSize(subtitleSize.value);
613
- video.loop = loopCheckbox.checked;
614
- toggleSubtitles();
615
- updateProgress();
616
- // 通常時の動画幅を記録
617
- normalVideoWidth = videoContainer.clientWidth;
618
- });
619
-
620
- // CSS変数を設定
621
- document.documentElement.style.setProperty('--subtitle-scale', '1');
622
- document.documentElement.style.setProperty('--subtitle-border-radius', '10px');
623
- document.documentElement.style.setProperty('--fullscreen-scale', '1');
624
- </script>
625
  </body>
 
626
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="ja">
3
+
4
  <head>
5
  <meta charset="UTF-8">
6
  <title>ラジオ体操動画プレイヤー</title>
 
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
  <link href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c&display=swap" rel="stylesheet">
10
  <link rel="icon" href="icon.png" type="image/png">
11
+ <style>
12
+ body {
 
13
  display: flex;
14
  flex-direction: column;
15
  align-items: center;
 
290
  .video-container:-ms-fullscreen video::cue {
291
  font-size: calc(16px * var(--subtitle-scale) * var(--fullscreen-scale, 1)) !important;
292
  }
293
+ body {
294
+ margin: 0;
295
+ padding: 0;
296
+ overflow: hidden;
297
+ background-color: #0a192f; /* 暗い青 */
298
+ height: 100vh;
299
+ width: 100vw;
300
+ }
301
+
302
+ .ripple {
303
+ position: absolute;
304
+ border-radius: 50%;
305
+ background: transparent;
306
+ border: 1px solid rgba(100, 210, 255, 0.3); /* 半透明の薄い水色 */
307
+ transform: translate(-50%, -50%);
308
+ pointer-events: none;
309
+ animation: ripple-animation 4s ease-out forwards;
310
+ z-index: 1;
311
+ }
312
+
313
+ @keyframes ripple-animation {
314
+ 0% {
315
+ width: 0;
316
+ height: 0;
317
+ opacity: 0.6;
318
+ }
319
+ 100% {
320
+ width: 600px;
321
+ height: 600px;
322
+ opacity: 0;
323
+ }
324
+ }
325
  </style>
326
  </head>
327
+
328
  <body>
329
+ <div id="ripple-container">
330
+ </div>
331
+ <script>
332
+ document.addEventListener('DOMContentLoaded', function() {
333
+ const container = document.getElementById('ripple-container');
334
+
335
+ function createRipple() {
336
+ const ripple = document.createElement('div');
337
+ ripple.classList.add('ripple');
338
+
339
+ // ランダムな位置
340
+ const posX = Math.random() * 100;
341
+ const posY = Math.random() * 100;
342
+
343
+ // ランダムなサイズとアニメーション時間
344
+ const maxSize = 400 + Math.random() * 500;
345
+ const duration = 3 + Math.random() * 3;
346
+
347
+ // 半透明の薄い水色のバリエーション
348
+ const hue = 190 + Math.random() * 20 - 10; // 水色を中心に少し変化
349
+ const saturation = 80 + Math.random() * 15;
350
+ const lightness = 70 + Math.random() * 20;
351
+ const opacity = 0.3 + Math.random() * 0.3;
352
+
353
+ ripple.style.left = `${posX}%`;
354
+ ripple.style.top = `${posY}%`;
355
+ ripple.style.borderColor = `hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity})`;
356
+ ripple.style.animationDuration = `${duration}s`;
357
+
358
+ // キーフレームを動的に変更
359
+ const animationName = `ripple-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
360
+ ripple.style.animationName = animationName;
361
+
362
+ const style = document.createElement('style');
363
+ style.innerHTML = `
364
+ @keyframes ${animationName} {
365
+ 0% {
366
+ width: 0;
367
+ height: 0;
368
+ opacity: ${opacity};
369
+ }
370
+ 100% {
371
+ width: ${maxSize}px;
372
+ height: ${maxSize}px;
373
+ opacity: 0;
374
+ }
375
+ }
376
+ `;
377
+ document.head.appendChild(style);
378
+
379
+ container.appendChild(ripple);
380
+
381
+ // アニメーション終了後に要素を削除
382
+ ripple.addEventListener('animationend', function() {
383
+ ripple.remove();
384
+ style.remove();
385
+ });
386
+ }
387
+
388
+ // 最初の波紋をいくつか作成
389
+ for (let i = 0; i < 8; i++) {
390
+ setTimeout(createRipple, i * 600);
391
+ }
392
+
393
+ // 定期的に新しい波紋を作成
394
+ setInterval(createRipple, 1200);
395
+
396
+ // クリックでも波紋を作成
397
+ document.addEventListener('click', function(e) {
398
+ createRippleAtPosition(e.clientX, e.clientY);
399
+ });
400
+
401
+ function createRippleAtPosition(x, y) {
402
+ const ripple = document.createElement('div');
403
+ ripple.classList.add('ripple');
404
+
405
+ const maxSize = 400 + Math.random() * 500;
406
+ const duration = 3 + Math.random() * 3;
407
+ const hue = 190 + Math.random() * 20 - 10;
408
+ const saturation = 80 + Math.random() * 15;
409
+ const lightness = 70 + Math.random() * 20;
410
+ const opacity = 0.3 + Math.random() * 0.3;
411
+
412
+ ripple.style.left = `${x}px`;
413
+ ripple.style.top = `${y}px`;
414
+ ripple.style.borderColor = `hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity})`;
415
+ ripple.style.animationDuration = `${duration}s`;
416
+
417
+ const animationName = `ripple-click-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
418
+ ripple.style.animationName = animationName;
419
+
420
+ const style = document.createElement('style');
421
+ style.innerHTML = `
422
+ @keyframes ${animationName} {
423
+ 0% {
424
+ width: 0;
425
+ height: 0;
426
+ opacity: ${opacity};
427
+ }
428
+ 100% {
429
+ width: ${maxSize}px;
430
+ height: ${maxSize}px;
431
+ opacity: 0;
432
+ }
433
+ }
434
+ `;
435
+ document.head.appendChild(style);
436
+
437
+ container.appendChild(ripple);
438
+
439
+ ripple.addEventListener('animationend', function() {
440
+ ripple.remove();
441
+ style.remove();
442
+ });
443
+ }
444
+ });
445
+ </script>
446
+ <h1>ラジオ体操動画プレイヤー
447
+ <br>For Kushihara</h1>
448
  <div class="controls">
449
  <div class="control-group">
450
  <label for="videoSelect">動画の音量:</label>
 
458
  <input type="range" id="speedRange" min="0.0001" max="20" step="0.0001" value="1" style="width:700px !important;">
459
  <input type="number" id="speedInput" min="0.0001" step="0.0001" value="1">
460
  </div>
 
461
  <div class="control-group">
462
  <label for="volumeRange">音量:</label>
463
  <input type="range" id="volumeRange" min="0" max="1" step="0.01" value="1">
464
  <input type="number" id="volumeInput" min="0" max="1" step="0.01" value="1">
465
  </div>
 
466
  <div class="control-group">
467
  <label for="loopCheckbox">ループ再生:</label>
468
  <input type="checkbox" id="loopCheckbox" checked>
469
  </div>
 
470
  <!-- 字幕設定セクション -->
471
  <div class="subtitle-settings">
472
  <div class="control-group">
 
486
  </select>
487
  </div>
488
  </div>
 
489
  <button onclick="goFullscreen()">全画面</button>
490
  </div>
 
491
  <div class="video-container">
492
  <video id="videoPlayer" src="v.mp4">
493
  <track id="subtitleTrackElement" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
494
+ </track>
495
  </video>
496
  <div class="custom-controls">
497
  <div class="progress-container" id="progressContainer">
498
+ <div class="progress-bar" id="progressBar">
499
+ </div>
500
  </div>
501
  <div class="buttons-container">
502
  <div class="left-controls">
 
514
  </div>
515
  </div>
516
  </div>
517
+ <script>
 
518
  const video = document.getElementById('videoPlayer');
519
+ const videoSelect = document.getElementById('videoSelect');
520
+ const speedRange = document.getElementById('speedRange');
521
+ const speedInput = document.getElementById('speedInput');
522
+ const volumeRange = document.getElementById('volumeRange');
523
+ const volumeInput = document.getElementById('volumeInput');
524
+ const loopCheckbox = document.getElementById('loopCheckbox');
525
+ const playPauseBtn = document.getElementById('playPauseBtn');
526
+ const progressBar = document.getElementById('progressBar');
527
+ const progressContainer = document.getElementById('progressContainer');
528
+ const timeDisplay = document.getElementById('timeDisplay');
529
+ const volumeBtn = document.getElementById('volumeBtn');
530
+ const volumeSlider = document.getElementById('volumeSlider');
531
+ const fullscreenBtn = document.getElementById('fullscreenBtn');
532
+ const subtitleBtn = document.getElementById('subtitleBtn');
533
+ const subtitleToggle = document.getElementById('subtitleToggle');
534
+ const subtitleSize = document.getElementById('subtitleSize');
535
+ const subtitleSizeInput = document.getElementById('subtitleSizeInput');
536
+ const subtitleTrack = document.getElementById('subtitleTrack');
537
+ const subtitleTrackElement = document.getElementById('subtitleTrackElement');
538
+ const videoContainer = document.querySelector('.video-container');
539
+
540
+ // 初期設定
541
+ video.controls = false;
542
+ let isDragging = false;
543
+ let subtitlesEnabled = true;
544
+ let normalVideoWidth = videoContainer.clientWidth;
545
+
546
+ function updatePlaybackRate(value) {
547
+ const speed = parseFloat(value);
548
+ speedInput.value = speed;
549
+ speedRange.value = speed;
550
+ video.playbackRate = speed;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  }
552
+
553
+ function updateVolume(value) {
554
+ const volume = parseFloat(value);
555
+ volumeInput.value = volume;
556
+ volumeRange.value = volume;
557
+ volumeSlider.value = volume;
558
+ video.volume = volume;
559
+
560
+ if (volume === 0) {
561
+ volumeBtn.textContent = '🔇';
562
+ } else if (volume < 0.5) {
563
+ volumeBtn.textContent = '🔈';
564
+ } else {
565
+ volumeBtn.textContent = '🔊';
566
  }
567
  }
568
+
569
+ function handleVideoChange() {
570
+ const selected = videoSelect.value;
571
+
572
+ if (selected === 'v-2.mp4') {
573
+ const confirmPlay = confirm("この動画は音量が大きいです。あらかじめ、デバイスの音量をある程度下げてください。また、音割れが起きます。再生してもよろしいですか?");
574
+ if (!confirmPlay) {
575
+ videoSelect.value = video.src.split('/').pop();
576
+ return;
577
+ }
578
+ }
579
+
580
+ video.src = selected;
581
+ video.load();
582
+ video.play().then(() => {
583
+ playPauseBtn.textContent = '⏸';
584
+ }).catch(e => console.log(e));
585
  }
586
+
587
+ function togglePlayPause() {
588
+ if (video.paused) {
589
+ video.play();
590
+ playPauseBtn.textContent = '⏸';
591
+ } else {
592
+ video.pause();
593
+ playPauseBtn.textContent = '';
594
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
  }
596
+
597
+ function updateProgress() {
598
+ const percent = (video.currentTime / video.duration) * 100;
599
+ progressBar.style.width = `${percent}%`;
600
+
601
+ const currentMinutes = Math.floor(video.currentTime / 60);
602
+ const currentSeconds = Math.floor(video.currentTime % 60).toString().padStart(2, '0');
603
+ const durationMinutes = Math.floor(video.duration / 60);
604
+ const durationSeconds = Math.floor(video.duration % 60).toString().padStart(2, '0');
605
+
606
+ timeDisplay.textContent = `${currentMinutes}:${currentSeconds} / ${durationMinutes}:${durationSeconds}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  }
608
+
609
+ function setProgress(e) {
610
+ const width = progressContainer.clientWidth;
611
+ const clickX = e.offsetX;
612
+ const duration = video.duration;
613
+ video.currentTime = (clickX / width) * duration;
614
+ }
615
+
616
+ function toggleMute() {
617
+ video.muted = !video.muted;
618
+ if (video.muted) {
619
+ volumeBtn.textContent = '🔇';
620
+ volumeSlider.value = 0;
621
+ } else {
622
+ updateVolume(video.volume);
623
+ }
624
+ }
625
+
626
+ function handleVolumeChange() {
627
+ video.muted = false;
628
+ updateVolume(volumeSlider.value);
629
+ }
630
+
631
+ function goFullscreen() {
632
+ if (
633
+ document.fullscreenElement ||
634
+ document.webkitFullscreenElement ||
635
+ document.msFullscreenElement
636
+ ) {
637
+ // フルスクリーンを解除
638
+ if (document.exitFullscreen) {
639
+ document.exitFullscreen();
640
+ } else if (document.webkitExitFullscreen) {
641
+ document.webkitExitFullscreen();
642
+ } else if (document.msExitFullscreen) {
643
+ document.msExitFullscreen();
644
+ }
645
  } else {
646
+ // フルスクリーンにする
647
+ if (videoContainer.requestFullscreen) {
648
+ videoContainer.requestFullscreen();
649
+ } else if (videoContainer.webkitRequestFullscreen) {
650
+ videoContainer.webkitRequestFullscreen();
651
+ } else if (videoContainer.msRequestFullscreen) {
652
+ videoContainer.msRequestFullscreen();
653
+ }
654
  }
655
  }
656
+
657
+
658
+ // 全画面変更時の字幕サイズ調整
659
+ function updateSubtitleScaleForFullscreen() {
660
+ if (document.fullscreenElement || document.webkitFullscreenElement ||
661
+ document.mozFullScreenElement || document.msFullscreenElement) {
662
+ // 全画面モード
663
+ const fullscreenWidth = window.innerWidth;
664
+ const scaleFactor = fullscreenWidth / normalVideoWidth;
665
+ document.documentElement.style.setProperty('--fullscreen-scale', scaleFactor);
666
+ } else {
667
+ // 通常モード
668
+ document.documentElement.style.setProperty('--fullscreen-scale', 1);
 
 
 
 
 
 
 
 
 
 
669
  }
670
  }
 
671
 
672
+ // 字幕関連の関数
673
+ function toggleSubtitles() {
674
+ subtitlesEnabled = subtitleToggle.checked;
675
+ subtitleTrackElement.track.mode = subtitlesEnabled ? 'showing' : 'hidden';
676
+ subtitleBtn.style.color = subtitlesEnabled ? '#00ccff' : '#666';
677
+ }
678
+
679
+ function updateSubtitleSize(value) {
680
+ const size = parseFloat(value);
681
+ subtitleSizeInput.value = size;
682
+ subtitleSize.value = size;
683
+
684
+ // CSS変数で字幕サイズを制御
685
+ document.documentElement.style.setProperty('--subtitle-scale', size);
686
+
687
+ // VTTCueのlineプロパティには数値のみを設定('bottom'は無効)
688
+ const track = subtitleTrackElement.track;
689
+ if (track && track.cues) {
690
+ for (let i = 0; i < track.cues.length; i++) {
691
+ // 画面下部に表示するため、適切な数値を設定(例: 90)
692
+ track.cues[i].line = 90;
693
+ track.cues[i].snapToLines = false; // ラインスナップを無効に
694
+ }
695
+ }
696
+ }
697
 
698
+ function changeSubtitleTrack() {
699
+ const selectedTrack = subtitleTrack.value;
700
+ subtitleTrackElement.src = selectedTrack;
701
+ subtitleTrackElement.track.mode = selectedTrack && subtitlesEnabled ? 'showing' : 'hidden';
702
+
703
+ // トラック変更後に再度読み込み
704
+ video.textTracks[0].mode = 'hidden';
705
+ if (selectedTrack) {
706
+ video.textTracks[0].mode = subtitlesEnabled ? 'showing' : 'hidden';
707
+ }
708
  }
709
+
710
+ function toggleSubtitleMenu() {
711
+ document.getElementById('subtitleToggle').checked ^= true;
712
+ toggleSubtitles();
713
+ }
714
+
715
+ // イベントリスナー
716
+ videoSelect.addEventListener('change', handleVideoChange);
717
+
718
+ ['input', 'change', 'mouseup'].forEach(eventName => {
719
+ speedRange.addEventListener(eventName, () => updatePlaybackRate(speedRange.value));
720
+ volumeRange.addEventListener(eventName, () => updateVolume(volumeRange.value));
721
+ subtitleSize.addEventListener(eventName, () => updateSubtitleSize(subtitleSize.value));
722
+ });
723
+
724
+ speedInput.addEventListener('input', () => updatePlaybackRate(speedInput.value));
725
+ volumeInput.addEventListener('input', () => updateVolume(volumeInput.value));
726
+ subtitleSizeInput.addEventListener('input', () => updateSubtitleSize(subtitleSizeInput.value));
727
+
728
+ loopCheckbox.addEventListener('change', () => {
729
+ video.loop = loopCheckbox.checked;
730
+ });
731
+
732
+ subtitleToggle.addEventListener('change', toggleSubtitles);
733
+ subtitleTrack.addEventListener('change', changeSubtitleTrack);
734
+ subtitleBtn.addEventListener('click', toggleSubtitleMenu);
735
+
736
+ playPauseBtn.addEventListener('click', togglePlayPause);
737
+ video.addEventListener('click', togglePlayPause);
738
+ video.addEventListener('play', () => playPauseBtn.textContent = '⏸');
739
+ video.addEventListener('pause', () => playPauseBtn.textContent = '');
740
+ video.addEventListener('timeupdate', updateProgress);
741
+ progressContainer.addEventListener('click', setProgress);
742
+ progressContainer.addEventListener('mousedown', () => isDragging = true);
743
+ document.addEventListener('mouseup', () => isDragging = false);
744
+ progressContainer.addEventListener('mousemove', (e) => isDragging && setProgress(e));
745
+ volumeBtn.addEventListener('click', toggleMute);
746
+ volumeSlider.addEventListener('input', handleVolumeChange);
747
+ fullscreenBtn.addEventListener('click', goFullscreen);
748
+
749
+ // 全画面変更イベントを監視
750
+ document.addEventListener('fullscreenchange', updateSubtitleScaleForFullscreen);
751
+ document.addEventListener('webkitfullscreenchange', updateSubtitleScaleForFullscreen);
752
+ document.addEventListener('mozfullscreenchange', updateSubtitleScaleForFullscreen);
753
+ document.addEventListener('MSFullscreenChange', updateSubtitleScaleForFullscreen);
754
+
755
+ video.addEventListener('loadedmetadata', () => {
756
+ updatePlaybackRate(speedRange.value);
757
+ updateVolume(volumeRange.value);
758
+ updateSubtitleSize(subtitleSize.value);
759
+ video.loop = loopCheckbox.checked;
760
+ toggleSubtitles();
761
+ updateProgress();
762
+ // 通常時の動画幅を記録
763
+ normalVideoWidth = videoContainer.clientWidth;
764
+ });
765
+
766
+ // CSS変数を設定
767
+ document.documentElement.style.setProperty('--subtitle-scale', '1');
768
+ document.documentElement.style.setProperty('--subtitle-border-radius', '10px');
769
+ document.documentElement.style.setProperty('--fullscreen-scale', '1');
770
+ </script>
 
771
  </body>
772
+
773
  </html>