Smart Video Title Timer

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

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Вам потребуется установить расширение, например Tampermonkey или Violentmonkey, чтобы установить этот скрипт.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==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();
  }
})();