NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name TrakTheSources // @namespace http://tribuadore.github.io/TrakTheSources // @version 0.4.2 // @author Tribuadore // @description Sources movies and tv episodes for Trakt.tv // @updateURL https://raw.githubusercontent.com/Tribuadore/TrakTheSources/gh-pages/TrakTheSources.user.js // @downloadURL https://raw.githubusercontent.com/Tribuadore/TrakTheSources/gh-pages/TrakTheSources.user.js // @domain trakt.tv // @domain raw.github.com // @include http://trakt.tv/* // @include https://trakt.tv/* // @grant GM_xmlhttpRequest // @run-at document-end // @license MIT License // ==/UserScript== var TrakTheSources = function() { if (!document.getElementById('TrakTheSources') && Select(document, document, '//p[@id="overview"]').iterateNext()) { var CSS = document.createElement('style'); CSS.textContent = [ '#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;}', '#TrakTheSources:hover {opacity: 1; transition: opacity 0.5s ease 0s;}', ].join('\n'); document.getElementsByTagName('head')[0].appendChild(CSS); SourcesDiv = document.createElement('div'); SourcesDiv.setAttribute('id', 'TrakTheSources'); document.body.appendChild(SourcesDiv); //Info('v0.4.2'); var Type = Text(Select(document, document.body, 'input[@id="comment-type"]/@value')); var Parsed; var Media; if (Type === 'episode') { Parsed = /^(.*) (\d+)x(\d+) ("|")(.*)("|")/.exec(document.title); Media = { Type: Type, Title: Parsed[1], Year: '\\d+', SeasonNo: Parsed[2], EpisodeNo: Parsed[3], EpisodeName: Parsed[5] }; } else if (Type === 'movie') { Parsed = /^(.*) \((\d+)\)/.exec(document.title); Media = { Type: Type, Title: Parsed[1], Year: Parsed[2] }; } //Info('Looking for ' + Media.Type + ' ' + Media.Title + ' (' + Media.Year + ')'); [Icefilms, Primewire ].forEach(function(Source) { Source(JSON.parse(JSON.stringify(Media)), HandleResult); }); } window.setTimeout(TrakTheSources, 2000); }; /** * Look for sources of Media from Icefilms. * @param {media} Media * @param {function} Result */ var Icefilms = function(Media, Result) { var IcefilmsUrl = 'https://www.icefilms.info'; var Letter = Media.Title.toLowerCase().replace('the ', '').replace('a ', '').replace(' ', '')[0].toUpperCase(); var Url = IcefilmsUrl + '/' + (Media.Type === 'movie' ? 'movies' : 'tv') + '/a-z/' + Letter; //Info('Searcing "' + Url + '"...'); RemoteDocument(Url, function(Document) { var Pages = Select(Document, Document.body, '//a[@href]'); var Found = false; for (var Page = Pages.iterateNext(); Page; Page = Pages.iterateNext()) { var Href = Page.getAttribute('href'); var Title = Page.textContent; if ((new RegExp('^' + Media.Title + ' \\(' + Media.Year + '\\)')).test(Title)) { Found = true; if (Media.Type === 'movie' && (new RegExp('^/ip\\.php\\?v=')).test(Href)) { Result({ success: true, Label: 'ICEFILMS', Source: Icefilms, Media: Media, Host: IcefilmsUrl, Path: Href }); } else if (Media.Type === 'episode' && (new RegExp('^/tv/series/\\d+/\\d+$')).test(Href)) { (function(Url) { RemoteDocument(Url, function(Document) { var Episodes = Select(Document, Document.body, '//a[@href]'); for (var Episode = Episodes.iterateNext(); Episode; Episode = Episodes.iterateNext()) { var Href = Episode.getAttribute('href'); var Title = Episode.textContent; if ((new RegExp('^/ip\\.php\\?v=').test(Href) && (new RegExp('^' + Media.SeasonNo + 'x' + Media.EpisodeNo + ' ')).test(Title))) { Result({ success: true, Label: 'ICEFILMS', Source: Icefilms, Media: Media, Host: IcefilmsUrl, Path: Href }); } } }); }(IcefilmsUrl + Href)); } } } if (!Found) { Result({ success: false, Label: 'ICEFILMS', Source: Icefilms, Media: Media, Host: IcefilmsUrl }); } }); }; /** * Look for sources of Media from Primewire. * @param {media} Media * @param {function} Result */ var Primewire = function(Media, Result) { var PrimewireUrl = 'https://www.primewire.ag'; var Url = PrimewireUrl + '/index.php?search_keywords=' + Media.Title; //Info('Searcing "' + Url + '"...'); RemoteDocument(Url, function(Document) { var Pages = Select(Document, Document.body, '//div[contains(@class, "index_item")]/a[starts-with(@title, "Watch ")]'); var Found = false; for (var Page = Pages.iterateNext(); Page; Page = Pages.iterateNext()) { var Title = Page.getAttribute('title'); if ((new RegExp('Watch ' + Escape(Media.Title) + ' \\(' + Media.Year + '\\)')).test(Title)) { Found = true; if (Media.Type === 'episode') { //Info('Primewire: TV show ' + Title); (function(Url) { RemoteDocument(Url, function(Document) { var Episodes = Select(Document, Document.body, '//div[@class="tv_episode_item"]/a'); for (var Episode = Episodes.iterateNext(); Episode; Episode = Episodes.iterateNext()) { var Href = Episode.getAttribute('href'); var SeasonNo = parseInt(Media.SeasonNo, 10); var EpisodeNo = parseInt(Media.EpisodeNo, 10); if ((new RegExp('/[^/]+/season-' + SeasonNo + '-episode-' + EpisodeNo)).test(Href)) { var EpisodeName = Text(Select(Document, Episode, 'span[@class="tv_episode_name"]')) Result({ success: true, Label: 'PRIMEWIRE', Source: Icefilms, Media: Media, Host: PrimewireUrl, Path: Href }); } } }); }(PrimewireUrl + Page.getAttribute('href'))); } else { Result({ success: true, Label: 'PRIMEWIRE', Source: Icefilms, Media: Media, Host: PrimewireUrl, Path: Page.getAttribute('href') }); } } } if (!Found) { Result({ success: false, Label: 'PRIMEWIRE', Source: Primewire, Media: Media, Host: PrimewireUrl }); } }); }; /** * @param {object} Result */ var HandleResult = function(Result) { //var DebugMsg = Result.Label + ': ' + Result.Media.Title; //if (Result.success && Result.Media.Type === 'episode') { // DebugMsg += ' s' + Result.Media.SeasonNo + 'e' + Result.Media.EpisodeNo + ' "' + Result.Media.EpisodeName + '"'; //} //Info(DebugMsg); if (Result.success) { SourceInfo(Result.Label, Result.Host, Result.Path); } else { var NextWord = Result.Media.Title.indexOf(' ') + 1; if (NextWord > 0) { Result.Media.Title = Result.Media.Title.substring(NextWord); Result.Source(Result.Media, HandleResult); } } }; /** * @param {string} Message */ var Info = function(Message) { console.log('[TrakTheSources] ' + Message); }; /** * @param {Object} Response */ var Error = function(Response) { console.log('[TrakTheSources] ' + Response.status + ': ' + '"' + Response.statusText + '"'); console.log('[TrakTheSources] ' + Response); }; /** * @param {string} url * @param {function()} onload */ var RemoteDocument = function(url, onload) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(Response) { if (Response.status != 200 && Response.status != 304) return Error(Response); var doc = document.implementation.createHTMLDocument(); doc.documentElement.innerHTML = Response.responseText; onload(doc); }, onabort: Error, onerror: Error, ontimeout: Error }); }; /** * @param {string} Str */ var Escape = function(Str) { return Str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); }; /** * @param {string} Url * @param {string} Label */ var SourceInfo = function(Label, SiteUrl, UrlPath) { var Source = document.getElementById(SiteUrl); if (!Source) { Source = document.createElement('div'); Source.setAttribute('id', SiteUrl); SourcesDiv.appendChild(Source); } if (!SiteUrl) { Source.innerHTML = '<div style="color: #555; text-align: center; padding-bottom: 3px;">' + Label + '</div>'; //Info(Label); } else if (!UrlPath) { Source.innerHTML = '<div style="color:#aaaaaa"><img src="' + SiteUrl + '/favicon.ico" width="20px"/> ' + Label + '</div>'; //Info(Label + ' (' + SiteUrl + ')'); } else { 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>'; //Info(Label + ' (' + SiteUrl + UrlPath + ')'); } }; /** * @param {HTMLDocument} Document * @param {Object} Context * @param {string} Query * @return {Object} */ var Select = function(Document, Context, Query) { return Document.evaluate(Query, Context, null, XPathResult.ANY_TYPE, null); }; /** * @param {XPathResult} Result * @return {string} */ var Text = function(Result) { var Node = Result.iterateNext(); var Text = ''; while (Node) { Text += Node.textContent; Node = Result.iterateNext(); } return Text; }; var SourcesDiv; TrakTheSources();