Spaces:
Running
Running
Update index.html
Browse files- index.html +125 -2
index.html
CHANGED
@@ -26,7 +26,7 @@
|
|
26 |
.video-container {
|
27 |
position: relative;
|
28 |
max-width: 800px;
|
29 |
-
margin
|
30 |
border: 2px solid #0066ff;
|
31 |
box-shadow: 0 0 15px rgba(0, 102, 255, 0.5);
|
32 |
background: #000;
|
@@ -37,6 +37,30 @@
|
|
37 |
display: block;
|
38 |
}
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
/* カスタム動画コントロール */
|
41 |
video::-webkit-media-controls {
|
42 |
display: none !important;
|
@@ -53,6 +77,7 @@
|
|
53 |
flex-direction: column;
|
54 |
opacity: 0;
|
55 |
transition: opacity 0.3s;
|
|
|
56 |
}
|
57 |
|
58 |
.video-container:hover .custom-controls {
|
@@ -270,6 +295,11 @@
|
|
270 |
<input type="number" id="volumeInput" min="0" max="1" step="0.01" value="1">
|
271 |
</div>
|
272 |
|
|
|
|
|
|
|
|
|
|
|
273 |
<div class="control-group">
|
274 |
<label for="loopCheckbox">ループ再生:</label>
|
275 |
<input type="checkbox" id="loopCheckbox" checked>
|
@@ -279,7 +309,12 @@
|
|
279 |
</div>
|
280 |
|
281 |
<div class="video-container">
|
282 |
-
<video id="videoPlayer" src="v.mp4"
|
|
|
|
|
|
|
|
|
|
|
283 |
<div class="custom-controls">
|
284 |
<div class="progress-container" id="progressContainer">
|
285 |
<div class="progress-bar" id="progressBar"></div>
|
@@ -308,6 +343,7 @@
|
|
308 |
const volumeRange = document.getElementById('volumeRange');
|
309 |
const volumeInput = document.getElementById('volumeInput');
|
310 |
const loopCheckbox = document.getElementById('loopCheckbox');
|
|
|
311 |
const playPauseBtn = document.getElementById('playPauseBtn');
|
312 |
const progressBar = document.getElementById('progressBar');
|
313 |
const progressContainer = document.getElementById('progressContainer');
|
@@ -315,10 +351,84 @@
|
|
315 |
const volumeBtn = document.getElementById('volumeBtn');
|
316 |
const volumeSlider = document.getElementById('volumeSlider');
|
317 |
const fullscreenBtn = document.getElementById('fullscreenBtn');
|
|
|
|
|
|
|
318 |
|
319 |
// 初期設定
|
320 |
video.controls = false;
|
321 |
let isDragging = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
|
323 |
function updatePlaybackRate(value) {
|
324 |
const speed = parseFloat(value);
|
@@ -383,6 +493,9 @@
|
|
383 |
const durationSeconds = Math.floor(video.duration % 60).toString().padStart(2, '0');
|
384 |
|
385 |
timeDisplay.textContent = `${currentMinutes}:${currentSeconds} / ${durationMinutes}:${durationSeconds}`;
|
|
|
|
|
|
|
386 |
}
|
387 |
|
388 |
function setProgress(e) {
|
@@ -407,6 +520,13 @@
|
|
407 |
updateVolume(volumeSlider.value);
|
408 |
}
|
409 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
410 |
function goFullscreen() {
|
411 |
const container = document.querySelector('.video-container');
|
412 |
if (container.requestFullscreen) {
|
@@ -433,6 +553,8 @@
|
|
433 |
video.loop = loopCheckbox.checked;
|
434 |
});
|
435 |
|
|
|
|
|
436 |
playPauseBtn.addEventListener('click', togglePlayPause);
|
437 |
video.addEventListener('click', togglePlayPause);
|
438 |
video.addEventListener('play', () => playPauseBtn.textContent = '⏸');
|
@@ -451,6 +573,7 @@
|
|
451 |
updateVolume(volumeRange.value);
|
452 |
video.loop = loopCheckbox.checked;
|
453 |
updateProgress();
|
|
|
454 |
});
|
455 |
</script>
|
456 |
</body>
|
|
|
26 |
.video-container {
|
27 |
position: relative;
|
28 |
max-width: 800px;
|
29 |
+
margin: 30px 0 20px 0;
|
30 |
border: 2px solid #0066ff;
|
31 |
box-shadow: 0 0 15px rgba(0, 102, 255, 0.5);
|
32 |
background: #000;
|
|
|
37 |
display: block;
|
38 |
}
|
39 |
|
40 |
+
/* 字幕スタイル */
|
41 |
+
.caption-container {
|
42 |
+
position: absolute;
|
43 |
+
bottom: 60px;
|
44 |
+
left: 0;
|
45 |
+
right: 0;
|
46 |
+
text-align: center;
|
47 |
+
padding: 10px;
|
48 |
+
z-index: 10;
|
49 |
+
}
|
50 |
+
|
51 |
+
.caption-text {
|
52 |
+
display: inline-block;
|
53 |
+
background-color: rgba(0, 0, 0, 0.7);
|
54 |
+
color: #00ffcc;
|
55 |
+
font-family: 'Courier New', monospace;
|
56 |
+
font-size: 18px;
|
57 |
+
padding: 8px 15px;
|
58 |
+
border-radius: 4px;
|
59 |
+
border: 1px solid #0066ff;
|
60 |
+
text-shadow: 0 0 5px #0066ff;
|
61 |
+
max-width: 80%;
|
62 |
+
}
|
63 |
+
|
64 |
/* カスタム動画コントロール */
|
65 |
video::-webkit-media-controls {
|
66 |
display: none !important;
|
|
|
77 |
flex-direction: column;
|
78 |
opacity: 0;
|
79 |
transition: opacity 0.3s;
|
80 |
+
z-index: 5;
|
81 |
}
|
82 |
|
83 |
.video-container:hover .custom-controls {
|
|
|
295 |
<input type="number" id="volumeInput" min="0" max="1" step="0.01" value="1">
|
296 |
</div>
|
297 |
|
298 |
+
<div class="control-group">
|
299 |
+
<label for="captionCheckbox">字幕表示:</label>
|
300 |
+
<input type="checkbox" id="captionCheckbox" checked>
|
301 |
+
</div>
|
302 |
+
|
303 |
<div class="control-group">
|
304 |
<label for="loopCheckbox">ループ再生:</label>
|
305 |
<input type="checkbox" id="loopCheckbox" checked>
|
|
|
309 |
</div>
|
310 |
|
311 |
<div class="video-container">
|
312 |
+
<video id="videoPlayer" src="v.mp4">
|
313 |
+
<track id="captionTrack" kind="subtitles" src="v.vtt" srclang="ja" label="日本語" default>
|
314 |
+
</video>
|
315 |
+
<div class="caption-container" id="captionContainer">
|
316 |
+
<div class="caption-text" id="captionText"></div>
|
317 |
+
</div>
|
318 |
<div class="custom-controls">
|
319 |
<div class="progress-container" id="progressContainer">
|
320 |
<div class="progress-bar" id="progressBar"></div>
|
|
|
343 |
const volumeRange = document.getElementById('volumeRange');
|
344 |
const volumeInput = document.getElementById('volumeInput');
|
345 |
const loopCheckbox = document.getElementById('loopCheckbox');
|
346 |
+
const captionCheckbox = document.getElementById('captionCheckbox');
|
347 |
const playPauseBtn = document.getElementById('playPauseBtn');
|
348 |
const progressBar = document.getElementById('progressBar');
|
349 |
const progressContainer = document.getElementById('progressContainer');
|
|
|
351 |
const volumeBtn = document.getElementById('volumeBtn');
|
352 |
const volumeSlider = document.getElementById('volumeSlider');
|
353 |
const fullscreenBtn = document.getElementById('fullscreenBtn');
|
354 |
+
const captionContainer = document.getElementById('captionContainer');
|
355 |
+
const captionText = document.getElementById('captionText');
|
356 |
+
const captionTrack = document.getElementById('captionTrack');
|
357 |
|
358 |
// 初期設定
|
359 |
video.controls = false;
|
360 |
let isDragging = false;
|
361 |
+
let captions = [];
|
362 |
+
let activeCaption = null;
|
363 |
+
|
364 |
+
// 字幕データを読み込む
|
365 |
+
function loadCaptions() {
|
366 |
+
fetch('v.vtt')
|
367 |
+
.then(response => response.text())
|
368 |
+
.then(data => {
|
369 |
+
const lines = data.split('\n');
|
370 |
+
captions = [];
|
371 |
+
let currentCaption = null;
|
372 |
+
|
373 |
+
for (let i = 0; i < lines.length; i++) {
|
374 |
+
const line = lines[i].trim();
|
375 |
+
|
376 |
+
if (line.includes('-->')) {
|
377 |
+
if (currentCaption) {
|
378 |
+
captions.push(currentCaption);
|
379 |
+
}
|
380 |
+
const times = line.split('-->');
|
381 |
+
currentCaption = {
|
382 |
+
start: parseTime(times[0].trim()),
|
383 |
+
end: parseTime(times[1].trim()),
|
384 |
+
text: ''
|
385 |
+
};
|
386 |
+
} else if (line && currentCaption && !line.startsWith('WEBVTT')) {
|
387 |
+
currentCaption.text += line + '\n';
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
if (currentCaption) {
|
392 |
+
captions.push(currentCaption);
|
393 |
+
}
|
394 |
+
})
|
395 |
+
.catch(error => console.error('字幕の読み込みに失敗しました:', error));
|
396 |
+
}
|
397 |
+
|
398 |
+
// 時間文字列を秒に変換
|
399 |
+
function parseTime(timeStr) {
|
400 |
+
const parts = timeStr.split(':');
|
401 |
+
if (parts.length === 3) {
|
402 |
+
return parseFloat(parts[0]) * 3600 +
|
403 |
+
parseFloat(parts[1]) * 60 +
|
404 |
+
parseFloat(parts[2]);
|
405 |
+
}
|
406 |
+
return parseFloat(timeStr);
|
407 |
+
}
|
408 |
+
|
409 |
+
// 現在の字幕を更新
|
410 |
+
function updateCaption() {
|
411 |
+
if (!captionCheckbox.checked) {
|
412 |
+
captionText.textContent = '';
|
413 |
+
activeCaption = null;
|
414 |
+
return;
|
415 |
+
}
|
416 |
+
|
417 |
+
const currentTime = video.currentTime;
|
418 |
+
let newCaption = null;
|
419 |
+
|
420 |
+
for (const caption of captions) {
|
421 |
+
if (currentTime >= caption.start && currentTime <= caption.end) {
|
422 |
+
newCaption = caption;
|
423 |
+
break;
|
424 |
+
}
|
425 |
+
}
|
426 |
+
|
427 |
+
if (newCaption !== activeCaption) {
|
428 |
+
activeCaption = newCaption;
|
429 |
+
captionText.textContent = newCaption ? newCaption.text.trim() : '';
|
430 |
+
}
|
431 |
+
}
|
432 |
|
433 |
function updatePlaybackRate(value) {
|
434 |
const speed = parseFloat(value);
|
|
|
493 |
const durationSeconds = Math.floor(video.duration % 60).toString().padStart(2, '0');
|
494 |
|
495 |
timeDisplay.textContent = `${currentMinutes}:${currentSeconds} / ${durationMinutes}:${durationSeconds}`;
|
496 |
+
|
497 |
+
// 字幕更新
|
498 |
+
updateCaption();
|
499 |
}
|
500 |
|
501 |
function setProgress(e) {
|
|
|
520 |
updateVolume(volumeSlider.value);
|
521 |
}
|
522 |
|
523 |
+
function toggleCaptions() {
|
524 |
+
captionContainer.style.display = captionCheckbox.checked ? 'block' : 'none';
|
525 |
+
if (!captionCheckbox.checked) {
|
526 |
+
captionText.textContent = '';
|
527 |
+
}
|
528 |
+
}
|
529 |
+
|
530 |
function goFullscreen() {
|
531 |
const container = document.querySelector('.video-container');
|
532 |
if (container.requestFullscreen) {
|
|
|
553 |
video.loop = loopCheckbox.checked;
|
554 |
});
|
555 |
|
556 |
+
captionCheckbox.addEventListener('change', toggleCaptions);
|
557 |
+
|
558 |
playPauseBtn.addEventListener('click', togglePlayPause);
|
559 |
video.addEventListener('click', togglePlayPause);
|
560 |
video.addEventListener('play', () => playPauseBtn.textContent = '⏸');
|
|
|
573 |
updateVolume(volumeRange.value);
|
574 |
video.loop = loopCheckbox.checked;
|
575 |
updateProgress();
|
576 |
+
loadCaptions();
|
577 |
});
|
578 |
</script>
|
579 |
</body>
|