Spaces:
Running
Running
Update index.html
Browse files- index.html +54 -82
index.html
CHANGED
@@ -39,18 +39,12 @@
|
|
39 |
}
|
40 |
|
41 |
/* 字幕スタイル */
|
42 |
-
::cue {
|
43 |
-
color:
|
44 |
-
|
45 |
-
text-shadow: 0 0 5px #0066ff;
|
46 |
font-family: 'Courier New', monospace;
|
47 |
-
|
48 |
-
|
49 |
-
}
|
50 |
-
|
51 |
-
::cue(b) {
|
52 |
-
color: #00aaff;
|
53 |
-
text-shadow: 0 0 7px #0066ff;
|
54 |
}
|
55 |
|
56 |
/* カスタム動画コントロール */
|
@@ -262,10 +256,12 @@
|
|
262 |
transform: translate(-50%, -50%);
|
263 |
}
|
264 |
|
265 |
-
|
|
|
266 |
margin-top: 10px;
|
267 |
-
padding
|
268 |
-
|
|
|
269 |
}
|
270 |
</style>
|
271 |
</head>
|
@@ -297,25 +293,22 @@
|
|
297 |
<input type="checkbox" id="loopCheckbox" checked>
|
298 |
</div>
|
299 |
|
300 |
-
|
|
|
301 |
<div class="control-group">
|
302 |
<label for="subtitleToggle">字幕表示:</label>
|
303 |
<input type="checkbox" id="subtitleToggle" checked>
|
304 |
</div>
|
305 |
<div class="control-group">
|
306 |
-
<label for="subtitleSize"
|
307 |
-
<input type="range" id="subtitleSize" min="
|
308 |
-
<input type="number" id="subtitleSizeInput" min="
|
309 |
</div>
|
310 |
<div class="control-group">
|
311 |
-
<label for="
|
312 |
-
<select id="
|
313 |
-
<option value="
|
314 |
-
<option value="
|
315 |
-
<option value="#00ff00">緑</option>
|
316 |
-
<option value="#ffff00">黄</option>
|
317 |
-
<option value="#ff00ff">マゼンタ</option>
|
318 |
-
<option value="#ffffff">白</option>
|
319 |
</select>
|
320 |
</div>
|
321 |
</div>
|
@@ -325,7 +318,7 @@
|
|
325 |
|
326 |
<div class="video-container">
|
327 |
<video id="videoPlayer" src="v.mp4">
|
328 |
-
<track id="
|
329 |
</video>
|
330 |
<div class="custom-controls">
|
331 |
<div class="progress-container" id="progressContainer">
|
@@ -363,17 +356,17 @@
|
|
363 |
const volumeBtn = document.getElementById('volumeBtn');
|
364 |
const volumeSlider = document.getElementById('volumeSlider');
|
365 |
const fullscreenBtn = document.getElementById('fullscreenBtn');
|
|
|
366 |
const subtitleToggle = document.getElementById('subtitleToggle');
|
367 |
const subtitleSize = document.getElementById('subtitleSize');
|
368 |
const subtitleSizeInput = document.getElementById('subtitleSizeInput');
|
369 |
-
const subtitleColor = document.getElementById('subtitleColor');
|
370 |
-
const subtitleBtn = document.getElementById('subtitleBtn');
|
371 |
const subtitleTrack = document.getElementById('subtitleTrack');
|
|
|
372 |
|
373 |
// 初期設定
|
374 |
video.controls = false;
|
375 |
let isDragging = false;
|
376 |
-
let
|
377 |
|
378 |
function updatePlaybackRate(value) {
|
379 |
const speed = parseFloat(value);
|
@@ -389,7 +382,6 @@
|
|
389 |
volumeSlider.value = volume;
|
390 |
video.volume = volume;
|
391 |
|
392 |
-
// 音量ボタンのアイコン更新
|
393 |
if (volume === 0) {
|
394 |
volumeBtn.textContent = '🔇';
|
395 |
} else if (volume < 0.5) {
|
@@ -431,7 +423,6 @@
|
|
431 |
const percent = (video.currentTime / video.duration) * 100;
|
432 |
progressBar.style.width = `${percent}%`;
|
433 |
|
434 |
-
// 時間表示更新
|
435 |
const currentMinutes = Math.floor(video.currentTime / 60);
|
436 |
const currentSeconds = Math.floor(video.currentTime % 60).toString().padStart(2, '0');
|
437 |
const durationMinutes = Math.floor(video.duration / 60);
|
@@ -475,60 +466,41 @@
|
|
475 |
|
476 |
// 字幕関連の関数
|
477 |
function toggleSubtitles() {
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
for (let i = 0; i < video.textTracks.length; i++) {
|
482 |
-
video.textTracks[i].mode = subtitlesVisible ? 'showing' : 'hidden';
|
483 |
-
}
|
484 |
-
|
485 |
-
subtitleBtn.textContent = subtitlesVisible ? '📝' : '📝✖';
|
486 |
}
|
487 |
|
488 |
function updateSubtitleSize(value) {
|
489 |
-
const size =
|
490 |
subtitleSizeInput.value = size;
|
491 |
subtitleSize.value = size;
|
|
|
492 |
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
}
|
499 |
-
|
500 |
-
document.head.appendChild(styleElement);
|
501 |
}
|
502 |
|
503 |
-
function
|
504 |
-
const
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
text-shadow: 0 0 7px ${color} !important;
|
514 |
-
}
|
515 |
-
`;
|
516 |
-
document.head.appendChild(styleElement);
|
517 |
}
|
518 |
|
519 |
-
function
|
520 |
-
const
|
521 |
-
|
522 |
-
const R = (num >> 16) + amt;
|
523 |
-
const G = (num >> 8 & 0x00FF) + amt;
|
524 |
-
const B = (num & 0x0000FF) + amt;
|
525 |
-
|
526 |
-
return '#' + (
|
527 |
-
0x1000000 +
|
528 |
-
(R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
|
529 |
-
(G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
|
530 |
-
(B < 255 ? (B < 1 ? 0 : B) : 255)
|
531 |
-
).toString(16).slice(1);
|
532 |
}
|
533 |
|
534 |
// イベントリスナー
|
@@ -543,14 +515,14 @@
|
|
543 |
speedInput.addEventListener('input', () => updatePlaybackRate(speedInput.value));
|
544 |
volumeInput.addEventListener('input', () => updateVolume(volumeInput.value));
|
545 |
subtitleSizeInput.addEventListener('input', () => updateSubtitleSize(subtitleSizeInput.value));
|
546 |
-
subtitleColor.addEventListener('change', () => updateSubtitleColor(subtitleColor.value));
|
547 |
|
548 |
loopCheckbox.addEventListener('change', () => {
|
549 |
video.loop = loopCheckbox.checked;
|
550 |
});
|
551 |
|
552 |
subtitleToggle.addEventListener('change', toggleSubtitles);
|
553 |
-
|
|
|
554 |
|
555 |
playPauseBtn.addEventListener('click', togglePlayPause);
|
556 |
video.addEventListener('click', togglePlayPause);
|
@@ -568,14 +540,14 @@
|
|
568 |
video.addEventListener('loadedmetadata', () => {
|
569 |
updatePlaybackRate(speedRange.value);
|
570 |
updateVolume(volumeRange.value);
|
571 |
-
video.loop = loopCheckbox.checked;
|
572 |
-
updateProgress();
|
573 |
-
|
574 |
-
// 字幕の初期設定
|
575 |
updateSubtitleSize(subtitleSize.value);
|
576 |
-
|
577 |
toggleSubtitles();
|
|
|
578 |
});
|
|
|
|
|
|
|
579 |
</script>
|
580 |
</body>
|
581 |
</html>
|
|
|
39 |
}
|
40 |
|
41 |
/* 字幕スタイル */
|
42 |
+
video::cue {
|
43 |
+
background-color: rgba(0, 0, 0, 0.7);
|
44 |
+
color: #c7dbed;
|
|
|
45 |
font-family: 'Courier New', monospace;
|
46 |
+
text-shadow: 1px 1px 2px #000;
|
47 |
+
outline: 1px solid #0b3e8f;
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
/* カスタム動画コントロール */
|
|
|
256 |
transform: translate(-50%, -50%);
|
257 |
}
|
258 |
|
259 |
+
/* 字幕設定用スタイル */
|
260 |
+
.subtitle-settings {
|
261 |
margin-top: 10px;
|
262 |
+
padding: 10px;
|
263 |
+
background-color: rgba(0, 20, 40, 0.5);
|
264 |
+
border: 1px solid #0066ff;
|
265 |
}
|
266 |
</style>
|
267 |
</head>
|
|
|
293 |
<input type="checkbox" id="loopCheckbox" checked>
|
294 |
</div>
|
295 |
|
296 |
+
<!-- 字幕設定セクション -->
|
297 |
+
<div class="subtitle-settings">
|
298 |
<div class="control-group">
|
299 |
<label for="subtitleToggle">字幕表示:</label>
|
300 |
<input type="checkbox" id="subtitleToggle" checked>
|
301 |
</div>
|
302 |
<div class="control-group">
|
303 |
+
<label for="subtitleSize">文字サイズ:</label>
|
304 |
+
<input type="range" id="subtitleSize" min="0.5" max="2" step="0.1" value="1">
|
305 |
+
<input type="number" id="subtitleSizeInput" min="0.5" max="2" step="0.1" value="1">
|
306 |
</div>
|
307 |
<div class="control-group">
|
308 |
+
<label for="subtitleTrack">字幕トラック:</label>
|
309 |
+
<select id="subtitleTrack">
|
310 |
+
<option value="v.vtt">日本語</option>
|
311 |
+
<option value="">字幕なし</option>
|
|
|
|
|
|
|
|
|
312 |
</select>
|
313 |
</div>
|
314 |
</div>
|
|
|
318 |
|
319 |
<div class="video-container">
|
320 |
<video id="videoPlayer" src="v.mp4">
|
321 |
+
<track id="subtitleTrackElement" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
|
322 |
</video>
|
323 |
<div class="custom-controls">
|
324 |
<div class="progress-container" id="progressContainer">
|
|
|
356 |
const volumeBtn = document.getElementById('volumeBtn');
|
357 |
const volumeSlider = document.getElementById('volumeSlider');
|
358 |
const fullscreenBtn = document.getElementById('fullscreenBtn');
|
359 |
+
const subtitleBtn = document.getElementById('subtitleBtn');
|
360 |
const subtitleToggle = document.getElementById('subtitleToggle');
|
361 |
const subtitleSize = document.getElementById('subtitleSize');
|
362 |
const subtitleSizeInput = document.getElementById('subtitleSizeInput');
|
|
|
|
|
363 |
const subtitleTrack = document.getElementById('subtitleTrack');
|
364 |
+
const subtitleTrackElement = document.getElementById('subtitleTrackElement');
|
365 |
|
366 |
// 初期設定
|
367 |
video.controls = false;
|
368 |
let isDragging = false;
|
369 |
+
let subtitlesEnabled = true;
|
370 |
|
371 |
function updatePlaybackRate(value) {
|
372 |
const speed = parseFloat(value);
|
|
|
382 |
volumeSlider.value = volume;
|
383 |
video.volume = volume;
|
384 |
|
|
|
385 |
if (volume === 0) {
|
386 |
volumeBtn.textContent = '🔇';
|
387 |
} else if (volume < 0.5) {
|
|
|
423 |
const percent = (video.currentTime / video.duration) * 100;
|
424 |
progressBar.style.width = `${percent}%`;
|
425 |
|
|
|
426 |
const currentMinutes = Math.floor(video.currentTime / 60);
|
427 |
const currentSeconds = Math.floor(video.currentTime % 60).toString().padStart(2, '0');
|
428 |
const durationMinutes = Math.floor(video.duration / 60);
|
|
|
466 |
|
467 |
// 字幕関連の関数
|
468 |
function toggleSubtitles() {
|
469 |
+
subtitlesEnabled = subtitleToggle.checked;
|
470 |
+
subtitleTrackElement.track.mode = subtitlesEnabled ? 'showing' : 'hidden';
|
471 |
+
subtitleBtn.style.color = subtitlesEnabled ? '#00ccff' : '#666';
|
|
|
|
|
|
|
|
|
|
|
472 |
}
|
473 |
|
474 |
function updateSubtitleSize(value) {
|
475 |
+
const size = parseFloat(value);
|
476 |
subtitleSizeInput.value = size;
|
477 |
subtitleSize.value = size;
|
478 |
+
video.style.setProperty('--subtitle-scale', size);
|
479 |
|
480 |
+
// 字幕サイズを動的に変更
|
481 |
+
const track = subtitleTrackElement.track;
|
482 |
+
if (track && track.cues) {
|
483 |
+
for (let i = 0; i < track.cues.length; i++) {
|
484 |
+
track.cues[i].size = 100 * size; // サイズをパーセンテージで設定
|
485 |
}
|
486 |
+
}
|
|
|
487 |
}
|
488 |
|
489 |
+
function changeSubtitleTrack() {
|
490 |
+
const selectedTrack = subtitleTrack.value;
|
491 |
+
subtitleTrackElement.src = selectedTrack;
|
492 |
+
subtitleTrackElement.track.mode = selectedTrack && subtitlesEnabled ? 'showing' : 'hidden';
|
493 |
+
|
494 |
+
// トラック変更後に再度読み込み
|
495 |
+
video.textTracks[0].mode = 'hidden';
|
496 |
+
if (selectedTrack) {
|
497 |
+
video.textTracks[0].mode = subtitlesEnabled ? 'showing' : 'hidden';
|
498 |
+
}
|
|
|
|
|
|
|
|
|
499 |
}
|
500 |
|
501 |
+
function toggleSubtitleMenu() {
|
502 |
+
const subtitleSettings = document.querySelector('.subtitle-settings');
|
503 |
+
subtitleSettings.style.display = subtitleSettings.style.display === 'none' ? 'block' : 'none';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
}
|
505 |
|
506 |
// イベントリスナー
|
|
|
515 |
speedInput.addEventListener('input', () => updatePlaybackRate(speedInput.value));
|
516 |
volumeInput.addEventListener('input', () => updateVolume(volumeInput.value));
|
517 |
subtitleSizeInput.addEventListener('input', () => updateSubtitleSize(subtitleSizeInput.value));
|
|
|
518 |
|
519 |
loopCheckbox.addEventListener('change', () => {
|
520 |
video.loop = loopCheckbox.checked;
|
521 |
});
|
522 |
|
523 |
subtitleToggle.addEventListener('change', toggleSubtitles);
|
524 |
+
subtitleTrack.addEventListener('change', changeSubtitleTrack);
|
525 |
+
subtitleBtn.addEventListener('click', toggleSubtitleMenu);
|
526 |
|
527 |
playPauseBtn.addEventListener('click', togglePlayPause);
|
528 |
video.addEventListener('click', togglePlayPause);
|
|
|
540 |
video.addEventListener('loadedmetadata', () => {
|
541 |
updatePlaybackRate(speedRange.value);
|
542 |
updateVolume(volumeRange.value);
|
|
|
|
|
|
|
|
|
543 |
updateSubtitleSize(subtitleSize.value);
|
544 |
+
video.loop = loopCheckbox.checked;
|
545 |
toggleSubtitles();
|
546 |
+
updateProgress();
|
547 |
});
|
548 |
+
|
549 |
+
// CSS変数を設定
|
550 |
+
document.documentElement.style.setProperty('--subtitle-scale', '1');
|
551 |
</script>
|
552 |
</body>
|
553 |
</html>
|