Raw Source
Tribuadore / TrakTheSources

// ==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();