TrakTheSources

Sources movies and tv episodes for Trakt.tv

目前为 2015-03-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TrakTheSources
  3. // @namespace http://tribuadore.github.io/TrakTheSources
  4. // @version 0.4.2
  5. // @author Tribuadore
  6. // @description Sources movies and tv episodes for Trakt.tv
  7. // @domain trakt.tv
  8. // @domain raw.github.com
  9. // @include http://trakt.tv/*
  10. // @include https://trakt.tv/*
  11. // @grant GM_xmlhttpRequest
  12. // @run-at document-end
  13. // @license MIT License
  14. // ==/UserScript==
  15.  
  16.  
  17. var TrakTheSources = function() {
  18. if (!document.getElementById('TrakTheSources') && Select(document, document, '//p[@id="overview"]').iterateNext()) {
  19. var CSS = document.createElement('style');
  20. CSS.textContent = [
  21. '#TrakTheSources {position: fixed; right: 0px; top: 50px; padding: 8px; border-bottom-left-radius: 5px; background: rgba(0, 0, 0, 1); cursor: pointer; opacity: 0.6; transition: opacity 0.5s ease 0s;}',
  22. '#TrakTheSources:hover {opacity: 1; transition: opacity 0.5s ease 0s;}',
  23. ].join('\n');
  24. document.getElementsByTagName('head')[0].appendChild(CSS);
  25. SourcesDiv = document.createElement('div');
  26. SourcesDiv.setAttribute('id', 'TrakTheSources');
  27. document.body.appendChild(SourcesDiv);
  28. //Info('v0.4.2');
  29. var Type = Text(Select(document, document.body, 'input[@id="comment-type"]/@value'));
  30. var Parsed;
  31. var Media;
  32. if (Type === 'episode') {
  33. Parsed = /^(.*) (\d+)x(\d+) ("|")(.*)("|")/.exec(document.title);
  34. Media = {
  35. Type: Type,
  36. Title: Parsed[1],
  37. Year: '\\d+',
  38. SeasonNo: Parsed[2],
  39. EpisodeNo: Parsed[3],
  40. EpisodeName: Parsed[5]
  41. };
  42. } else if (Type === 'movie') {
  43. Parsed = /^(.*) \((\d+)\)/.exec(document.title);
  44. Media = {
  45. Type: Type,
  46. Title: Parsed[1],
  47. Year: Parsed[2]
  48. };
  49. }
  50. //Info('Looking for ' + Media.Type + ' ' + Media.Title + ' (' + Media.Year + ')');
  51.  
  52. [Icefilms,
  53. Primewire
  54. ].forEach(function(Source) {
  55. Source(JSON.parse(JSON.stringify(Media)), HandleResult);
  56. });
  57. }
  58. window.setTimeout(TrakTheSources, 2000);
  59. };
  60.  
  61.  
  62. /**
  63. * Look for sources of Media from Icefilms.
  64. * @param {media} Media
  65. * @param {function} Result
  66. */
  67. var Icefilms = function(Media, Result) {
  68. var IcefilmsUrl = 'https://www.icefilms.info';
  69. var Letter = Media.Title.toLowerCase().replace('the ', '').replace('a ', '').replace(' ', '')[0].toUpperCase();
  70. var Url = IcefilmsUrl + '/' + (Media.Type === 'movie' ? 'movies' : 'tv') + '/a-z/' + Letter;
  71. //Info('Searcing "' + Url + '"...');
  72. RemoteDocument(Url, function(Document) {
  73. var Pages = Select(Document, Document.body, '//a[@href]');
  74. var Found = false;
  75. for (var Page = Pages.iterateNext(); Page; Page = Pages.iterateNext()) {
  76. var Href = Page.getAttribute('href');
  77. var Title = Page.textContent;
  78. if ((new RegExp('^' + Media.Title + ' \\(' + Media.Year + '\\)')).test(Title)) {
  79. Found = true;
  80. if (Media.Type === 'movie' && (new RegExp('^/ip\\.php\\?v=')).test(Href)) {
  81. Result({
  82. success: true,
  83. Label: 'ICEFILMS',
  84. Source: Icefilms,
  85. Media: Media,
  86. Host: IcefilmsUrl,
  87. Path: Href
  88. });
  89. } else if (Media.Type === 'episode' && (new RegExp('^/tv/series/\\d+/\\d+$')).test(Href)) {
  90. (function(Url) {
  91. RemoteDocument(Url, function(Document) {
  92. var Episodes = Select(Document, Document.body, '//a[@href]');
  93. for (var Episode = Episodes.iterateNext(); Episode; Episode = Episodes.iterateNext()) {
  94. var Href = Episode.getAttribute('href');
  95. var Title = Episode.textContent;
  96. if ((new RegExp('^/ip\\.php\\?v=').test(Href) && (new RegExp('^' + Media.SeasonNo + 'x' + Media.EpisodeNo + ' ')).test(Title))) {
  97. Result({
  98. success: true,
  99. Label: 'ICEFILMS',
  100. Source: Icefilms,
  101. Media: Media,
  102. Host: IcefilmsUrl,
  103. Path: Href
  104. });
  105. }
  106. }
  107. });
  108. }(IcefilmsUrl + Href));
  109. }
  110. }
  111. }
  112. if (!Found) {
  113. Result({
  114. success: false,
  115. Label: 'ICEFILMS',
  116. Source: Icefilms,
  117. Media: Media,
  118. Host: IcefilmsUrl
  119. });
  120. }
  121. });
  122. };
  123.  
  124.  
  125. /**
  126. * Look for sources of Media from Primewire.
  127. * @param {media} Media
  128. * @param {function} Result
  129. */
  130. var Primewire = function(Media, Result) {
  131. var PrimewireUrl = 'https://www.primewire.ag';
  132. var Url = PrimewireUrl + '/index.php?search_keywords=' + Media.Title;
  133. //Info('Searcing "' + Url + '"...');
  134. RemoteDocument(Url, function(Document) {
  135. var Pages = Select(Document, Document.body, '//div[contains(@class, "index_item")]/a[starts-with(@title, "Watch ")]');
  136. var Found = false;
  137. for (var Page = Pages.iterateNext(); Page; Page = Pages.iterateNext()) {
  138. var Title = Page.getAttribute('title');
  139. if ((new RegExp('Watch ' + Escape(Media.Title) + ' \\(' + Media.Year + '\\)')).test(Title)) {
  140. Found = true;
  141. if (Media.Type === 'episode') {
  142. //Info('Primewire: TV show ' + Title);
  143. (function(Url) {
  144. RemoteDocument(Url, function(Document) {
  145. var Episodes = Select(Document, Document.body, '//div[@class="tv_episode_item"]/a');
  146. for (var Episode = Episodes.iterateNext(); Episode; Episode = Episodes.iterateNext()) {
  147. var Href = Episode.getAttribute('href');
  148. var SeasonNo = parseInt(Media.SeasonNo, 10);
  149. var EpisodeNo = parseInt(Media.EpisodeNo, 10);
  150. if ((new RegExp('/[^/]+/season-' + SeasonNo + '-episode-' + EpisodeNo)).test(Href)) {
  151. var EpisodeName = Text(Select(Document, Episode, 'span[@class="tv_episode_name"]'))
  152. Result({
  153. success: true,
  154. Label: 'PRIMEWIRE',
  155. Source: Icefilms,
  156. Media: Media,
  157. Host: PrimewireUrl,
  158. Path: Href
  159. });
  160. }
  161. }
  162. });
  163. }(PrimewireUrl + Page.getAttribute('href')));
  164. } else {
  165. Result({
  166. success: true,
  167. Label: 'PRIMEWIRE',
  168. Source: Icefilms,
  169. Media: Media,
  170. Host: PrimewireUrl,
  171. Path: Page.getAttribute('href')
  172. });
  173. }
  174. }
  175. }
  176. if (!Found) {
  177. Result({
  178. success: false,
  179. Label: 'PRIMEWIRE',
  180. Source: Primewire,
  181. Media: Media,
  182. Host: PrimewireUrl
  183. });
  184. }
  185. });
  186. };
  187.  
  188.  
  189. /**
  190. * @param {object} Result
  191. */
  192. var HandleResult = function(Result) {
  193. //var DebugMsg = Result.Label + ': ' + Result.Media.Title;
  194. //if (Result.success && Result.Media.Type === 'episode') {
  195. // DebugMsg += ' s' + Result.Media.SeasonNo + 'e' + Result.Media.EpisodeNo + ' "' + Result.Media.EpisodeName + '"';
  196. //}
  197. //Info(DebugMsg);
  198. if (Result.success) {
  199. SourceInfo(Result.Label, Result.Host, Result.Path);
  200. } else {
  201. var NextWord = Result.Media.Title.indexOf(' ') + 1;
  202. if (NextWord > 0) {
  203. Result.Media.Title = Result.Media.Title.substring(NextWord);
  204. Result.Source(Result.Media, HandleResult);
  205. }
  206. }
  207. };
  208.  
  209.  
  210. /**
  211. * @param {string} Message
  212. */
  213. var Info = function(Message) {
  214. console.log('[TrakTheSources] ' + Message);
  215. };
  216.  
  217.  
  218. /**
  219. * @param {Object} Response
  220. */
  221. var Error = function(Response) {
  222. console.log('[TrakTheSources] ' + Response.status + ': ' + '"' + Response.statusText + '"');
  223. console.log('[TrakTheSources] ' + Response);
  224. };
  225.  
  226.  
  227. /**
  228. * @param {string} url
  229. * @param {function()} onload
  230. */
  231. var RemoteDocument = function(url, onload) {
  232. GM_xmlhttpRequest({
  233. method: 'GET',
  234. url: url,
  235. onload: function(Response) {
  236. if (Response.status != 200 && Response.status != 304) return Error(Response);
  237. var doc = document.implementation.createHTMLDocument();
  238. doc.documentElement.innerHTML = Response.responseText;
  239. onload(doc);
  240. },
  241. onabort: Error,
  242. onerror: Error,
  243. ontimeout: Error
  244. });
  245. };
  246.  
  247.  
  248. /**
  249. * @param {string} Str
  250. */
  251. var Escape = function(Str) {
  252. return Str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
  253. };
  254.  
  255.  
  256. /**
  257. * @param {string} Url
  258. * @param {string} Label
  259. */
  260. var SourceInfo = function(Label, SiteUrl, UrlPath) {
  261. var Source = document.getElementById(SiteUrl);
  262. if (!Source) {
  263. Source = document.createElement('div');
  264. Source.setAttribute('id', SiteUrl);
  265. SourcesDiv.appendChild(Source);
  266. }
  267. if (!SiteUrl) {
  268. Source.innerHTML = '<div style="color: #555; text-align: center; padding-bottom: 3px;">' + Label + '</div>';
  269. //Info(Label);
  270. } else if (!UrlPath) {
  271. Source.innerHTML = '<div style="color:#aaaaaa"><img src="' + SiteUrl + '/favicon.ico" width="20px"/> ' + Label + '</div>';
  272. //Info(Label + ' (' + SiteUrl + ')');
  273. } else {
  274. Source.innerHTML = '<div><img src="' + SiteUrl + '/favicon.ico" width="20px"/> <a target="_blank" href="' + SiteUrl + UrlPath + '"><b style="color:white">' + Label + '</b> <div class="fa fa-external-link"></div></a></div>';
  275. //Info(Label + ' (' + SiteUrl + UrlPath + ')');
  276. }
  277. };
  278.  
  279.  
  280. /**
  281. * @param {HTMLDocument} Document
  282. * @param {Object} Context
  283. * @param {string} Query
  284. * @return {Object}
  285. */
  286. var Select = function(Document, Context, Query) {
  287. return Document.evaluate(Query, Context, null, XPathResult.ANY_TYPE, null);
  288. };
  289.  
  290.  
  291. /**
  292. * @param {XPathResult} Result
  293. * @return {string}
  294. */
  295. var Text = function(Result) {
  296. var Node = Result.iterateNext();
  297. var Text = '';
  298. while (Node) {
  299. Text += Node.textContent;
  300. Node = Result.iterateNext();
  301. }
  302. return Text;
  303. };
  304.  
  305.  
  306. var SourcesDiv;
  307.  
  308. TrakTheSources();