TVMaze: add BTN search to calendar

Add BTN search to calendar at TVMaze

  1. // ==UserScript==
  2. // @name TVMaze: add BTN search to calendar
  3. // @description Add BTN search to calendar at TVMaze
  4. // @namespace BlackNullerNS
  5. // @include http*://www.tvmaze.com/calendar*
  6. // @version 1.1
  7. // @grant GM_xmlhttpRequest
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // ==/UserScript==
  11.  
  12. var episodes = document.querySelectorAll(".entry:not(.watched)");
  13. var userAgent = "[UserScript] BTN + TVMaze Calendar";
  14. var btnKey = GM_getValue("BTN_KEY", false);
  15.  
  16. var style = document.createElement("style");
  17. style.textContent = "#btn-results { color: #333; position:fixed; width: 750px; max-width:90%; top:100px; left:50%; margin-left:-375px; padding:30px;display:inline-block;border:1px solid #666;border-radius:6px;-moz-box-shadow: 0px 0px 7px #2e2e2e;-webkit-box-shadow: 0px 0px 7px #2e2e2e;box-shadow: 0px 0px 7px #2e2e2e;background:#fff;z-index:200;transition:all 0.5s;transition-delay:0s; } "
  18. + "#btn-results a { color: blue; font-size: 13px; } "
  19. + "#btn-results a:hover { color: red; } ";
  20.  
  21. document.head.appendChild(style);
  22.  
  23. var getPopup = function(){
  24. var div = document.getElementById("btn-results");
  25. if (!div) {
  26. div = document.createElement("div");
  27. div.id = "btn-results";
  28. document.body.appendChild(div);
  29. }
  30.  
  31. div.textContent = "";
  32.  
  33. return div;
  34. };
  35.  
  36. function humanizeSize(size) {
  37. var i = Math.floor( Math.log(size) / Math.log(1024) );
  38. return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
  39. };
  40.  
  41. var showResults = function(show, ep, torrents)
  42. {
  43. torrents = Object.keys(torrents).map(function (key) {return torrents[key]});
  44. console.log(torrents);
  45.  
  46. var div = getPopup();
  47. div.appendChild(document.createTextNode(show + " " + ep));
  48. div.appendChild(document.createElement("br"));
  49. div.appendChild(document.createElement("br"));
  50.  
  51. torrents.sort(function(a, b){
  52. if(a.Resolution > b.Resolution) return -1;
  53. if(a.Resolution < b.Resolution) return 1;
  54. return 0;
  55. });
  56.  
  57. var torrent, item;
  58.  
  59. for (var i = 0, l = torrents.length; i < l; i++) {
  60. item = torrents[i];
  61.  
  62. torrent = document.createElement("a");
  63. torrent.setAttribute("href", item.DownloadURL);
  64. //torrent.textContent = [item.Container, item.Codec, item.Source, item.Resolution, item.Origin].join(" / ");
  65. torrent.textContent = item.ReleaseName + (item.Category === "Episode" ? "." + item.Container.toLowerCase() : "");
  66.  
  67. if (item.Origin === "Internal") {
  68. torrent.style.color = "#339900";
  69. } else if (item.Origin === "Scene") {
  70. torrent.style.color = "grey";
  71. }
  72.  
  73. div.appendChild(torrent);
  74. div.appendChild(document.createTextNode(" [" + item.Origin + "]"));
  75. div.appendChild(document.createTextNode(" [" + humanizeSize(item.Size) + "]"));
  76. div.appendChild(document.createElement("br"));
  77. }
  78.  
  79. var close = document.createElement("a");
  80. close.onclick = function(){ div.parentNode.removeChild(div); return false; };
  81. close.textContent = "[Close]";
  82. close.style.cursor = "pointer";
  83. close.style.float = "right";
  84.  
  85. var btnsearch = document.createElement("a");
  86. btnsearch.setAttribute("href", "https://broadcasthe.net/torrents.php?action=basic&searchstr=" + encodeURIComponent(show + " " + ep));
  87. btnsearch.setAttribute("target", "_blank");
  88. btnsearch.style.float = "left";
  89. btnsearch.textContent = "[Go to BTN]";
  90.  
  91. div.appendChild(document.createElement("br"));
  92. div.appendChild(close);
  93. div.appendChild(btnsearch);
  94. };
  95.  
  96. var getApiKey = function(e){
  97. GM_xmlhttpRequest({
  98. method: "GET",
  99. url: "https://broadcasthe.net/user.php?action=edit",
  100. onerror: function(){
  101. alert("BTN request failed!");
  102. },
  103. timeout: 15000,
  104. ontimeout: function(){
  105. alert("BTN request timed out!");
  106. },
  107. onload: function(response){
  108. var key = response.responseText.split('id="apikey" value="')[1].split('"')[0];
  109. if (key.length === 32) {
  110. btnKey = key;
  111. GM_setValue("BTN_KEY", btnKey);
  112. searchBTNHandler(e);
  113. } else {
  114. alert("Unable to retrieve BTN API key!");
  115. }
  116. }
  117. });
  118. };
  119.  
  120. var searchBTNHandler = function(e){
  121. if (!btnKey) {
  122. getApiKey(e);
  123. return;
  124. }
  125.  
  126. var show = e.target.parentNode.querySelector('a[href*="shows/"]').textContent.trim();
  127. var ep = e.target.parentNode.querySelector('a[href*="episodes/"]').textContent.trim();
  128.  
  129. if (/^\d{1,2}x\d{2}$/.test(ep)) {
  130. ep = "S" + (ep.split("x")[0].length === 1 ? "0" : "") + ep.replace("x", "E");
  131. }
  132.  
  133. var data = {
  134. method: "getTorrents",
  135. params: [
  136. btnKey, {
  137. Series: (show.replace(/[']+/g, "%") + "%").replace(/[%]+/g, '%'),
  138. Category: "Episode",
  139. Name: ep + "%"
  140. },
  141. 50
  142. ],
  143. id: Date.now()
  144. };
  145.  
  146. console.log(data);
  147.  
  148. GM_xmlhttpRequest({
  149. method: "POST",
  150. url: "https://api.broadcasthe.net/",
  151. headers: {
  152. 'Content-Type': 'application/json',
  153. 'User-Agent': userAgent
  154. },
  155. data: JSON.stringify(data),
  156. onerror: function(){
  157. alert("BTN request failed!");
  158. },
  159. timeout: 15000,
  160. ontimeout: function(){
  161. alert("BTN request timed out!");
  162. },
  163. onload: function(response){
  164. try {
  165. var data = JSON.parse(response.responseText);
  166. } catch (e) {
  167. console.log(response.responseText);
  168. alert("Unexpected response from BTN");
  169. return;
  170. }
  171.  
  172. if (!data.result || data.result.results == 0) {
  173.  
  174. var season = ep.split("E")[0].slice(1);
  175. if (season[0] === "0") season = season[1];
  176.  
  177. GM_xmlhttpRequest({
  178. method: "POST",
  179. url: "https://api.broadcasthe.net/",
  180. headers: {
  181. 'Content-Type': 'application/json',
  182. 'User-Agent': userAgent
  183. },
  184. data: JSON.stringify({
  185. method: "getTorrents",
  186. params: [
  187. btnKey, {
  188. Series: show + "%",
  189. Category: "Season",
  190. Name: "Season " + season
  191. },
  192. 50
  193. ],
  194. id: Date.now()
  195. }),
  196. onerror: function(){
  197. alert("BTN request failed!");
  198. },
  199. timeout: 15000,
  200. ontimeout: function(){
  201. alert("BTN request timed out!");
  202. },
  203. onload: function(response){
  204. try {
  205. var data = JSON.parse(response.responseText);
  206. } catch (e) {
  207. alert("Unexpected response from BTN");
  208. return;
  209. }
  210.  
  211. if (!data.result || data.result.results == 0) {
  212. var div = document.createElement('div');
  213. div.style.width = '100%';
  214. div.style.top = 0;
  215. div.style.left = 0;
  216. div.style.right = 0;
  217. div.style.position = 'fixed';
  218. div.style.backgroundColor = '#c00';
  219. div.style.color = '#fff';
  220. div.style.padding = '18px';
  221. div.style.textAlign = 'center';
  222. div.textContent = 'Not found on BTN!';
  223.  
  224. document.body.appendChild(div);
  225.  
  226. setTimeout(function() {
  227. div.remove();
  228. }, 800);
  229.  
  230. return;
  231. }
  232.  
  233. showResults(show, ep, data.result.torrents);
  234. }
  235. });
  236.  
  237. return;
  238. }
  239.  
  240. showResults(show, ep, data.result.torrents);
  241. }
  242. });
  243. };
  244.  
  245. (function () {
  246. var btn = document.createElement('button');
  247. btn.innerHTML = '&#128269;';
  248. btn.style.border = 0;
  249. btn.style.padding = '2px 4px';
  250. btn.style.background = 'transparent';
  251. btn.style.color = '#3C948B';
  252. btn.style.cursor = 'pointer';
  253. btn.setAttribute('title', 'Find on BTN');
  254.  
  255. var cloned;
  256.  
  257. for (var i = 0, l = episodes.length; i < l; i++) {
  258. cloned = btn.cloneNode(true);
  259. cloned.addEventListener('click', searchBTNHandler);
  260. episodes.item(i).firstElementChild.appendChild(cloned);
  261. }
  262. })();