// ==UserScript== // @name TVShow Time Watch Online // @namespace dannieboi // @version 0.3 // @description Show links to watch tv shows on To-Watch page // @author dannieboi // @match http://www.tvshowtime.com/en // @grant GM_addStyle // @downloadURL https://update.greasyfork.cloud/scripts/12819/TVShow%20Time%20Watch%20Online.user.js // @updateURL https://update.greasyfork.cloud/scripts/12819/TVShow%20Time%20Watch%20Online.meta.js // ==/UserScript== "format register"; (function(global) { var defined = {}; // indexOf polyfill for IE8 var indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) if (this[i] === item) return i; return -1; } function dedupe(deps) { var newDeps = []; for (var i = 0, l = deps.length; i < l; i++) if (indexOf.call(newDeps, deps[i]) == -1) newDeps.push(deps[i]) return newDeps; } function register(name, deps, declare, execute) { if (typeof name != 'string') throw "System.register provided no module name"; var entry; // dynamic if (typeof declare == 'boolean') { entry = { declarative: false, deps: deps, execute: execute, executingRequire: declare }; } else { // ES6 declarative entry = { declarative: true, deps: deps, declare: declare }; } entry.name = name; // we never overwrite an existing define if (!defined[name]) defined[name] = entry; entry.deps = dedupe(entry.deps); // we have to normalize dependencies // (assume dependencies are normalized for now) // entry.normalizedDeps = entry.deps.map(normalize); entry.normalizedDeps = entry.deps; } function buildGroups(entry, groups) { groups[entry.groupIndex] = groups[entry.groupIndex] || []; if (indexOf.call(groups[entry.groupIndex], entry) != -1) return; groups[entry.groupIndex].push(entry); for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) { var depName = entry.normalizedDeps[i]; var depEntry = defined[depName]; // not in the registry means already linked / ES6 if (!depEntry || depEntry.evaluated) continue; // now we know the entry is in our unlinked linkage group var depGroupIndex = entry.groupIndex + (depEntry.declarative != entry.declarative); // the group index of an entry is always the maximum if (depEntry.groupIndex === undefined || depEntry.groupIndex < depGroupIndex) { // if already in a group, remove from the old group if (depEntry.groupIndex !== undefined) { groups[depEntry.groupIndex].splice(indexOf.call(groups[depEntry.groupIndex], depEntry), 1); // if the old group is empty, then we have a mixed depndency cycle if (groups[depEntry.groupIndex].length == 0) throw new TypeError("Mixed dependency cycle detected"); } depEntry.groupIndex = depGroupIndex; } buildGroups(depEntry, groups); } } function link(name) { var startEntry = defined[name]; startEntry.groupIndex = 0; var groups = []; buildGroups(startEntry, groups); var curGroupDeclarative = !!startEntry.declarative == groups.length % 2; for (var i = groups.length - 1; i >= 0; i--) { var group = groups[i]; for (var j = 0; j < group.length; j++) { var entry = group[j]; // link each group if (curGroupDeclarative) linkDeclarativeModule(entry); else linkDynamicModule(entry); } curGroupDeclarative = !curGroupDeclarative; } } // module binding records var moduleRecords = {}; function getOrCreateModuleRecord(name) { return moduleRecords[name] || (moduleRecords[name] = { name: name, dependencies: [], exports: {}, // start from an empty module and extend importers: [] }) } function linkDeclarativeModule(entry) { // only link if already not already started linking (stops at circular) if (entry.module) return; var module = entry.module = getOrCreateModuleRecord(entry.name); var exports = entry.module.exports; var declaration = entry.declare.call(global, function(name, value) { module.locked = true; exports[name] = value; for (var i = 0, l = module.importers.length; i < l; i++) { var importerModule = module.importers[i]; if (!importerModule.locked) { var importerIndex = indexOf.call(importerModule.dependencies, module); importerModule.setters[importerIndex](exports); } } module.locked = false; return value; }); module.setters = declaration.setters; module.execute = declaration.execute; if (!module.setters || !module.execute) throw new TypeError("Invalid System.register form for " + entry.name); // now link all the module dependencies for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) { var depName = entry.normalizedDeps[i]; var depEntry = defined[depName]; var depModule = moduleRecords[depName]; // work out how to set depExports based on scenarios... var depExports; if (depModule) { depExports = depModule.exports; } else if (depEntry && !depEntry.declarative) { depExports = { 'default': depEntry.module.exports, __useDefault: true }; } // in the module registry else if (!depEntry) { depExports = load(depName); } // we have an entry -> link else { linkDeclarativeModule(depEntry); depModule = depEntry.module; depExports = depModule.exports; } // only declarative modules have dynamic bindings if (depModule && depModule.importers) { depModule.importers.push(module); module.dependencies.push(depModule); } else module.dependencies.push(null); // run the setter for this dependency if (module.setters[i]) module.setters[i](depExports); } } // An analog to loader.get covering execution of all three layers (real declarative, simulated declarative, simulated dynamic) function getModule(name) { var exports; var entry = defined[name]; if (!entry) { exports = load(name); if (!exports) throw new Error("Unable to load dependency " + name + "."); } else { if (entry.declarative) ensureEvaluated(name, []); else if (!entry.evaluated) linkDynamicModule(entry); exports = entry.module.exports; } if ((!entry || entry.declarative) && exports && exports.__useDefault) return exports['default']; return exports; } function linkDynamicModule(entry) { if (entry.module) return; var exports = {}; var module = entry.module = { exports: exports, id: entry.name }; // AMD requires execute the tree first if (!entry.executingRequire) { for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) { var depName = entry.normalizedDeps[i]; var depEntry = defined[depName]; if (depEntry) linkDynamicModule(depEntry); } } // now execute entry.evaluated = true; var output = entry.execute.call(global, function(name) { for (var i = 0, l = entry.deps.length; i < l; i++) { if (entry.deps[i] != name) continue; return getModule(entry.normalizedDeps[i]); } throw new TypeError('Module ' + name + ' not declared as a dependency.'); }, exports, module); if (output) module.exports = output; } /* * Given a module, and the list of modules for this current branch, * ensure that each of the dependencies of this module is evaluated * (unless one is a circular dependency already in the list of seen * modules, in which case we execute it) * * Then we evaluate the module itself depth-first left to right * execution to match ES6 modules */ function ensureEvaluated(moduleName, seen) { var entry = defined[moduleName]; // if already seen, that means it's an already-evaluated non circular dependency if (entry.evaluated || !entry.declarative) return; // this only applies to declarative modules which late-execute seen.push(moduleName); for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) { var depName = entry.normalizedDeps[i]; if (indexOf.call(seen, depName) == -1) { if (!defined[depName]) load(depName); else ensureEvaluated(depName, seen); } } if (entry.evaluated) return; entry.evaluated = true; entry.module.execute.call(global); } // magical execution function var modules = {}; function load(name) { if (modules[name]) return modules[name]; var entry = defined[name]; // first we check if this module has already been defined in the registry if (!entry) throw "Module " + name + " not present."; // recursively ensure that the module and all its // dependencies are linked (with dependency group handling) link(name); // now handle dependency execution in correct order ensureEvaluated(name, []); // remove from the registry defined[name] = undefined; var module = entry.declarative ? entry.module.exports : { 'default': entry.module.exports, '__useDefault': true }; // return the defined module object return modules[name] = module; }; return function(main, declare) { var System; // if there's a system loader, define onto it if (typeof System != 'undefined' && System.register) { declare(System); System['import'](main); } // otherwise, self execute else { declare(System = { register: register, get: load, set: function(name, module) { modules[name] = module; }, newModule: function(module) { return module; }, global: global }); System.set('@empty', System.newModule({})); load(main); } }; })(typeof window != 'undefined' ? window : global) /* ('mainModule', function(System) { System.register(...); }); */ ('src/run.tvshowtime', function(System) { System.register("src/core/TvShowInfo", [], function (_export) { var _createClass, _classCallCheck, TitleInfo, TvShowInfo; return { setters: [], execute: function () { "use strict"; _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; TitleInfo = (function () { function TitleInfo(title) { _classCallCheck(this, TitleInfo); this.title = title; } _createClass(TitleInfo, { raw: { get: function () { return this.title; } }, clean: { get: function () { return this.title.replace(/[:,'()\.]/g, "").replace("&", "and"); } }, dash: { get: function () { return this.clean.replace(/\s/g, "-").toLowerCase(); } }, underscore: { get: function () { return this.clean.replace(/\s/g, "_").toLowerCase(); } }, plus: { get: function () { return this.clean.replace(/\s/g, "+").toLowerCase(); } }, space: { get: function () { return this.clean.replace(/\s/g, "%20").toLowerCase(); } } }); return TitleInfo; })(); TvShowInfo = (function () { function TvShowInfo(title, season, episode, year) { _classCallCheck(this, TvShowInfo); this.title = title; this.season = season; this.episode = episode; this.year = year; } _createClass(TvShowInfo, { getTitleInfo: { value: function getTitleInfo() { return new TitleInfo(this.title); } }, getSeasonString: { value: function getSeasonString(numDigits) { if (numDigits) { return this._pad(this.season, numDigits); } return this.season.toString(); } }, getEpisodeString: { value: function getEpisodeString(numDigits) { if (numDigits) { return this._pad(this.episode, numDigits); } return this.episode.toString(); } }, _pad: { value: function _pad(num, size) { var s = num + ""; while (s.length < size) s = "0" + s; return s; } } }); return TvShowInfo; })(); _export("default", TvShowInfo); } }; }); System.register("src/core/TvShowSiteInfo", [], function (_export) { var _classCallCheck, TvShowSiteInfo; return { setters: [], execute: function () { "use strict"; _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; TvShowSiteInfo = function TvShowSiteInfo(siteName, options) { _classCallCheck(this, TvShowSiteInfo); this.siteName = siteName; this.tvShowPageUrl = options.tvShowPageUrl; this.episodePageUrl = options.episodePageUrl; this.searchUrl = options.searchUrl; this.logoUrl = options.logoUrl; }; _export("default", TvShowSiteInfo); } }; }); System.register("src/core/tvShowSitesArray", ["src/core/TvShowSiteInfo"], function (_export) { var TvShowSiteInfo; return { setters: [function (_srcCoreTvShowSiteInfo) { TvShowSiteInfo = _srcCoreTvShowSiteInfo["default"]; }], execute: function () { "use strict"; // tv show sites _export("default", [ // PutLocker TV Shows new TvShowSiteInfo("PutLocker TV Shows", { logoUrl: "http://www.iconj.com/ico/3/s/3s61b5mccc.ico", tvShowPageUrl: "http://putlockertvshows.me/watch/{TITLE_DASH}/", episodePageUrl: "http://putlockertvshows.me/watch/{TITLE_DASH}/s{SEASON_2}e{EPISODE_2}.html" }), // watch series new TvShowSiteInfo("Watch Series", { logoUrl: "http://watchseriesfree.to/favicon.ico", tvShowPageUrl: "http://watchseriesfree.to/serie/{TITLE_UNDERSCORE}", episodePageUrl: "http://watchseriesfree.to/episode/{TITLE_UNDERSCORE}_s{SEASON}_e{EPISODE}.html", searchUrl: "http://watchseriesfree.to/search/{TITLE_RAW}" }), // project free tV new TvShowSiteInfo("Project Free TV", { logoUrl: "http://cdn4.projectfreetv.so/wp-content/uploads/2015/01/favicon.ico", tvShowPageUrl: "http://projectfreetv.ch/free/{TITLE_DASH}/", episodePageUrl: "http://projectfreetv.ch/{TITLE_DASH}-season-{SEASON}-episode-{EPISODE}/", searchUrl: "http://projectfreetv.ch/search/{TITLE_SPACE}" }), // netflix new TvShowSiteInfo("Netflix", { logoUrl: "http://www.netflix.com/favicon.ico", searchUrl: "http://www.netflix.com/search/{TITLE_SPACE}" }), // amazon new TvShowSiteInfo("Amazon", { logoUrl: "http://www.amazon.com/favicon.ico", searchUrl: "http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Dinstant-video&field-keywords={TITLE_PLUS}&rh=n%3A2858778011%2Ck%3A{TITLE_PLUS}" }), // hulu new TvShowSiteInfo("Hulu", { logoUrl: "http://www.hulu.com/favicon.ico", searchUrl: "http://www.hulu.com/{TITLE_DASH}" })]); } }; }); System.register("src/renderers/IconRenderer", [], function (_export) { var _createClass, _classCallCheck, IconRenderer; return { setters: [], execute: function () { "use strict"; _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; //import $ from "jquery"; IconRenderer = (function () { function IconRenderer() { _classCallCheck(this, IconRenderer); } _createClass(IconRenderer, null, { render: { value: function render(tvShowlinks, tvLinksContainSelector) { var $container = $(tvLinksContainSelector); var iconsHtml = []; for (var i = 0; i < tvShowlinks.length; i++) { var linkData = tvShowlinks[i]; var pageUrl = linkData.episodePageUrl || linkData.tvShowPageUrl || linkData.searchUrl; var iconHtml = "\n \n "; iconsHtml.push(iconHtml); } $container.append(iconsHtml.join("")); } }, addPageStyles: { value: function addPageStyles() { var css = "\n a.tv-link {\n padding-right: 2px;\n }\n\n a.tv-link img {\n width: 16px;\n height: 16px;\n -webkit-filter: grayscale(1);\n -webkit-filter: grayscale(100%);\n filter: grayscale(100%);\n filter: url(#greyscale);\n filter: gray;\n }\n\n a.tv-link img:hover {\n -webkit-filter: none;\n filter: none;\n }\n "; GM_addStyle(css); } } }); return IconRenderer; })(); _export("default", IconRenderer); } }; }); System.register("src/core/getTvShowLinksFromInfo", ["src/core/TvShowInfo", "src/core/TvShowSiteInfo", "src/core/tvShowSitesArray"], function (_export) { var TvShowInfo, TvShowSiteInfo, siteInfoArray; function setTitlePlaceholderData(str, tvShowInfo) { if (!str) { return null; }var titleInfo = tvShowInfo.getTitleInfo(); str = str.replace("{TITLE_PLUS}", titleInfo.plus); str = str.replace("{TITLE_CLEAN}", titleInfo.clean); str = str.replace("{TITLE_DASH}", titleInfo.dash); str = str.replace("{TITLE_UNDERSCORE}", titleInfo.underscore); str = str.replace("{TITLE_RAW}", titleInfo.raw); str = str.replace("{TITLE_SPACE}", titleInfo.space); str = str.replace("{SEASON}", tvShowInfo.getSeasonString()); str = str.replace("{SEASON_2}", tvShowInfo.getSeasonString(2)); str = str.replace("{EPISODE}", tvShowInfo.getEpisodeString()); str = str.replace("{EPISODE_2}", tvShowInfo.getEpisodeString(2)); return str; } return { setters: [function (_srcCoreTvShowInfo) { TvShowInfo = _srcCoreTvShowInfo["default"]; }, function (_srcCoreTvShowSiteInfo) { TvShowSiteInfo = _srcCoreTvShowSiteInfo["default"]; }, function (_srcCoreTvShowSitesArray) { siteInfoArray = _srcCoreTvShowSitesArray["default"]; }], execute: function () { "use strict"; _export("default", function (tvShowInfo) { return siteInfoArray.map(function (value, index, array) { return new TvShowSiteInfo(value.siteName, { tvShowPageUrl: setTitlePlaceholderData(value.tvShowPageUrl, tvShowInfo), episodePageUrl: setTitlePlaceholderData(value.episodePageUrl, tvShowInfo), searchUrl: setTitlePlaceholderData(value.searchUrl, tvShowInfo), logoUrl: value.logoUrl }); }); }); } }; }); System.register("src/parsers/TvShowTimeParser", ["src/core/getTvShowLinksFromInfo", "src/core/TvShowInfo"], function (_export) { var getTvShowLinks, TvShowInfo, _createClass, _classCallCheck, TvShowTimeParser; return { setters: [function (_srcCoreGetTvShowLinksFromInfo) { getTvShowLinks = _srcCoreGetTvShowLinksFromInfo["default"]; }, function (_srcCoreTvShowInfo) { TvShowInfo = _srcCoreTvShowInfo["default"]; }], execute: function () { "use strict"; _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; TvShowTimeParser = (function () { function TvShowTimeParser(renderer) { _classCallCheck(this, TvShowTimeParser); this.renderer = renderer; } _createClass(TvShowTimeParser, { parse: { value: function parse() { this.renderer.addPageStyles(); this._parseElement($("ul.to-watch-list > li[id^='episode-item-']:not(.upcoming)")); var self = this; // select the target node var target = document.querySelector("ul.to-watch-list"); // configuration of the observer: var config = { childList: true }; // create an observer instance var observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { var numAddedNodes = mutation.addedNodes.length; if (numAddedNodes > 0) { for (var i = 0; i < numAddedNodes; i++) { var $node = $(mutation.addedNodes.item(i)); console.dir($node); if ($node.is("li") && $node.hasClass("episode-item") && !$node.hasClass("upcoming")) { self._parseElement($node).bind(self, $node)(); } } } }); }); // pass in the target node, as well as the observer options observer.observe(target, config); } }, _parseElement: { value: function _parseElement($element) { var _this = this; $element.each(function (index, li) { var title, season, episode, year; var $li = $(li); var episodeDetails = $li.find("div.episode-details > h2 > a").text(); var regExMatches = episodeDetails.match(/S(\d*)E(\d*)/i); season = parseInt(regExMatches[1]); episode = parseInt(regExMatches[2]); var titleDetails = $li.find("div.episode-details > a").text(); var indexOfYear = titleDetails.lastIndexOf("("); if (indexOfYear > 0) { title = titleDetails.substr(0, indexOfYear).trim(); year = parseInt(titleDetails.substring(indexOfYear + 1, titleDetails.lastIndexOf(")"))); } else { title = titleDetails; } $li.find("div.nav").prepend(""); var tvShowInfo = new TvShowInfo(title, season, episode, year); var tvShowLinks = getTvShowLinks(tvShowInfo); var tvLinksContainSelector = "#" + $li.attr("id") + "> div.nav > div.tv-links-container"; _this.renderer.render(tvShowLinks, tvLinksContainSelector); }); } } }); return TvShowTimeParser; })(); _export("default", TvShowTimeParser); } }; }); //import $ from "jquery"; System.register("src/run.tvshowtime", ["src/parsers/TvShowTimeParser", "src/renderers/IconRenderer"], function (_export) { var Parser, renderer; return { setters: [function (_srcParsersTvShowTimeParser) { Parser = _srcParsersTvShowTimeParser["default"]; }, function (_srcRenderersIconRenderer) { renderer = _srcRenderersIconRenderer["default"]; }], execute: function () { "use strict"; new Parser(renderer).parse(); } }; }); }); //# sourceMappingURL=tvshowtime.js.map