// ==UserScript==
// @name TrakTheSources
// @namespace http://tribuadore.github.io/TrakTheSources
// @version 0.4.1
// @author Tribuadore
// @description Sources movies and tv episodes for Trakt.tv
// @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.1');
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: 'My ' + 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();