Smart Video Title Timer

Updates main document title with speed-adjusted time from videos, including cross-origin iframes.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu budete musieť nainštalovať rozšírenie, ako je napríklad Tampermonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Smart Video Title Timer
// @name:tr Akıllı Video Başlık Zamanlayıcı
// @namespace    http://tampermonkey.net
// @version      3
// @description  Updates main document title with speed-adjusted time from videos, including cross-origin iframes.
// @description:tr Video hızı değiştirildiğinde, ana site başlığını iframe içindekiler dahil hıza göre ayarlanmış süreyle günceller.
// @author       Atilla
// @match        *://*/*
// @grant        none
// @run-at       document-start
// @allframes    true
// @icon https://gitlab.com/atilla-tr/tampermonkey-depolama/-/raw/main/Smart%20Video%20Title%20Timer.js/app-icon-1024.png
// @license      MIT
// ==/UserScript==
(function () {
  "use strict";

  const isMainFrame = window === window.top;
  let activeVideo = null;
  let originalTitle = isMainFrame
    ? document.title || window.location.hostname
    : "";

  // Saniyeyi SS:DD:SS formatına çevirir
  function formatTime(seconds) {
    if (isNaN(seconds) || seconds === Infinity) return "00:00";
    const h = Math.floor(seconds / 3600);
    const m = Math.floor((seconds % 3600) / 60);
    const s = Math.floor(seconds % 60);
    return h > 0
      ? `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`
      : `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
  }

  // ----------------------------------------------------
  // ANA SAYFA (MAIN FRAME) MANTIĞI
  // ----------------------------------------------------
  if (isMainFrame) {
    const titleObserver = new MutationObserver(() => {
      // Eğer başlık dışarıdan (site tarafından) değişirse orijinal başlığı güncelle
      const cleanTitle = document.title.replace(
        /^\(\d+:\d+(:\d+)? \/ \d+:\d+(:\d+)?\) /,
        "",
      );
      if (!document.title.startsWith("(")) {
        originalTitle = cleanTitle;
      }
    });

    if (document.querySelector("title")) {
      titleObserver.observe(document.querySelector("title"), {
        childList: true,
      });
    } else {
      // Title elementi henüz yoksa DOM yüklendiğinde bağlan
      document.addEventListener("DOMContentLoaded", () => {
        if (document.querySelector("title")) {
          titleObserver.observe(document.querySelector("title"), {
            childList: true,
          });
        }
      });
    }

    // Iframe'lerden gelen zaman mesajlarını dinle
    window.addEventListener("message", (event) => {
      if (event.data && event.data.type === "SMART_VIDEO_TIMER") {
        applyNewTitle(event.data.timeString);
      }
    });

    function applyNewTitle(timeString) {
      const cleanTitle = originalTitle.replace(
        /^\(\d+:\d+(:\d+)? \/ \d+:\d+(:\d+)?\) /,
        "",
      );
      const newTitle = timeString ? `${timeString} ${cleanTitle}` : cleanTitle;

      if (document.title !== newTitle) {
        titleObserver.disconnect();
        document.title = newTitle;
        if (document.querySelector("title")) {
          titleObserver.observe(document.querySelector("title"), {
            childList: true,
          });
        }
      }
    }

    // Ana sayfadaki videolar için yerel fonksiyon
    window._updateMainTitleDirectly = function (timeString) {
      applyNewTitle(timeString);
    };
  }

  // ----------------------------------------------------
  // VİDEO TAKİP MANTIĞI (Hem Ana Sayfa Hem Iframe Çalıştırır)
  // ----------------------------------------------------
  function calculateAndSend() {
    if (!activeVideo || activeVideo.paused || activeVideo.playbackRate === 1) {
      sendTitleUpdate(""); // Zamanı temizle, orijinal başlığa dön
      return;
    }

    const rate = activeVideo.playbackRate;
    const currentAdjusted = activeVideo.currentTime / rate;
    const durationAdjusted = activeVideo.duration / rate;
    const timeString = `(${formatTime(currentAdjusted)} / ${formatTime(durationAdjusted)})`;

    sendTitleUpdate(timeString);
  }

  function sendTitleUpdate(timeString) {
    if (isMainFrame) {
      if (typeof window._updateMainTitleDirectly === "function") {
        window._updateMainTitleDirectly(timeString);
      }
    } else {
      // Iframe içindeyse mesajı güvenli bir şekilde ana sayfaya fırlatır
      window.top.postMessage(
        {
          type: "SMART_VIDEO_TIMER",
          timeString: timeString,
        },
        "*",
      );
    }
  }

  function setupVideoListeners(video) {
    if (video.dataset.titleTimerTracked) return;
    video.dataset.titleTimerTracked = "true";

    const events = [
      "timeupdate",
      "play",
      "pause",
      "ratechange",
      "ended",
      "durationchange",
    ];
    events.forEach((evt) => {
      video.addEventListener(evt, () => {
        if (!video.paused) {
          activeVideo = video;
        }
        calculateAndSend();
      });
    });

    if (!video.paused) {
      activeVideo = video;
      calculateAndSend();
    }
  }

  function scanForVideos() {
    document.querySelectorAll("video").forEach(setupVideoListeners);
  }

  const domObserver = new MutationObserver((mutations) => {
    let shouldScan = false;
    for (let mutation of mutations) {
      if (mutation.addedNodes.length > 0) {
        shouldScan = true;
        break;
      }
    }
    if (shouldScan) scanForVideos();
  });

  function init() {
    if (isMainFrame && document.querySelector("title") && !originalTitle) {
      originalTitle = document.title;
    }
    scanForVideos();
    if (document.body) {
      domObserver.observe(document.body, { childList: true, subtree: true });
    }
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();