soiz1 commited on
Commit
a951a50
·
verified ·
1 Parent(s): d7e11fc

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +154 -283
index.html CHANGED
@@ -420,20 +420,18 @@
420
  }
421
 
422
  /* フレームプレビュー */
423
- .frame-preview {
424
- position: absolute;
425
- bottom: 50px; /* プログレスバーの上に表示 */
426
- transform: translateX(-50%);
427
- width: 160px;
428
- height: 90px;
429
- background: #000;
430
- border: 2px solid #00aaff;
431
- box-shadow: 0 0 10px rgba(0, 170, 255, 0.7);
432
- display: none;
433
- z-index: 1000; /* 高いz-indexを設定 */
434
- pointer-events: none;
435
- }
436
-
437
 
438
  .frame-preview img {
439
  width: 100%;
@@ -460,7 +458,7 @@
460
  background-color: #0f0f1a;
461
  border: 1px solid #0066ff;
462
  box-shadow: 0 0 15px rgba(0, 102, 255, 0.5);
463
- z-index: 2147483647 !important;
464
  display: none;
465
  min-width: 200px;
466
  }
@@ -591,10 +589,6 @@
591
  <track id="subtitleTrackElement" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
592
  </track>
593
  </video>
594
- <div class="preview-container" id="previewContainer">
595
- <img id="preview" style="max-width: 200px; max-height: 150px;">
596
- <div class="preview-time" id="previewTime"></div>
597
- </div>
598
  <div class="custom-controls">
599
  <div class="progress-container" id="progressContainer">
600
  <div class="progress-bar" id="progressBar">
@@ -616,8 +610,7 @@
616
  </div>
617
  </div>
618
  </div>
619
- <canvas id="canvas">
620
- </canvas>
621
  <!-- サムネイル用の非表示video要素 -->
622
  <video id="video-for-thumbnail" src="v.mp4" preload="auto" style="display:none;"></video>
623
  <script>
@@ -647,9 +640,6 @@
647
  const frameTime = document.getElementById('frameTime');
648
  const audioOnlyModeIndicator = document.getElementById('audioOnlyModeIndicator');
649
  const contextMenu = document.getElementById('contextMenu');
650
- const previewContainer = document.getElementById('previewContainer');
651
- const preview = document.getElementById('preview');
652
- const previewTime = document.getElementById('previewTime');
653
  const VideoForThumbnail = document.getElementById('video-for-thumbnail');
654
  const canvas = document.getElementById('canvas');
655
  const ctx = canvas.getContext('2d');
@@ -801,98 +791,87 @@
801
  }
802
  hideContextMenu();
803
  }
804
- function setupFullscreenContextMenu() {
805
- const fullscreenElement = document.fullscreenElement ||
806
- document.webkitFullscreenElement ||
807
- document.msFullscreenElement;
808
-
809
- if (fullscreenElement) {
810
- fullscreenElement.addEventListener('contextmenu', showContextMenu);
811
- }
812
- }
813
- function updateSubtitleScaleForFullscreen() {
814
- if (document.fullscreenElement || document.webkitFullscreenElement ||
815
- document.mozFullScreenElement || document.msFullscreenElement) {
816
- // 全画面モード
817
- const fullscreenWidth = window.innerWidth;
818
- const scaleFactor = fullscreenWidth / normalVideoWidth;
819
- document.documentElement.style.setProperty('--fullscreen-scale', scaleFactor);
820
-
821
- // 全画面要素にイベントリスナーを追加
822
- const fsElement = document.fullscreenElement || document.webkitFullscreenElement ||
823
- document.mozFullScreenElement || document.msFullscreenElement;
824
- fsElement.addEventListener('contextmenu', showContextMenu);
825
- } else {
826
- // 通常モード
827
- document.documentElement.style.setProperty('--fullscreen-scale', 1);
828
- }
829
- }
830
- function setupFramePreview() {
831
- let previewTimeout;
832
-
833
- progressContainer.addEventListener('mousemove', (e) => {
834
- if (!videoBlob || !video.duration) return;
835
-
836
- clearTimeout(previewTimeout);
837
 
838
- const progressRect = progressContainer.getBoundingClientRect();
839
- const clickX = Math.max(0, Math.min(e.clientX - progressRect.left, progressRect.width));
840
- const previewTime = (clickX / progressRect.width) * video.duration;
841
-
842
- // 時間表示を更新
843
- const previewMinutes = Math.floor(previewTime / 60);
844
- const previewSeconds = Math.floor(previewTime % 60).toString().padStart(2, '0');
845
- frameTime.textContent = `${previewMinutes}:${previewSeconds}`;
846
-
847
- // プレビュー位置を更新(プログレスバーの上に表示)
848
- framePreview.style.left = `${e.clientX - 80}px`; // 中央寄せ
849
- framePreview.style.bottom = `${progressContainer.offsetHeight + 10}px`;
850
- framePreview.style.display = 'block';
851
-
852
- // キャッシュがあればそれを使う
853
- const cacheKey = Math.floor(previewTime);
854
- if (frameCache[cacheKey]) {
855
- previewImage.src = frameCache[cacheKey];
856
- return;
857
  }
858
 
859
- // フレームを取得
860
- VideoForThumbnail.currentTime = previewTime;
861
-
862
- const onSeeked = () => {
863
- if (VideoForThumbnail.readyState >= 2) { // HAVE_CURRENT_DATA 以上か確認
864
- canvas.width = VideoForThumbnail.videoWidth || 160;
865
- canvas.height = VideoForThumbnail.videoHeight || 90;
866
- ctx.drawImage(VideoForThumbnail, 0, 0, canvas.width, canvas.height);
 
 
 
 
 
 
 
 
867
 
868
- try {
869
- const imageData = canvas.toDataURL('image/jpeg');
870
- previewImage.src = imageData;
871
- frameCache[cacheKey] = imageData;
872
- } catch (e) {
873
- console.error("Failed to generate preview image:", e);
 
 
 
 
874
  }
875
- }
876
- VideoForThumbnail.removeEventListener('seeked', onSeeked);
877
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
878
 
879
- VideoForThumbnail.addEventListener('seeked', onSeeked);
880
- });
881
-
882
- progressContainer.addEventListener('mouseleave', () => {
883
- previewTimeout = setTimeout(() => {
884
- framePreview.style.display = 'none';
885
- }, 300);
886
- });
887
-
888
- framePreview.addEventListener('mouseenter', () => {
889
- clearTimeout(previewTimeout);
890
- });
891
-
892
- framePreview.addEventListener('mouseleave', () => {
893
- framePreview.style.display = 'none';
894
- });
895
- }
896
  // 字幕関連の関数
897
  function toggleSubtitles() {
898
  subtitlesEnabled = !subtitlesEnabled;
@@ -937,73 +916,29 @@ function setupFramePreview() {
937
  toggleSubtitles();
938
  }
939
 
940
- // フレームプレビュー関連
941
- function showFramePreview(e) {
942
- if (!videoBlob) return;
943
-
944
- const progressRect = progressContainer.getBoundingClientRect();
945
- const clickX = e.clientX - progressRect.left;
946
- const duration = video.duration;
947
- const previewTime = (clickX / progressRect.width) * duration;
948
-
949
- // 時間表示を更新
950
- const previewMinutes = Math.floor(previewTime / 60);
951
- const previewSeconds = Math.floor(previewTime % 60).toString().padStart(2, '0');
952
- frameTime.textContent = `${previewMinutes}:${previewSeconds}`;
953
-
954
- // プレビュー位置を更新
955
- framePreview.style.left = `${e.clientX}px`;
956
- framePreview.style.display = 'block';
957
-
958
- // キャッシュがあればそれを使う
959
- const cacheKey = Math.floor(previewTime);
960
- if (frameCache[cacheKey]) {
961
- previewImage.src = frameCache[cacheKey];
962
- return;
963
- }
964
-
965
- // フレームを取得
966
- videoFrames({
967
- url: URL.createObjectURL(videoBlob),
968
- count: 1,
969
- startTime: previewTime,
970
- endTime: previewTime + 0.1
971
- }).then((frames) => {
972
- if (frames.length > 0) {
973
- previewImage.src = frames[0].image;
974
- frameCache[cacheKey] = frames[0].image; // キャッシュに保存
975
  }
976
- }).catch(err => {
977
- console.error('Error getting video frame:', err);
978
- });
979
  }
980
 
981
- function hideFramePreview() {
982
- framePreview.style.display = 'none';
983
- }
984
-
985
- // 右クリックメニュー関連
986
- function showContextMenu(e) {
987
- e.preventDefault();
988
-
989
- // メニューの位置を計算
990
- const x = e.clientX || e.touches?.[0]?.clientX;
991
- const y = e.clientY || e.touches?.[0]?.clientY;
992
-
993
- if (!x || !y) return;
994
-
995
- contextMenu.style.display = 'block';
996
- contextMenu.style.left = `${x}px`;
997
- contextMenu.style.top = `${y}px`;
998
-
999
- // 全画面時は document にイベントリスナーを追加
1000
- if (document.fullscreenElement) {
1001
- document.addEventListener('click', hideContextMenu);
1002
- }
1003
- }
1004
-
1005
  function hideContextMenu() {
1006
- contextMenu.style.display = 'none';
 
1007
  }
1008
 
1009
  // 音声/字幕のみモード
@@ -1050,77 +985,29 @@ function showContextMenu(e) {
1050
  progressContainer.addEventListener('click', setProgress);
1051
  progressContainer.addEventListener('mousedown', () => isDragging = true);
1052
  document.addEventListener('mouseup', () => isDragging = false);
1053
- // マウスホバー時のプレビュー表示
1054
- progressContainer.addEventListener('mousemove', function(e) {
1055
- if (isDragging) {
1056
- const width = progressContainer.clientWidth;
1057
- const clickX = e.offsetX;
1058
- const duration = video.duration;
1059
- const previewTime = (clickX / width) * duration;
1060
-
1061
- // プレビュー位置を更新
1062
- previewContainer.style.left = `${e.clientX - 100}px`;
1063
- previewContainer.style.bottom = '60px';
1064
- previewContainer.style.display = 'block';
1065
-
1066
- // 時間表示を更新
1067
- const minutes = Math.floor(previewTime / 60);
1068
- const seconds = Math.floor(previewTime % 60).toString().padStart(2, '0');
1069
- document.getElementById('previewTime').textContent = `${minutes}:${seconds}`;
1070
-
1071
- // サムネイル画像を更新
1072
- updateThumbnail(previewTime);
1073
- } else {
1074
- previewContainer.style.display = 'none';
1075
- }
1076
- });
1077
-
1078
- // サムネイル画像更新関数
1079
- function updateThumbnail(time) {
1080
- VideoForThumbnail.currentTime = time;
1081
-
1082
- VideoForThumbnail.addEventListener('seeked', function() {
1083
- canvas.width = VideoForThumbnail.videoWidth;
1084
- canvas.height = VideoForThumbnail.videoHeight;
1085
- ctx.drawImage(VideoForThumbnail, 0, 0, canvas.width, canvas.height);
1086
- preview.src = canvas.toDataURL('image/jpeg');
1087
- }, { once: true });
1088
- }
1089
-
1090
-
1091
- // プログレスバーのホバーイベント
1092
- progressContainer.addEventListener('mouseenter', () => {
1093
- isHoveringProgress = true;
1094
- clearTimeout(hoverTimeout);
1095
- });
1096
-
1097
- progressContainer.addEventListener('mouseleave', () => {
1098
- isHoveringProgress = false;
1099
- hoverTimeout = setTimeout(() => {
1100
- if (!isDragging) hideFramePreview();
1101
- }, 300);
1102
- });
1103
 
1104
  volumeBtn.addEventListener('click', toggleMute);
1105
  volumeSlider.addEventListener('input', handleVolumeChange);
1106
  fullscreenBtn.addEventListener('click', goFullscreen);
1107
 
1108
  // 全画面変更イベントを監視
1109
- document.addEventListener('fullscreenchange', updateFullscreenEventListeners);
1110
- document.addEventListener('webkitfullscreenchange', updateFullscreenEventListeners);
1111
- document.addEventListener('mozfullscreenchange', updateFullscreenEventListeners);
1112
- document.addEventListener('MSFullscreenChange', updateFullscreenEventListeners);
1113
 
1114
- function updateFullscreenEventListeners() {
1115
- if (document.fullscreenElement) {
1116
- // 全画面時は document にイベントリスナーを設定
1117
- document.addEventListener('contextmenu', showContextMenu);
1118
- } else {
1119
- // 通常時は videoContainer に戻す
1120
- videoContainer.addEventListener('contextmenu', showContextMenu);
1121
- document.removeEventListener('contextmenu', showContextMenu);
1122
- }
1123
- }
 
 
1124
 
1125
  // 右クリックメニューイベント
1126
  videoContainer.addEventListener('contextmenu', showContextMenu);
@@ -1138,53 +1025,37 @@ function updateFullscreenEventListeners() {
1138
  updateProgress();
1139
  normalVideoWidth = videoContainer.clientWidth;
1140
  });
 
1141
  video.addEventListener("loadeddata", async () => {
1142
- const response = await fetch(video.src);
1143
- videoBlob = await response.blob();
1144
- });
1145
-
1146
- // 保存
1147
- video.addEventListener('timeupdate', () => {
1148
- localStorage.setItem('radioTaisoTime', video.currentTime);
1149
- });
1150
-
1151
- // 復元
1152
- window.addEventListener('load', () => {
1153
- setupFramePreview();
1154
- setupFullscreenContextMenu();
1155
- const savedTime = parseFloat(localStorage.getItem('radioTaisoTime'));
1156
- if (!isNaN(savedTime)) {
1157
- video.currentTime = savedTime;
1158
- }
1159
-
1160
- document.addEventListener('fullscreenchange', () => {
1161
- updateSubtitleScaleForFullscreen();
1162
- setupFullscreenContextMenu();
1163
- });
1164
- document.addEventListener('webkitfullscreenchange', () => {
1165
- updateSubtitleScaleForFullscreen();
1166
- setupFullscreenContextMenu();
1167
- });
1168
- document.addEventListener('mozfullscreenchange', () => {
1169
- updateSubtitleScaleForFullscreen();
1170
- setupFullscreenContextMenu();
1171
- });
1172
- document.addEventListener('MSFullscreenChange', () => {
1173
- updateSubtitleScaleForFullscreen();
1174
- setupFullscreenContextMenu();
1175
- });
1176
- });
1177
- document.addEventListener('keydown', (e) => {
1178
- if (e.target.tagName === 'INPUT') return; // 入力中は無視
1179
- switch (e.key.toLowerCase()) {
1180
- case ' ': e.preventDefault(); togglePlayPause(); break;
1181
- case 'f': goFullscreen(); break;
1182
- case 'm': toggleMute(); break;
1183
- case 'arrowright': video.currentTime += 5; break;
1184
- case 'arrowleft': video.currentTime -= 5; break;
1185
- }
1186
- });
1187
-
1188
  // CSS変数を設定
1189
  document.documentElement.style.setProperty('--subtitle-scale', '1');
1190
  document.documentElement.style.setProperty('--subtitle-border-radius', '10px');
 
420
  }
421
 
422
  /* フレームプレビュー */
423
+ .frame-preview {
424
+ position: fixed;
425
+ width: 160px;
426
+ height: 90px;
427
+ background: #000;
428
+ border: 2px solid #00aaff;
429
+ box-shadow: 0 0 10px rgba(0, 170, 255, 0.7);
430
+ display: none;
431
+ z-index: 2147483646;
432
+ pointer-events: none;
433
+ transform: translateX(-50%);
434
+ }
 
 
435
 
436
  .frame-preview img {
437
  width: 100%;
 
458
  background-color: #0f0f1a;
459
  border: 1px solid #0066ff;
460
  box-shadow: 0 0 15px rgba(0, 102, 255, 0.5);
461
+ z-index: 2147483647;
462
  display: none;
463
  min-width: 200px;
464
  }
 
589
  <track id="subtitleTrackElement" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
590
  </track>
591
  </video>
 
 
 
 
592
  <div class="custom-controls">
593
  <div class="progress-container" id="progressContainer">
594
  <div class="progress-bar" id="progressBar">
 
610
  </div>
611
  </div>
612
  </div>
613
+ <canvas id="canvas" style="display:none;"></canvas>
 
614
  <!-- サムネイル用の非表示video要素 -->
615
  <video id="video-for-thumbnail" src="v.mp4" preload="auto" style="display:none;"></video>
616
  <script>
 
640
  const frameTime = document.getElementById('frameTime');
641
  const audioOnlyModeIndicator = document.getElementById('audioOnlyModeIndicator');
642
  const contextMenu = document.getElementById('contextMenu');
 
 
 
643
  const VideoForThumbnail = document.getElementById('video-for-thumbnail');
644
  const canvas = document.getElementById('canvas');
645
  const ctx = canvas.getContext('2d');
 
791
  }
792
  hideContextMenu();
793
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
 
795
+ function updateSubtitleScaleForFullscreen() {
796
+ if (document.fullscreenElement || document.webkitFullscreenElement ||
797
+ document.mozFullScreenElement || document.msFullscreenElement) {
798
+ // 全画面モード
799
+ const fullscreenWidth = window.innerWidth;
800
+ const scaleFactor = fullscreenWidth / normalVideoWidth;
801
+ document.documentElement.style.setProperty('--fullscreen-scale', scaleFactor);
802
+ } else {
803
+ // 通常モード
804
+ document.documentElement.style.setProperty('--fullscreen-scale', 1);
805
+ }
 
 
 
 
 
 
 
 
806
  }
807
 
808
+ function setupFramePreview() {
809
+ let previewTimeout;
810
+
811
+ progressContainer.addEventListener('mousemove', (e) => {
812
+ if (!videoBlob || !video.duration) return;
813
+
814
+ clearTimeout(previewTimeout);
815
+
816
+ const progressRect = progressContainer.getBoundingClientRect();
817
+ const clickX = Math.max(0, Math.min(e.clientX - progressRect.left, progressRect.width));
818
+ const previewTime = (clickX / progressRect.width) * video.duration;
819
+
820
+ // 時間表示を更新
821
+ const previewMinutes = Math.floor(previewTime / 60);
822
+ const previewSeconds = Math.floor(previewTime % 60).toString().padStart(2, '0');
823
+ frameTime.textContent = `${previewMinutes}:${previewSeconds}`;
824
 
825
+ // プレビュー位置を更新(プログレスバーの上に表示)
826
+ framePreview.style.left = `${e.clientX}px`;
827
+ framePreview.style.top = `${progressRect.top - 100}px`; // プログレスバーの上に表示
828
+ framePreview.style.display = 'block';
829
+
830
+ // キャッシュがあればそれを使う
831
+ const cacheKey = Math.floor(previewTime);
832
+ if (frameCache[cacheKey]) {
833
+ previewImage.src = frameCache[cacheKey];
834
+ return;
835
  }
836
+
837
+ // フレームを取得
838
+ VideoForThumbnail.currentTime = previewTime;
839
+
840
+ const onSeeked = () => {
841
+ if (VideoForThumbnail.readyState >= 2) { // HAVE_CURRENT_DATA 以上か確認
842
+ canvas.width = VideoForThumbnail.videoWidth || 160;
843
+ canvas.height = VideoForThumbnail.videoHeight || 90;
844
+ ctx.drawImage(VideoForThumbnail, 0, 0, canvas.width, canvas.height);
845
+
846
+ try {
847
+ const imageData = canvas.toDataURL('image/jpeg');
848
+ previewImage.src = imageData;
849
+ frameCache[cacheKey] = imageData;
850
+ } catch (e) {
851
+ console.error("Failed to generate preview image:", e);
852
+ }
853
+ }
854
+ VideoForThumbnail.removeEventListener('seeked', onSeeked);
855
+ };
856
+
857
+ VideoForThumbnail.addEventListener('seeked', onSeeked);
858
+ });
859
+
860
+ progressContainer.addEventListener('mouseleave', () => {
861
+ previewTimeout = setTimeout(() => {
862
+ framePreview.style.display = 'none';
863
+ }, 300);
864
+ });
865
+
866
+ framePreview.addEventListener('mouseenter', () => {
867
+ clearTimeout(previewTimeout);
868
+ });
869
+
870
+ framePreview.addEventListener('mouseleave', () => {
871
+ framePreview.style.display = 'none';
872
+ });
873
+ }
874
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
  // 字幕関連の関数
876
  function toggleSubtitles() {
877
  subtitlesEnabled = !subtitlesEnabled;
 
916
  toggleSubtitles();
917
  }
918
 
919
+ // 右クリックメニュー関連
920
+ function showContextMenu(e) {
921
+ e.preventDefault();
922
+
923
+ // メニューの位置を計算
924
+ const x = e.clientX || e.touches?.[0]?.clientX;
925
+ const y = e.clientY || e.touches?.[0]?.clientY;
926
+
927
+ if (!x || !y) return;
928
+
929
+ contextMenu.style.display = 'block';
930
+ contextMenu.style.left = `${x}px`;
931
+ contextMenu.style.top = `${y}px`;
932
+
933
+ // 全画面時は document にイベントリスナーを追加
934
+ if (document.fullscreenElement) {
935
+ document.addEventListener('click', hideContextMenu);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
936
  }
 
 
 
937
  }
938
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939
  function hideContextMenu() {
940
+ contextMenu.style.display = 'none';
941
+ document.removeEventListener('click', hideContextMenu);
942
  }
943
 
944
  // 音声/字幕のみモード
 
985
  progressContainer.addEventListener('click', setProgress);
986
  progressContainer.addEventListener('mousedown', () => isDragging = true);
987
  document.addEventListener('mouseup', () => isDragging = false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
988
 
989
  volumeBtn.addEventListener('click', toggleMute);
990
  volumeSlider.addEventListener('input', handleVolumeChange);
991
  fullscreenBtn.addEventListener('click', goFullscreen);
992
 
993
  // 全画面変更イベントを監視
994
+ document.addEventListener('fullscreenchange', updateFullscreenEventListeners);
995
+ document.addEventListener('webkitfullscreenchange', updateFullscreenEventListeners);
996
+ document.addEventListener('mozfullscreenchange', updateFullscreenEventListeners);
997
+ document.addEventListener('MSFullscreenChange', updateFullscreenEventListeners);
998
 
999
+ function updateFullscreenEventListeners() {
1000
+ updateSubtitleScaleForFullscreen();
1001
+ if (document.fullscreenElement) {
1002
+ // 全画面時は document にイベントリスナーを設定
1003
+ document.addEventListener('contextmenu', showContextMenu);
1004
+ videoContainer.removeEventListener('contextmenu', showContextMenu);
1005
+ } else {
1006
+ // 通常時は videoContainer に戻す
1007
+ videoContainer.addEventListener('contextmenu', showContextMenu);
1008
+ document.removeEventListener('contextmenu', showContextMenu);
1009
+ }
1010
+ }
1011
 
1012
  // 右クリックメニューイベント
1013
  videoContainer.addEventListener('contextmenu', showContextMenu);
 
1025
  updateProgress();
1026
  normalVideoWidth = videoContainer.clientWidth;
1027
  });
1028
+
1029
  video.addEventListener("loadeddata", async () => {
1030
+ const response = await fetch(video.src);
1031
+ videoBlob = await response.blob();
1032
+ });
1033
+
1034
+ // 保存
1035
+ video.addEventListener('timeupdate', () => {
1036
+ localStorage.setItem('radioTaisoTime', video.currentTime);
1037
+ });
1038
+
1039
+ // 復元
1040
+ window.addEventListener('load', () => {
1041
+ setupFramePreview();
1042
+ const savedTime = parseFloat(localStorage.getItem('radioTaisoTime'));
1043
+ if (!isNaN(savedTime)) {
1044
+ video.currentTime = savedTime;
1045
+ }
1046
+ });
1047
+
1048
+ document.addEventListener('keydown', (e) => {
1049
+ if (e.target.tagName === 'INPUT') return; // 入力中は無視
1050
+ switch (e.key.toLowerCase()) {
1051
+ case ' ': e.preventDefault(); togglePlayPause(); break;
1052
+ case 'f': goFullscreen(); break;
1053
+ case 'm': toggleMute(); break;
1054
+ case 'arrowright': video.currentTime += 5; break;
1055
+ case 'arrowleft': video.currentTime -= 5; break;
1056
+ }
1057
+ });
1058
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1059
  // CSS変数を設定
1060
  document.documentElement.style.setProperty('--subtitle-scale', '1');
1061
  document.documentElement.style.setProperty('--subtitle-border-radius', '10px');