Update index.html
Browse files- index.html +87 -63
index.html
CHANGED
@@ -1247,7 +1247,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1247 |
let controlsVisible = true;
|
1248 |
let isCheckingSync = false;
|
1249 |
let isInBackgroundTab = false;
|
1250 |
-
let
|
1251 |
|
1252 |
try {
|
1253 |
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
@@ -1381,7 +1381,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1381 |
const tempoSpeedValue = document.getElementById('tempo-speed-value');
|
1382 |
const videoControls = document.querySelector('.video-controls');
|
1383 |
const applyTimeBtn = document.getElementById('apply-time-btn');
|
1384 |
-
const
|
|
|
|
|
|
|
|
|
|
|
1385 |
|
1386 |
// 音声オブジェクトを作成
|
1387 |
const audioElements = {};
|
@@ -1390,8 +1395,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1390 |
let combinedAudioElement = null;
|
1391 |
let isAudioCombined = false;
|
1392 |
let currentVolumes = { p: 0, a: 1, t: 1, s: 1, k: 0 };
|
1393 |
-
let appliedStartTime = 0;
|
1394 |
-
let appliedEndTime = 0;
|
1395 |
|
1396 |
// 初期化
|
1397 |
let videoDuration = 0;
|
@@ -1399,22 +1402,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1399 |
let lastVolume = 1;
|
1400 |
let currentPlaybackRate = 1;
|
1401 |
let isFullscreen = false;
|
1402 |
-
|
1403 |
-
// 消画モード切り替え
|
1404 |
-
function toggleBlankMode() {
|
1405 |
-
isBlankMode = !isBlankMode;
|
1406 |
-
if (isBlankMode) {
|
1407 |
-
video.style.backgroundColor = 'black';
|
1408 |
-
video.style.opacity = '0';
|
1409 |
-
blankModeBtn.textContent = '消画モード: ON';
|
1410 |
-
blankModeBtn.classList.add('active');
|
1411 |
-
} else {
|
1412 |
-
video.style.backgroundColor = '';
|
1413 |
-
video.style.opacity = '1';
|
1414 |
-
blankModeBtn.textContent = '消画モード: OFF';
|
1415 |
-
blankModeBtn.classList.remove('active');
|
1416 |
-
}
|
1417 |
-
}
|
1418 |
|
1419 |
async function enterPiP() {
|
1420 |
if (!document.pictureInPictureElement && !video.paused) {
|
@@ -1435,7 +1423,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1435 |
}
|
1436 |
}
|
1437 |
}
|
1438 |
-
|
1439 |
// 動画のバッファリング状態を監視
|
1440 |
video.addEventListener('waiting', function() {
|
1441 |
isBuffering = true;
|
@@ -1496,6 +1484,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1496 |
}
|
1497 |
|
1498 |
applyTimeBtn.addEventListener('click', function() {
|
|
|
|
|
|
|
1499 |
// 現在再生中なら一時停止
|
1500 |
const wasPlaying = isPlaying;
|
1501 |
if (isPlaying) {
|
@@ -1503,21 +1494,21 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1503 |
}
|
1504 |
|
1505 |
// 開始時間と終了時間を取得
|
1506 |
-
|
1507 |
-
|
1508 |
|
1509 |
// 現在位置が開始時間より前なら開始時間に移動
|
1510 |
-
if (video.currentTime <
|
1511 |
-
video.currentTime =
|
1512 |
if (combinedAudioElement) {
|
1513 |
-
combinedAudioElement.currentTime =
|
1514 |
}
|
1515 |
}
|
1516 |
// 現在位置が終了時間より後なら開始時間に移動
|
1517 |
-
else if (video.currentTime >
|
1518 |
-
video.currentTime =
|
1519 |
if (combinedAudioElement) {
|
1520 |
-
combinedAudioElement.currentTime =
|
1521 |
}
|
1522 |
}
|
1523 |
|
@@ -1575,11 +1566,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1575 |
|
1576 |
// 音声を結合する関数
|
1577 |
async function combineAudio() {
|
1578 |
-
//
|
1579 |
-
if (
|
1580 |
-
|
1581 |
-
combinedAudioElement.src = '';
|
1582 |
-
combinedAudioElement = null;
|
1583 |
}
|
1584 |
|
1585 |
combineButton.disabled = true;
|
@@ -1661,6 +1650,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1661 |
const url = URL.createObjectURL(blob);
|
1662 |
|
1663 |
// 新しいaudio要素を作成
|
|
|
|
|
|
|
|
|
1664 |
combinedAudioElement = new Audio(url);
|
1665 |
combinedAudioElement.preservesPitch = true;
|
1666 |
combinedAudioElement.mozPreservesPitch = true;
|
@@ -1668,6 +1661,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1668 |
combinedAudioElement.playbackRate = currentPlaybackRate;
|
1669 |
|
1670 |
isAudioCombined = true;
|
|
|
1671 |
combineStatus.textContent = "音声の合成が完了しました";
|
1672 |
enablePlayerControls();
|
1673 |
|
@@ -1730,7 +1724,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1730 |
|
1731 |
// 動画終了時に自動的にPiPを閉じる(次回再開のため)
|
1732 |
video.addEventListener('ended', exitPiP);
|
1733 |
-
|
1734 |
// 合成後に音量と再生速度を適用
|
1735 |
applyVolume();
|
1736 |
applyPlaybackRate();
|
@@ -1848,7 +1842,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1848 |
setEndTimeBtn.disabled = false;
|
1849 |
playbackSpeedSlider.disabled = false;
|
1850 |
applyTimeBtn.disabled = false;
|
1851 |
-
|
1852 |
}
|
1853 |
|
1854 |
// プレビュー再生
|
@@ -1904,6 +1898,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1904 |
endTimeInput.max = videoDuration;
|
1905 |
startTimeInput.max = videoDuration - 0.1;
|
1906 |
updateTimeDisplay();
|
|
|
1907 |
checkLoadingComplete();
|
1908 |
} catch (error) {
|
1909 |
handleError(error, '動画メタデータ読み込み中にエラーが発生しました');
|
@@ -1917,11 +1912,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1917 |
|
1918 |
// 再生ボタンクリック
|
1919 |
playPauseBtn.addEventListener('click', function() {
|
1920 |
-
if (
|
1921 |
-
|
1922 |
-
|
1923 |
-
|
1924 |
-
|
|
|
|
|
|
|
|
|
1925 |
}
|
1926 |
togglePlayPause();
|
1927 |
});
|
@@ -1966,9 +1965,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
1966 |
function playMedia() {
|
1967 |
try {
|
1968 |
const duration = video.duration || videoDuration;
|
|
|
|
|
1969 |
|
1970 |
-
if (video.currentTime >=
|
1971 |
-
video.currentTime =
|
1972 |
}
|
1973 |
|
1974 |
const playPromise = video.play();
|
@@ -2017,17 +2018,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
2017 |
|
2018 |
// 時間更新時の処理
|
2019 |
video.addEventListener('timeupdate', function() {
|
|
|
|
|
2020 |
const duration = video.duration || videoDuration;
|
|
|
2021 |
|
2022 |
-
if (video.currentTime >=
|
2023 |
if (loopCheckbox.checked) {
|
2024 |
-
|
|
|
2025 |
if (combinedAudioElement) {
|
2026 |
-
combinedAudioElement.currentTime =
|
2027 |
}
|
2028 |
} else {
|
2029 |
pauseMedia();
|
2030 |
-
video.currentTime =
|
|
|
|
|
|
|
2031 |
}
|
2032 |
}
|
2033 |
|
@@ -2049,7 +2057,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
2049 |
function seekMedia(time) {
|
2050 |
try {
|
2051 |
const duration = video.duration || videoDuration;
|
2052 |
-
const
|
|
|
|
|
|
|
2053 |
video.currentTime = seekTime;
|
2054 |
|
2055 |
if (combinedAudioElement) {
|
@@ -2352,8 +2363,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
2352 |
}
|
2353 |
}
|
2354 |
|
2355 |
-
//
|
2356 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2357 |
|
2358 |
// 合成ボタンクリック
|
2359 |
combineButton.addEventListener('click', combineAudio);
|
@@ -2408,7 +2433,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
2408 |
|
2409 |
// タイムマーカー関連のコード
|
2410 |
document.addEventListener('DOMContentLoaded', function() {
|
2411 |
-
//
|
2412 |
const startMarker = document.getElementById('start-marker');
|
2413 |
const endMarker = document.getElementById('end-marker');
|
2414 |
const video = document.getElementById('video');
|
@@ -2505,21 +2530,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
2505 |
const endTime = parseFloat(endTimeInput.value) || duration;
|
2506 |
|
2507 |
if (duration > 0) {
|
2508 |
-
if(startMarker) startMarker.style.left = `${(startTime / duration) * 100}%`;
|
2509 |
-
if(endMarker) endMarker.style.left = `${(endTime / duration) * 100}%`;
|
2510 |
-
|
2511 |
// 開始時間が0の場合はマーカーを非表示
|
2512 |
-
if(startTime <= 0
|
2513 |
-
|
2514 |
-
} else
|
2515 |
-
|
|
|
2516 |
}
|
2517 |
-
|
2518 |
// 終了時間が動画の長さと同じ場合はマーカーを非表示
|
2519 |
-
if(endTime >= duration
|
2520 |
-
|
2521 |
-
} else
|
2522 |
-
|
|
|
2523 |
}
|
2524 |
}
|
2525 |
}
|
|
|
1247 |
let controlsVisible = true;
|
1248 |
let isCheckingSync = false;
|
1249 |
let isInBackgroundTab = false;
|
1250 |
+
let isBlackVideoMode = false; // 消画モードフラグ
|
1251 |
|
1252 |
try {
|
1253 |
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
|
1381 |
const tempoSpeedValue = document.getElementById('tempo-speed-value');
|
1382 |
const videoControls = document.querySelector('.video-controls');
|
1383 |
const applyTimeBtn = document.getElementById('apply-time-btn');
|
1384 |
+
const blackVideoToggle = document.createElement('button');
|
1385 |
+
blackVideoToggle.className = 'control-button';
|
1386 |
+
blackVideoToggle.id = 'black-video-btn';
|
1387 |
+
blackVideoToggle.textContent = '消画モード';
|
1388 |
+
blackVideoToggle.title = '動画を黒画面に切り替え(読み込み遅延防止)';
|
1389 |
+
document.querySelector('.main-controls').appendChild(blackVideoToggle);
|
1390 |
|
1391 |
// 音声オブジェクトを作成
|
1392 |
const audioElements = {};
|
|
|
1395 |
let combinedAudioElement = null;
|
1396 |
let isAudioCombined = false;
|
1397 |
let currentVolumes = { p: 0, a: 1, t: 1, s: 1, k: 0 };
|
|
|
|
|
1398 |
|
1399 |
// 初期化
|
1400 |
let videoDuration = 0;
|
|
|
1402 |
let lastVolume = 1;
|
1403 |
let currentPlaybackRate = 1;
|
1404 |
let isFullscreen = false;
|
1405 |
+
let isTimeApplied = false; // 時間設定が適用されたかどうか
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1406 |
|
1407 |
async function enterPiP() {
|
1408 |
if (!document.pictureInPictureElement && !video.paused) {
|
|
|
1423 |
}
|
1424 |
}
|
1425 |
}
|
1426 |
+
|
1427 |
// 動画のバッファリング状態を監視
|
1428 |
video.addEventListener('waiting', function() {
|
1429 |
isBuffering = true;
|
|
|
1484 |
}
|
1485 |
|
1486 |
applyTimeBtn.addEventListener('click', function() {
|
1487 |
+
// 時間設定を適用
|
1488 |
+
isTimeApplied = true;
|
1489 |
+
|
1490 |
// 現在再生中なら一時停止
|
1491 |
const wasPlaying = isPlaying;
|
1492 |
if (isPlaying) {
|
|
|
1494 |
}
|
1495 |
|
1496 |
// 開始時間と終了時間を取得
|
1497 |
+
const startTime = parseFloat(startTimeInput.value) || 0;
|
1498 |
+
const endTime = parseFloat(endTimeInput.value) || video.duration;
|
1499 |
|
1500 |
// 現在位置が開始時間より前なら開始時間に移動
|
1501 |
+
if (video.currentTime < startTime) {
|
1502 |
+
video.currentTime = startTime;
|
1503 |
if (combinedAudioElement) {
|
1504 |
+
combinedAudioElement.currentTime = startTime;
|
1505 |
}
|
1506 |
}
|
1507 |
// 現在位置が終了時間より後なら開始時間に移動
|
1508 |
+
else if (video.currentTime > endTime) {
|
1509 |
+
video.currentTime = startTime;
|
1510 |
if (combinedAudioElement) {
|
1511 |
+
combinedAudioElement.currentTime = startTime;
|
1512 |
}
|
1513 |
}
|
1514 |
|
|
|
1566 |
|
1567 |
// 音声を結合する関数
|
1568 |
async function combineAudio() {
|
1569 |
+
// 再生中なら停止
|
1570 |
+
if (isPlaying) {
|
1571 |
+
pauseMedia();
|
|
|
|
|
1572 |
}
|
1573 |
|
1574 |
combineButton.disabled = true;
|
|
|
1650 |
const url = URL.createObjectURL(blob);
|
1651 |
|
1652 |
// 新しいaudio要素を作成
|
1653 |
+
if (combinedAudioElement) {
|
1654 |
+
combinedAudioElement.pause();
|
1655 |
+
URL.revokeObjectURL(combinedAudioElement.src);
|
1656 |
+
}
|
1657 |
combinedAudioElement = new Audio(url);
|
1658 |
combinedAudioElement.preservesPitch = true;
|
1659 |
combinedAudioElement.mozPreservesPitch = true;
|
|
|
1661 |
combinedAudioElement.playbackRate = currentPlaybackRate;
|
1662 |
|
1663 |
isAudioCombined = true;
|
1664 |
+
isTimeApplied = false; // 音声再合成時に時間設定をリセット
|
1665 |
combineStatus.textContent = "音声の合成が完了しました";
|
1666 |
enablePlayerControls();
|
1667 |
|
|
|
1724 |
|
1725 |
// 動画終了時に自動的にPiPを閉じる(次回再開のため)
|
1726 |
video.addEventListener('ended', exitPiP);
|
1727 |
+
|
1728 |
// 合成後に音量と再生速度を適用
|
1729 |
applyVolume();
|
1730 |
applyPlaybackRate();
|
|
|
1842 |
setEndTimeBtn.disabled = false;
|
1843 |
playbackSpeedSlider.disabled = false;
|
1844 |
applyTimeBtn.disabled = false;
|
1845 |
+
blackVideoToggle.disabled = false;
|
1846 |
}
|
1847 |
|
1848 |
// プレビュー再生
|
|
|
1898 |
endTimeInput.max = videoDuration;
|
1899 |
startTimeInput.max = videoDuration - 0.1;
|
1900 |
updateTimeDisplay();
|
1901 |
+
updateProgressMarkers(); // マーカーを初期化
|
1902 |
checkLoadingComplete();
|
1903 |
} catch (error) {
|
1904 |
handleError(error, '動画メタデータ読み込み中にエラーが発生しました');
|
|
|
1912 |
|
1913 |
// 再生ボタンクリック
|
1914 |
playPauseBtn.addEventListener('click', function() {
|
1915 |
+
if (!isTimeApplied) {
|
1916 |
+
alert('時間設定を適用してください');
|
1917 |
+
return;
|
1918 |
+
}
|
1919 |
+
|
1920 |
+
const endTime = parseFloat(endTimeInput.value) || videoDuration;
|
1921 |
+
if (video.currentTime >= endTime) {
|
1922 |
+
const startTime = parseFloat(startTimeInput.value) || 0;
|
1923 |
+
seekMedia(startTime);
|
1924 |
}
|
1925 |
togglePlayPause();
|
1926 |
});
|
|
|
1965 |
function playMedia() {
|
1966 |
try {
|
1967 |
const duration = video.duration || videoDuration;
|
1968 |
+
const startTime = parseFloat(startTimeInput.value) || 0;
|
1969 |
+
const endTime = parseFloat(endTimeInput.value) || duration;
|
1970 |
|
1971 |
+
if (video.currentTime >= endTime) {
|
1972 |
+
video.currentTime = startTime;
|
1973 |
}
|
1974 |
|
1975 |
const playPromise = video.play();
|
|
|
2018 |
|
2019 |
// 時間更新時の処理
|
2020 |
video.addEventListener('timeupdate', function() {
|
2021 |
+
if (!isTimeApplied) return;
|
2022 |
+
|
2023 |
const duration = video.duration || videoDuration;
|
2024 |
+
const endTime = parseFloat(endTimeInput.value) || duration;
|
2025 |
|
2026 |
+
if (video.currentTime >= endTime && endTime > 0) {
|
2027 |
if (loopCheckbox.checked) {
|
2028 |
+
const startTime = parseFloat(startTimeInput.value) || 0;
|
2029 |
+
video.currentTime = startTime;
|
2030 |
if (combinedAudioElement) {
|
2031 |
+
combinedAudioElement.currentTime = startTime;
|
2032 |
}
|
2033 |
} else {
|
2034 |
pauseMedia();
|
2035 |
+
video.currentTime = endTime;
|
2036 |
+
if (combinedAudioElement) {
|
2037 |
+
combinedAudioElement.currentTime = endTime;
|
2038 |
+
}
|
2039 |
}
|
2040 |
}
|
2041 |
|
|
|
2057 |
function seekMedia(time) {
|
2058 |
try {
|
2059 |
const duration = video.duration || videoDuration;
|
2060 |
+
const startTime = parseFloat(startTimeInput.value) || 0;
|
2061 |
+
const endTime = parseFloat(endTimeInput.value) || duration;
|
2062 |
+
|
2063 |
+
const seekTime = Math.max(startTime, Math.min(time, endTime));
|
2064 |
video.currentTime = seekTime;
|
2065 |
|
2066 |
if (combinedAudioElement) {
|
|
|
2363 |
}
|
2364 |
}
|
2365 |
|
2366 |
+
// 消画モード切り替え
|
2367 |
+
blackVideoToggle.addEventListener('click', function() {
|
2368 |
+
isBlackVideoMode = !isBlackVideoMode;
|
2369 |
+
|
2370 |
+
if (isBlackVideoMode) {
|
2371 |
+
// 消画モードON
|
2372 |
+
video.style.filter = 'brightness(0)';
|
2373 |
+
this.style.backgroundColor = '#64ffda';
|
2374 |
+
this.style.color = '#0a192f';
|
2375 |
+
} else {
|
2376 |
+
// 消画モードOFF
|
2377 |
+
video.style.filter = '';
|
2378 |
+
this.style.backgroundColor = '';
|
2379 |
+
this.style.color = '';
|
2380 |
+
}
|
2381 |
+
});
|
2382 |
|
2383 |
// 合成ボタンクリック
|
2384 |
combineButton.addEventListener('click', combineAudio);
|
|
|
2433 |
|
2434 |
// タイムマーカー関連のコード
|
2435 |
document.addEventListener('DOMContentLoaded', function() {
|
2436 |
+
// まず必要なDOM要素を取得
|
2437 |
const startMarker = document.getElementById('start-marker');
|
2438 |
const endMarker = document.getElementById('end-marker');
|
2439 |
const video = document.getElementById('video');
|
|
|
2530 |
const endTime = parseFloat(endTimeInput.value) || duration;
|
2531 |
|
2532 |
if (duration > 0) {
|
|
|
|
|
|
|
2533 |
// 開始時間が0の場合はマーカーを非表示
|
2534 |
+
if (startTime <= 0) {
|
2535 |
+
if(startMarker) startMarker.style.display = 'none';
|
2536 |
+
} else {
|
2537 |
+
if(startMarker) startMarker.style.left = `${(startTime / duration) * 100}%`;
|
2538 |
+
if(startMarker) startMarker.style.display = 'block';
|
2539 |
}
|
2540 |
+
|
2541 |
// 終了時間が動画の長さと同じ場合はマーカーを非表示
|
2542 |
+
if (endTime >= duration) {
|
2543 |
+
if(endMarker) endMarker.style.display = 'none';
|
2544 |
+
} else {
|
2545 |
+
if(endMarker) endMarker.style.left = `${(endTime / duration) * 100}%`;
|
2546 |
+
if(endMarker) endMarker.style.display = 'block';
|
2547 |
}
|
2548 |
}
|
2549 |
}
|