IMDb to VidPlus (Unified Integration)

Inline VidPlus players on IMDb: styled Episode guide on series pages, per-episode buttons on episode list pages, inline player toggle for movies/episodes if needed (matching official player style).

Από την 15/11/2025. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         IMDb to VidPlus (Unified Integration)
// @namespace    https://www.imdb.com/
// @icon         https://vidplus.to/favicon.ico
// @version      1.0
// @description  Inline VidPlus players on IMDb: styled Episode guide on series pages, per-episode buttons on episode list pages, inline player toggle for movies/episodes if needed (matching official player style).
// @author       Grok (built on VidFast script)
// @license      MIT
// @match        https://*.imdb.com/title/*
// @match        https://m.imdb.com/title/*
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  function getImdbId() {
    const parts = location.pathname.split("/").filter(Boolean);
    return parts[1] || null;
  }

  function getTmdbId() {
    // Try JSON-LD first (most reliable)
    const jsonLd = document.querySelector('script[type="application/ld+json"]');
    if (jsonLd) {
      try {
        const data = JSON.parse(jsonLd.textContent);
        if (data['@type'] === 'Movie' || data['@type'] === 'TVEpisode') {
          return data.sameAs?.find(url => url.includes('themoviedb.org'))?.split('/').pop() || null;
        }
      } catch (e) {}
    }
    // Fallback: Meta tag or data attributes
    const meta = document.querySelector('link[rel="alternate"][href*="themoviedb"]');
    if (meta) {
      return meta.href.split('/').pop().split('?')[0] || null;
    }
    // Ultimate fallback: Use IMDb ID (VidPlus may redirect/work)
    console.warn('TMDB ID not found, using IMDb ID as fallback');
    return getImdbId();
  }

  // ---------- Inline iframe creation (matching IMDb VidPlus Player style) ----------
  function createIframe(src) {
    const iframe = document.createElement("iframe");
    iframe.id = "vidplus-player";
    iframe.src = src;
    iframe.allowFullscreen = true;
    iframe.setAttribute("webkitallowfullscreen", "true");
    iframe.setAttribute("mozallowfullscreen", "true");
    Object.assign(iframe.style, {
      height: "300px",
      width: "100%",
      margin: "0 auto",
      display: "block",
      border: "none"
    });
    return iframe;
  }

  // ---------- Toggle player *after* episode card ----------
  function toggleCardPlayer(card, url) {
    const next = card.nextElementSibling;
    if (next && next.classList.contains("vp-inline-player")) {
      next.remove();
      return;
    }
    const iframe = createIframe(url);
    iframe.className = "vp-inline-player";
    card.insertAdjacentElement("afterend", iframe);
  }

  // ---------- Episode list helpers ----------
  function parseEpisodeNumbers(card, seasonDefault) {
    const label =
      card.querySelector(".ipc-title__text, .image, .info, .hover-over-image")
        ?.textContent || card.textContent;

    let m = label.match(/S(\d+)\.E(\d+)/i);
    if (m) return { season: +m[1], episode: +m[2] };

    m = label.match(/Episode\s+(\d+)/i);
    if (m) return { season: seasonDefault, episode: +m[1] };

    return null;
  }

  function getSeasonFromUrl() {
    const params = new URLSearchParams(location.search);
    return parseInt(params.get("season") || "1", 10);
  }

  function insertEpisodeButtons() {
    const tmdbId = getTmdbId();
    if (!tmdbId) return;
    const season = getSeasonFromUrl();

    const cards = document.querySelectorAll(".episode-item-wrapper, .list_item");
    cards.forEach((card) => {
      if (card.querySelector(".vp-ep-btn")) return;

      const ep = parseEpisodeNumbers(card, season);
      if (!ep) return;
      const { season: s, episode: e } = ep;

      if (getComputedStyle(card).position === "static")
        card.style.position = "relative";

      const btn = document.createElement("button");
      btn.className = "vp-ep-btn";
      btn.textContent = "VidPlus";
      Object.assign(btn.style, {
        position: "absolute",
        right: "8px",
        bottom: "8px",
        padding: "6px 12px",
        background: "#1e40af",  // VidPlus blue theme
        color: "#ffffff",
        border: "none",
        cursor: "pointer",
        fontWeight: "bold",
        borderRadius: "6px",
        fontSize: "13px",
        zIndex: 9999,
        opacity: 0.95
      });

      const url = `https://player.vidplus.to/embed/tv/${tmdbId}/${s}/${e}?subcolor=FFFFFF&subsize=16&subopacity=1`;
      btn.addEventListener("click", (ev) => {
        ev.stopPropagation();
        ev.preventDefault();
        toggleCardPlayer(card, url);
      });

      card.appendChild(btn);
    });
  }

  // ---------- Replace Episode guide link ----------
  function styleEpisodeGuide() {
    const guideLink = document.querySelector('a[href*="/episodes"]');
    if (!guideLink) return;

    guideLink.textContent = "Episode guide (Watch on VidPlus)";

    // Adjust spacing & shift slightly left
    Object.assign(guideLink.style, {
      display: "inline-block",
      padding: "8px 12px",
      marginLeft: "4px",
      marginRight: "6px",
      background: "#1e40af",
      color: "#ffffff",
      border: "none",
      cursor: "pointer",
      fontWeight: "bold",
      borderRadius: "6px",
      textDecoration: "none"
    });
  }

  // ---------- Floating button for movies only ----------
  function addMovieButton() {
    if (document.getElementById("vp-main-btn")) return;

    const tmdbId = getTmdbId();
    if (!tmdbId) return;

    const url = `https://player.vidplus.to/embed/movie/${tmdbId}?subcolor=FFFFFF&subsize=16&subopacity=1`;

    const btn = document.createElement("button");
    btn.id = "vp-main-btn";
    btn.textContent = "📽 Watch on VidPlus";
    Object.assign(btn.style, {
      fontFamily: "Arial",
      position: "fixed",
      bottom: "10px",
      right: "10px",
      padding: "10px 14px",
      background: "#1e40af",
      color: "#ffffff",
      border: "none",
      cursor: "pointer",
      fontWeight: "bold",
      borderRadius: "6px",
      zIndex: 10001,
      filter: "drop-shadow(0 10px 8px rgba(0,0,0,0.2))"
    });

    btn.addEventListener("click", () => {
      const existing = document.getElementById("vidplus-player");
      if (existing) {
        existing.remove();
        return;
      }
      const iframe = createIframe(url);
      const target = document.querySelector("main");
      if (target) target.before(iframe);
    });

    document.body.appendChild(btn);
  }

  // ---------- Init ----------
  function init() {
    if (location.pathname.includes("/episodes")) {
      insertEpisodeButtons();
      const mo = new MutationObserver(() => insertEpisodeButtons());
      mo.observe(document.body, { childList: true, subtree: true });
    } else if (document.title.includes("TV Series") ||
               document.title.includes("TV Mini Series")) {
      styleEpisodeGuide();
    } else {
      addMovieButton();
    }
  }

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