IMDb Watcher

Adds buttons on IMDb to watch movies/series for free

当前为 2025-01-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name IMDb Watcher
  3. // @namespace https://www.imdb.com/
  4. // @icon https://vidsrc.net/template/vidsrc-ico.png
  5. // @version 1.1.1
  6. // @description Adds buttons on IMDb to watch movies/series for free
  7. // @author cevoj35548 (orig. Undefined42)
  8. // @license MIT
  9. // @match https://*.imdb.com/title/*
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const sources = [
  17. {
  18. name: 'Embed.su',
  19. urls: {
  20. movie: 'https://embed.su/embed/movie/{id}/1/1',
  21. tv: 'https://embed.su/embed/tv/{id}/1/1',
  22. tvEp: 'https://embed.su/embed/tv/{id}/{season}/{episode}'
  23. },
  24. color: '#9038ED',
  25. textColor: '#f0f0f0'
  26. },
  27. {
  28. name: 'SuperEmbed',
  29. urls: {
  30. movie: 'https://multiembed.mov/?video_id={id}',
  31. tv: 'https://multiembed.mov/?video_id={id}',
  32. tvEp: 'https://multiembed.mov/?video_id={id}&s={season}&e={episode}'
  33. },
  34. color: '#5009DE',
  35. textColor: '#bad8eb'
  36. },
  37. {
  38. name: '2Embed',
  39. urls: {
  40. movie: 'https://www.2embed.stream/embed/movie/{id}',
  41. tv: 'https://www.2embed.stream/embed/tv/{id}',
  42. tvEp: 'https://www.2embed.stream/embed/tv/{id}/{season}/{episode}'
  43. },
  44. color: '#0058a4',
  45. textColor: '#bad8eb'
  46. },
  47. {
  48. name: 'VidSrc',
  49. urls: {
  50. movie: 'https://vidsrc.net/embed/movie/{id}',
  51. tv: 'https://vidsrc.net/embed/tv/{id}',
  52. tvEp: 'https://vidsrc.net/embed/tv/{id}/{season}/{episode}'
  53. },
  54. color: '#125784',
  55. textColor: '#bad8eb'
  56. },
  57. ];
  58.  
  59. const cornerPadding = 20; // Distance from the corner of the screen
  60. const buttonSpacing = 2; // Space between each button in the stack
  61.  
  62. // extract season and episode numbers from the IMDb page
  63. function extractSeasonEpisode() {
  64. const seasonEpisodeDiv = document.querySelector('[data-testid="hero-subnav-bar-season-episode-numbers-section"]');
  65. if (seasonEpisodeDiv) {
  66. const seasonEpisodeText = seasonEpisodeDiv.textContent.trim();
  67. const match = seasonEpisodeText.match(/S(\d+).E(\d+)/);
  68. if (match) {
  69. return {
  70. season: match[1],
  71. episode: match[2]
  72. };
  73. }
  74. }
  75. return null;
  76. }
  77.  
  78. // extract the series ID from the IMDb page
  79. function extractSeriesId() {
  80. const seriesLink = document.querySelector('[data-testid="hero-title-block__series-link"]');
  81. if (seriesLink) {
  82. const href = seriesLink.getAttribute('href');
  83. const match = href.match(/\/title\/(tt\d+)\//);
  84. if (match) {
  85. return match[1];
  86. }
  87. }
  88. return null;
  89. }
  90.  
  91. // generate the URL for a specific source
  92. function generateUrl(urls, isMovie, isEpisode, imdbId, seriesId, seasonEpisode) {
  93. if (isMovie && isEpisode) {
  94. return urls.movie.replace('{id}', imdbId);
  95. } else if (seasonEpisode && seriesId) {
  96. const { season, episode } = seasonEpisode;
  97. return urls.tvEp.replace('{id}', seriesId).replace('{season}', season).replace('{episode}', episode);
  98. } else {
  99. return urls.tv.replace('{id}', imdbId);
  100. }
  101. }
  102.  
  103. sources.reverse().forEach((source, index) => {
  104. const button = document.createElement('button');
  105. button.textContent = `📽 Watch - ${source.name}`;
  106. button.style.fontFamily = 'Arial';
  107. button.style.position = 'fixed';
  108. button.style.bottom = `${cornerPadding + index * (40 + buttonSpacing)}px`;
  109. button.style.right = `${cornerPadding}px`;
  110. button.style.padding = '10px';
  111. button.style.background = source.color;
  112. button.style.color = source.textColor;
  113. button.style.border = 'none';
  114. button.style.cursor = 'pointer';
  115. button.style.fontWeight = 'bold';
  116. button.style.borderRadius = '6px';
  117. button.style.zIndex = '9999';
  118. 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))';
  119.  
  120. // add click event to redirect to the source URL
  121. button.addEventListener('click', () => {
  122. const imdbId = window.location.pathname.split('/')[2];
  123. const isMovie = document.title.indexOf('TV Series') === -1;
  124. const isEpisode = document.title.indexOf('TV Episode') === -1;
  125. const seasonEpisode = extractSeasonEpisode();
  126. const seriesId = extractSeriesId();
  127. const url = generateUrl(source.urls, isMovie, isEpisode, imdbId, seriesId, seasonEpisode);
  128. window.open(url, '_blank');
  129. });
  130.  
  131. document.body.appendChild(button);
  132. });
  133. })();