Akıllı Video Başlık Zamanlayıcı

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.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu betiği yüklemek için bir betik yöneticisi eklentisi yüklemeniz gerekecektir.

(Zaten bir betik yöneticim var, hadi yükleyelim!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

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