<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube IFrame API - レジューム再生と視聴時間記録</title>
<script>
var player;
var watchTime = 0; // 実際に見た時間(秒)
var lastTime = 0; // 直前の再生位置
var lastTimestamp = 0; // 最後に計測した時間
var tracking = false; // 視聴時間の計測状態
var threshold = 2; // シーク検知の閾値(2秒以上の移動はシークとみなす)
var videoId = 'M7lc1UVf-VE'; // YouTube動画ID(変更可能)
var resumeTime = 0; // レジューム用の再生位置
// LocalStorage から視聴データを取得
function loadWatchData() {
var savedData = JSON.parse(localStorage.getItem('youtube_watch_data')) || {};
if (savedData[videoId]) {
resumeTime = savedData[videoId].lastTime || 0;
watchTime = savedData[videoId].watchTime || 0;
}
}
// YouTube IFrame API の読み込み
function onYouTubeIframeAPIReady() {
loadWatchData(); // 視聴データを読み込む
player = new YT.Player('player', {
height: '360',
width: '640',
videoId: videoId,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// プレイヤー準備完了時の処理
function onPlayerReady(event) {
console.log("YouTubeプレイヤーが準備完了");
if (resumeTime > 0) {
console.log(`レジューム再生: {resumeTime}秒から再開`);
player.seekTo(resumeTime, true); // シークして再生位置を復元
}
updateWatchTimeDisplay(); // 表示更新
}
// プレイヤーの状態変化を監視
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
console.log("再生開始");
startTrackingWatchTime();
} else if (event.data == YT.PlayerState.PAUSED) {
console.log("一時停止");
stopTrackingWatchTime();
saveWatchData();
} else if (event.data == YT.PlayerState.ENDED) {
console.log("動画終了");
stopTrackingWatchTime();
saveWatchData();
document.getElementById("status").innerText = "視聴完了 ✅";
}
}
// 視聴時間の計測を開始
function startTrackingWatchTime() {
tracking = true;
lastTimestamp = performance.now();
lastTime = player.getCurrentTime();
trackTime();
}
function trackTime() {
if (!tracking) return;
let now = performance.now();
let elapsed = (now - lastTimestamp) / 1000; // 経過時間(秒)
lastTimestamp = now;
let currentTime = player.getCurrentTime();
let timeDiff = currentTime - lastTime;
let playbackRate = player.getPlaybackRate(); // 現在の再生速度
// シークしていない場合、視聴時間を加算
if (timeDiff >= 0 && timeDiff <= threshold) {
watchTime += elapsed * playbackRate; // 再生速度を考慮
} else {
console.log("シーク検知! 視聴時間には加算しない");
}
lastTime = currentTime;
saveWatchData(); // 視聴時間を保存
updateWatchTimeDisplay();
requestAnimationFrame(trackTime);
}
function stopTrackingWatchTime() {
tracking = false;
}
// 視聴データを保存 (LocalStorage)
function saveWatchData() {
var currentTime = player.getCurrentTime();
var saveData = JSON.parse(localStorage.getItem('youtube_watch_data')) || {};
saveData[videoId] = {
lastTime: currentTime,
watchTime: watchTime
};
localStorage.setItem('youtube_watch_data', JSON.stringify(saveData));
}
// 視聴時間を更新
function updateWatchTimeDisplay() {
document.getElementById("watchTimeDisplay").innerText = "視聴時間: " + formatTime(watchTime);
}
// 時:分:秒 形式に変換
function formatTime(seconds) {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = Math.floor(seconds % 60);
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
}
// 視聴データをクリア
function clearWatchData() {
var saveData = JSON.parse(localStorage.getItem('youtube_watch_data')) || {};
delete saveData[videoId];
localStorage.setItem('youtube_watch_data', JSON.stringify(saveData));
watchTime = 0;
resumeTime = 0;
updateWatchTimeDisplay();
document.getElementById("status").innerText = "";
alert("視聴データをリセットしました");
}
</script>
<!-- キャッシュ対策 -->
<script>
var script = document.createElement("script");
script.src = "https://www.youtube.com/iframe_api?v=" + new Date().getTime();
document.head.appendChild(script);
</script>
</head>
<body>
<h1>YouTube IFrame API - レジューム再生と視聴時間記録</h1>
<div id="player"></div>
<h2>視聴情報</h2>
<p id="watchTimeDisplay">視聴時間: 00:00:00</p>
<p id="status"></p>
<button onclick="clearWatchData()">視聴データをリセット</button>
</body>
</html>