您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds buttons on IMDb to watch movies/series for free
当前为
- // ==UserScript==
- // @name IMDb Watcher
- // @namespace https://www.imdb.com/
- // @icon https://vidsrc.net/template/vidsrc-ico.png
- // @version 1.3.0
- // @description Adds buttons on IMDb to watch movies/series for free
- // @author cevoj35548
- // @license MIT
- // @match https://*.imdb.com/title/*
- // @grant GM_xmlhttpRequest
- // @connect api.themoviedb.org
- // ==/UserScript==
- (function() {
- 'use strict';
- const sources = [{
- name: 'Embed.su',
- urls: {
- movie: 'https://embed.su/embed/movie/{id}/1/1',
- tv: 'https://embed.su/embed/tv/{id}/{season}/{episode}'
- },
- color: '#9038ED',
- textColor: '#f0f0f0'
- },
- {
- name: 'SuperEmbed',
- urls: {
- movie: 'https://multiembed.mov/?video_id={id}',
- tv: 'https://multiembed.mov/?video_id={id}&s={season}&e={episode}'
- },
- color: '#5009DE',
- textColor: '#bad8eb'
- },
- {
- name: 'VidLink',
- urls: {
- movie: 'https://vidlink.pro/movie/{id}',
- tv: 'https://vidlink.pro/tv/{id}/{season}/{episode}'
- },
- tmdb: true,
- color: '#5009DE',
- textColor: '#bad8eb'
- },
- {
- name: '2Embed',
- urls: {
- movie: 'https://www.2embed.stream/embed/movie/{id}',
- tv: 'https://www.2embed.stream/embed/tv/{id}/{season}/{episode}'
- },
- color: '#0058a4',
- textColor: '#bad8eb'
- },
- {
- name: 'VidSrc',
- urls: {
- movie: 'https://vidsrc.net/embed/movie/{id}',
- tv: 'https://vidsrc.net/embed/tv/{id}/{season}/{episode}'
- },
- color: '#125784',
- textColor: '#bad8eb'
- },
- ];
- const cornerPadding = 20; // Distance from the corner of the screen
- const buttonSpacing = 2; // Space between each button in the stack
- function gmRequest(options) {
- console.log("Requesting", options.url)
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- ...options,
- method: "GET",
- onload: (response) => resolve(response),
- onerror: (error) => reject(error),
- });
- });
- }
- // helper to convert imdb IDs to tmdb IDs
- // source: https://greasyfork.org/en/scripts/437200
- async function getTmdbID(imdbId) {
- console.log(`Fetching Tmdb ID for ${imdbId}`);
- return await new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: "GET",
- url: "https://api.themoviedb.org/3/find/" + imdbId + "?api_key=8d6d91941230817f7807d643736e8a49&language=en-US&external_source=imdb_id",
- onload: function(response) {
- let respJson = JSON.parse(response.responseText);
- let tmdbId = (respJson.tv_results?.[0]?.id) || (respJson.movie_results?.[0]?.id) || (respJson.tv_episode_results?.[0]?.show_id);
- if (!tmdbId) {
- reject("No Tmdb ID found");
- return;
- }
- console.log(`Tmdb Id: ${tmdbId}`);
- resolve(tmdbId);
- },
- });
- });
- }
- // extract season and episode numbers from the IMDb page
- function extractSeasonEpisode() {
- const seasonEpisodeDiv = document.querySelector('[data-testid="hero-subnav-bar-season-episode-numbers-section"]');
- if (seasonEpisodeDiv) {
- const seasonEpisodeText = seasonEpisodeDiv.textContent.trim();
- const match = seasonEpisodeText.match(/S(\d+).E(\d+)/);
- if (match) {
- return {
- season: match[1],
- episode: match[2]
- };
- }
- }
- return null;
- }
- // extract the series ID from the IMDb page
- function extractSeriesId() {
- const seriesLink = document.querySelector('[data-testid="hero-title-block__series-link"]');
- if (seriesLink) {
- const href = seriesLink.getAttribute('href');
- const match = href.match(/\/title\/(tt\d+)\//);
- if (match) {
- return match[1];
- }
- }
- return null;
- }
- // generate the URL for a specific source
- async function generateUrl(urls, isMovie, isEpisode, imdbId, seriesId, seasonEpisode, isTmdb) {
- // get original ID
- imdbId = seriesId || imdbId;
- if (isTmdb) {
- imdbId = await getTmdbID(imdbId);
- }
- if (isMovie && isEpisode) {
- return urls.movie.replace('{id}', imdbId);
- }
- if (seasonEpisode && seriesId) {
- const { season, episode } = seasonEpisode;
- return urls.tv.replace('{id}', imdbId).replace('{season}', season).replace('{episode}', episode);
- } else {
- // console.log("Found no season/episode pair. Using s01e01")
- return urls.tv.replace('{id}', imdbId).replace('{season}', '1').replace('{episode}', '1');
- }
- }
- sources.reverse().forEach((source, index) => {
- const button = document.createElement('button');
- button.textContent = `📽 Watch - ${source.name}`;
- button.style.fontFamily = 'Arial';
- button.style.position = 'fixed';
- button.style.bottom = `${cornerPadding + index * (40 + buttonSpacing)}px`;
- button.style.right = `${cornerPadding}px`;
- button.style.padding = '10px';
- button.style.background = source.color;
- button.style.color = source.textColor;
- button.style.border = 'none';
- button.style.cursor = 'pointer';
- button.style.fontWeight = 'bold';
- button.style.borderRadius = '6px';
- button.style.zIndex = '9999';
- button.style.filter = 'drop-shadow(0 10px 8px rgb(0 0 0 / 0.05)) drop-shadow(0 4px 3px rgb(0 0 0 / 0.1))';
- let originalText = null;
- let disableBtn = () => {
- originalText = button.textContent;
- button.textContent = "⏳ Loading...";
- button.disabled = true;
- };
- let enableBtn = () => {
- button.textContent = originalText;
- button.disabled = false;
- };
- // add click event to redirect to the source URL
- button.addEventListener('click', () => {
- disableBtn();
- const imdbId = window.location.pathname.split('/')[2];
- const isMovie = document.title.indexOf('TV Series') === -1;
- const isEpisode = document.title.indexOf('TV Episode') === -1;
- const seasonEpisode = extractSeasonEpisode();
- const seriesId = extractSeriesId();
- generateUrl(source.urls, isMovie, isEpisode, imdbId, seriesId, seasonEpisode, !!source.tmdb)
- .then(url => {
- console.log(`Opening ${url}`)
- window.open(url, '_blank');
- enableBtn();
- })
- .catch(error => {
- console.error("Error generating URL:", error);
- enableBtn();
- alert(`Failed to generate URL: ${error}`);
- });
- });
- document.body.appendChild(button);
- });
- })();