- // ==UserScript==
- // @name Youtube Tracker
- // @namespace http://tampermonkey.net/
- // @version 0.3
- // @description Counts youtube watchtime
- // @author Kaanium
- // @match https://www.youtube.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // @grant GM_setClipboard
- // @license MIT
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- function secondsToTime(seconds) {
- const hours = Math.floor(seconds / 3600);
- const minutes = Math.floor((seconds % 3600) / 60);
- const remainingSeconds = seconds % 60;
-
- const formattedHours = hours.toString().padStart(2, '0');
- const formattedMinutes = minutes.toString().padStart(2, '0');
- const formattedSeconds = remainingSeconds.toString().padStart(2, '0');
-
- if (hours > 0) {
- return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`;
- } else {
- return `${formattedMinutes}:${formattedSeconds}`;
- }
- }
-
- function secondsToMoe(seconds) {
- const minutes = Math.floor(seconds / 60);
- const fractionalMinutes = (seconds % 60) / 60;
- return (minutes + fractionalMinutes).toFixed(2);
- }
-
- function timeToSeconds(timeString) {
- const timeParts = timeString.split(':').map(Number);
- const totalParts = timeParts.length;
-
- if (totalParts === 2) {
- // Format: mm:ss
- const [minutes, seconds] = timeParts;
- if (isNaN(minutes) || isNaN(seconds) || minutes < 0 || seconds < 0) {
- throw new Error('Invalid time format. Please use numeric values for minutes and seconds.');
- }
- return minutes * 60 + seconds;
- } else if (totalParts === 3) {
- // Format: hh:mm:ss
- const [hours, minutes, seconds] = timeParts;
- if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) || hours < 0 || minutes < 0 || seconds < 0) {
- throw new Error('Invalid time format. Please use numeric values for hours, minutes, and seconds.');
- }
- return hours * 3600 + minutes * 60 + seconds;
- } else {
- throw new Error('Invalid time format. Expected format: hh:mm:ss or mm:ss');
- }
- }
-
- function handleTextbox1Change() {
- timeTextbox2.value = secondsToMoe(timeToSeconds(timeTextbox1.value));
- totalWatchedTime = timeToSeconds(timeTextbox1.value);
- localStorage.setItem('totalWatchedTime', totalWatchedTime);
- }
-
- function createStyledButton(text, onClickHandler) {
- const button = document.createElement("button");
- button.textContent = text;
- applyCommonStyles(button);
- button.onclick = onClickHandler;
- return button;
- }
-
- function createStyledTextbox(type, value) {
- const textbox = document.createElement("input");
- textbox.setAttribute("type", type);
- textbox.setAttribute("value", value);
- applyCommonStyles(textbox);
- return textbox;
- }
-
- function applyCommonStyles(element) {
- element.style.fontSize = "10px";
- element.style.backgroundColor = "hsl(0, 0%, 7%)";
- element.style.color = "#ffffffe0";
- element.style.borderColor = "hsla(0, 0%, 53.3%, 0.4)";
- element.style.borderWidth = "1px";
- element.style.borderRadius = "40px";
- element.style.fontFamily = '"Roboto","Arial",sans-serif';
- element.style.fontSize = "1.4rem";
- element.style.lineHeight = "2rem";
- element.style.fontWeight = "500";
- element.style.textAlign = "center";
- element.style.width = "5%";
- element.style.margin = "3px"
- }
-
- var container = document.querySelector("#masthead > div:nth-child(5)");
-
- const timeTextbox1 = createStyledTextbox("text", "00:00:00");
- container.insertBefore(timeTextbox1, document.getElementById("end"));
-
- timeTextbox1.addEventListener("input", handleTextbox1Change);
-
- const timeTextbox2 = createStyledTextbox("text", "0.0");
- container.insertBefore(timeTextbox2, document.getElementById("end"));
-
- const newButton = createStyledButton("Clipboard", function () {
- GM_setClipboard(".log listening " + timeTextbox2.value);
- });
- container.insertBefore(newButton, document.getElementById("end"));
-
- const resetButton = createStyledButton("Reset", function () {
- totalWatchedTime = 0;
- bufferSum = 0;
- bufferTime = 0;
- timeTextbox1.value = "00:00:00";
- timeTextbox2.value = "0.0";
- localStorage.removeItem('totalWatchedTime');
- });
- container.insertBefore(resetButton, document.getElementById("end"));
-
- let startTime = new Date();
- let totalWatchedTime = parseInt(localStorage.getItem('totalWatchedTime')) || 0;
- let isVideoPlaying = true;
- let bufferTime = 0;
- let bufferSum = 0;
- let seconds = 0;
- var videoPlayer = document.querySelector("video");
- var moviePlayer = null;
-
-
- function updateTimeSpent() {
- if (isVideoPlaying && !moviePlayer.classList.contains("buffering-mode")) {
- bufferSum += bufferTime
- bufferTime = 0
- seconds = parseInt((new Date() - startTime) / 1000, 10);
- var temp = parseInt(localStorage.getItem('totalWatchedTime'))
- if (temp > totalWatchedTime + seconds - bufferSum) {
- totalWatchedTime = temp
- bufferSum = 0
- startTime = new Date()
- seconds = parseInt((new Date() - startTime) / 1000, 10);
- }
- timeTextbox2.value = secondsToMoe(totalWatchedTime + seconds - bufferSum);
- timeTextbox1.value = secondsToTime(totalWatchedTime + seconds - bufferSum);
- localStorage.setItem('totalWatchedTime', totalWatchedTime + seconds - bufferSum);
- }
- else if(moviePlayer.classList.contains("buffering-mode")) {
- bufferTime = parseInt((new Date() - startTime) / 1000, 10);
- console.log("buffer time: " + bufferTime)
- }
- }
-
- function saveTotalWatchedTime() {
- if (videoPlayer.src) {
- let _seconds = parseInt((new Date() - startTime) / 1000, 10);
- totalWatchedTime += _seconds;
- }
- }
-
- const checkForVideoPlayer = () => {
- videoPlayer = document.querySelector("video");
- moviePlayer = document.querySelector("#movie_player");
- if (videoPlayer && window.location.pathname == "/watch") {
- isVideoPlaying = true;
- videoPlayer.addEventListener("timeupdate", updateTimeSpent);
- videoPlayer.addEventListener("pause", function () {
- isVideoPlaying = false;
- console.log("pause")
- saveTotalWatchedTime();
- });
- videoPlayer.addEventListener("play", function () {
- isVideoPlaying = true;
- console.log("play")
- startTime = new Date();
- });
- videoPlayer.addEventListener("canplaythrough", function () {
- console.log("video can play through");
- startTime = new Date();
- });
- } else {
- setTimeout(checkForVideoPlayer, 1000);
- }
- };
-
- checkForVideoPlayer();
-
- document.addEventListener("yt-navigate-start", function() {
- isVideoPlaying = false;
- saveTotalWatchedTime()
- });
-
- window.addEventListener('keydown', function(event) {
- if (event.key === 'ArrowLeft' || event.key === 'ArrowRight' || /^[0-9]$/.test(event.key)) {
- saveTotalWatchedTime();
- startTime = new Date();
- }
- });
-
- window.addEventListener('popstate', function(event) {
- totalWatchedTime = timeToSeconds(timeTextbox1.value);
- startTime = new Date();
- });
-
- updateTimeSpent();
- })();