down2transmission

Add a button in torrent sites to support adding torrent to Transmission directly.

当前为 2018-12-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name down2transmission
  3. // @namespace https://github.com/coderant/
  4. // @copyright 2017, coderant
  5. // @author coderant
  6. // @icon http://pics.smotri.com/cskins/blue/smiles/bt.gif
  7. // @license https://raw.githubusercontent.com/coderant/down2transmission/master/LICENSE
  8. // @encoding utf-8
  9. // @version 1.1.10
  10. // @description Add a button in torrent sites to support adding torrent to Transmission directly.
  11. // @supportURL https://github.com/coderant/down2transmission
  12. // @match *://ccfbits.org/*
  13. // @match *://totheglory.im/*
  14. // @match *://thepiratebay.org/*
  15. // @match *://iptorrents.com/*
  16. // @require https://code.jquery.com/jquery-3.2.1.min.js
  17. // @run-at document-end
  18. // @grant GM_xmlhttpRequest
  19. // ==/UserScript==
  20.  
  21. // Edit these before use.
  22. // http://192.168.1.1 for local access, input ddns for external access.
  23. // NO trailing slash(/).
  24. var transmission_url = "http://your.url.here";
  25.  
  26. // value of "rpc-port" in settings.json .
  27. var transmission_port = "9091";
  28.  
  29. // value of "rpc-url" in settings.json .
  30. var transmission_rpc_bind_address = "/transmission/";
  31.  
  32. // Authentication;
  33. var username = "your_username";
  34. var pw = "your_password";
  35.  
  36. // Can be found in direct download rss.
  37. var ipt_torrent_pass = "your_ipt_torrent_pass";
  38.  
  39. // DO NOT EDIT BELOW.
  40. var rpc_url = transmission_url + ":" + transmission_port + transmission_rpc_bind_address + "rpc";
  41. console.log("Constructed url:" + rpc_url);
  42. var $ = window.jQuery;
  43.  
  44. (function () {
  45. 'use strict';
  46. var site = window.location.href;
  47. var reCCF = /ccf/i;
  48. var reTTG = /totheglory/i;
  49. var rePira = /thepiratebay.org/i;
  50. var reIpt = /iptorrents.com/i;
  51. var baseURL = document.location.origin;
  52. var target;
  53. var buttonCSS = {
  54. 'background-color': '#B6B6B6',
  55. '-moz-border-radius': '2px',
  56. '-webkit-border-radius': '2px',
  57. 'border-radius': '2px',
  58. 'display': 'inline-block',
  59. 'cursor': 'pointer',
  60. 'color': '#000000',
  61. 'font-family': 'Verdana',
  62. 'font-size': '12px',
  63. 'padding': '2px 5px',
  64. 'text-decoration': 'none'
  65. };
  66.  
  67. if (reCCF.test(site)) {
  68. if (site.includes("browse")) {
  69. // CCF main page
  70. target = $('table[border=1][cellpadding=5]>>> td:nth-child(2):not([class])');
  71. target.each(function (i) {
  72. var pageURL = baseURL + "/" + $(this).find("a[title][href]").attr("href");
  73. var button = $('<a>', {id: "transmission_" + i, "data-detailurl": pageURL, text: "Transmission", "data-type": "ccf-main"});
  74. var resultText = $('<a>', {id: "transmission_" + i + "_result", text: "", style: "padding-left:5px", "data-type": "ccf-main"});
  75. button.css(buttonCSS);
  76. $(this).append(button);
  77. button.after(resultText);
  78. });
  79. }
  80. if (site.includes("details")) {
  81. // CCF detail page
  82. target = $('a[class="index"][href*=".torrent"]');
  83. var ccfTorrentUrl = baseURL + "/" + target.attr("href");
  84. var ccfDetailInsert = $('<a>', {id: "transmission", "data-detailurl": ccfTorrentUrl, text: "Transmission", "data-type": "ccf-detail"});
  85. ccfDetailInsert.css(buttonCSS);
  86. target.after(ccfDetailInsert);
  87. ccfDetailInsert.after($('<a>', {id: "transmission_result", text: "", style: "padding-left:5px", "data-type": "ccf-detail"}));
  88. target.after("<br>");
  89. }
  90. }
  91.  
  92. if (reTTG.test(site)) {
  93. if (site.includes("browse")) {
  94. // TTG main page
  95. target = $('tr[id]> td:nth-child(2)');
  96. target.each(function (i) {
  97. var page = $(this).find("a[href]").attr("href");
  98. var el = $('<a>', {id: "transmission_" + i, "data-detailurl": baseURL + page, text: "Transmission", "data-type": "ttg-main"});
  99. el.css(buttonCSS);
  100. $(this).append(el);
  101. el.after($('<a>', {id: "transmission_" + i + "_result", text: "", style: "padding-left:5px", "data-type": "ttg-main"}));
  102. });
  103. }
  104. if (site.includes("/t/")) {
  105. // TTG detail page
  106. target = $('a[class="index"][href*="zip"]');
  107. var ttgTorrentUrl = baseURL + "/" + $('a[class="index"][href*=".torrent"]').attr("href");
  108. var ttgDetailInsert = $('<a>', {id: "transmission", "data-detailurl": ttgTorrentUrl, text: "Transmission", "data-type": "ttg-detail"});
  109. ttgDetailInsert.css(buttonCSS);
  110. target.after(ttgDetailInsert);
  111. ttgDetailInsert.after($('<a>', {id: "transmission_result", text: "", style: "padding-left:5px", "data-type": "ttg-detail"}));
  112. target.after("<br>");
  113. }
  114. }
  115.  
  116. if (rePira.test(site)) {
  117. if (site.includes("/search/")) {
  118. // piratebay main page
  119. target = $('#searchResult> tbody td:nth-child(2)');
  120. target.each(function (i) {
  121. var pageURL = baseURL + "/" + $(this).find("a[title][href]").attr("href");
  122. var el = $('<a>', {id: "transmission_" + i, "data-detailurl": pageURL, text: "Transmission", "data-type": "pira-main"});
  123. el.css(buttonCSS);
  124. $(this).append(el);
  125. el.after($('<a>', {id: "transmission_" + i + "_result", text: "", style: "padding-left:5px", "data-type": "pira-main"}));
  126. el.before("<br>");
  127. });
  128. }
  129. // if (site.includes("/torrent/")) {
  130. // // piratebay detail page
  131. // target = $('.download:first> a');
  132. // var ccfTorrentUrl = baseURL + "/" + target.attr("href");
  133. // var ccfDetailInsert = $('<a>', {id: "transmission_piradetail", "data-detailurl": ccfTorrentUrl, text: "Transmission"});
  134. // ccfDetailInsert.css(buttonCSS);
  135. // target.after(ccfDetailInsert);
  136. // ccfDetailInsert.after($('<a>', {id: "transmission_piradetail_result", text: "", style: "padding-left:5px"}));
  137. // target.after("<br>");
  138. // }
  139. }
  140.  
  141. if (reIpt.test(site)) {
  142. if (site.includes("/t")) {
  143. // main page
  144. target = $('td:has(> div.ar)');
  145. target.each(function (i) {
  146. var torrentURL = baseURL + $(this).parent().find("a:has(i.fa-download)").attr("href") + "?torrent_pass=" + ipt_torrent_pass;
  147. var el = $('<a>', {id: "transmission_" + i, "data-detailurl": torrentURL, text: "Transmission", "data-type": "ipt-main"});
  148. el.css(buttonCSS);
  149. $(this).append(el);
  150. el.after($('<a>', {id: "transmission_" + i + "_result", text: "", style: "padding-left:5px", "data-type": "ipt-main"}));
  151. el.before("<br>");
  152. });
  153. }
  154. }
  155.  
  156. $('[id^=transmission]:not([id*=result]').click(function () {
  157. var id = $(this).attr('id');
  158. var type = $(this).data("type");
  159. var resultText = $("#" + id + "_result");
  160. var torrentURL;
  161. resultText.text("Submitting to Transmission...");
  162. console.log(id + " is clicked");
  163. var request;
  164. if (type.includes("ccf-main") || type.includes("ttg-main")) {
  165. console.log("main page");
  166. var torrentPage = $(this).data('detailurl');
  167. GM_xmlhttpRequest({
  168. method: "GET",
  169. url: torrentPage,
  170. onload: function (response) {
  171. console.log("Start fetching torrent details");
  172. if (type.includes("ccf-main")) {
  173. torrentURL = baseURL + "/" + $(response.responseText).find('a[href*=".torrent"]').attr('href');
  174. }
  175.  
  176. if (type.includes("ttg-main")) {
  177. torrentURL = $(response.responseText).find('td.heading:contains(种子链接)').next().children("a:first").attr("href");
  178. }
  179. console.log("Extracted torrent url: " + torrentURL);
  180. var request = {
  181. arguments: {cookies: getCookie(), filename: torrentURL},
  182. method: "torrent-add",
  183. tag: 80
  184. };
  185. console.log("request: " + request);
  186. addTorrent($("#" + id), resultText, request);
  187. }
  188. });
  189. }
  190. if (type.includes("ccf-detail") || type.includes("ttg-detail")) {
  191. console.log("detail page");
  192. torrentURL = baseURL + "/" + $('a[class="index"]:contains("torrent")').attr('href');
  193. request = {arguments: {cookies: getCookie(), filename: torrentURL}, method: "torrent-add", tag: 80};
  194. addTorrent($("#" + id), resultText, request);
  195. }
  196. if (type.includes("pira-main")) {
  197. console.log("pira-main page");
  198. torrentURL = $(this).siblings().filter('a[href^="magnet"]').attr('href');
  199. request = {arguments: {cookies: getCookie(), filename: torrentURL}, method: "torrent-add", tag: 80};
  200. addTorrent($("#" + id), resultText, request);
  201. }
  202. if (type.includes("ipt-main")) {
  203. console.log("ipt-main");
  204. torrentURL = $(this).data('detailurl');
  205. request = {arguments: {cookies: getCookie(), filename: torrentURL}, method: "torrent-add", tag: 80};
  206. addTorrent($("#" + id), resultText, request);
  207. }
  208. });
  209. })();
  210.  
  211. function addTorrent(button, result, request, sessionId, tries) {
  212. if (!tries) {
  213. tries = 0;
  214. }
  215. if (tries === 3) {
  216. alert("p2transmission: Too many Error 409: Conflict.\nCheck your transmission installation");
  217. return;
  218. }
  219. console.log("sending torrent with sessionid: (" + sessionId);
  220. console.log("sending: " + JSON.stringify(request));
  221. GM_xmlhttpRequest({
  222. method: "POST",
  223. user: username,
  224. password: pw,
  225. url: rpc_url,
  226. data: JSON.stringify(request),
  227. headers: {
  228. "X-Transmission-Session-Id": sessionId
  229. },
  230. onload: function (response) {
  231. console.log("Got response:\n" + [
  232. response.status,
  233. response.statusText,
  234. response.responseText
  235. ].join("\n"));
  236. var resultText;
  237. var success = false;
  238. var unclickable = false;
  239. var error = false;
  240. switch (response.status) {
  241. case 200: // status OK
  242. var rpcResponse = response.responseText;
  243. var rpcJSON = JSON.parse(rpcResponse);
  244. if (rpcJSON.result.toLowerCase() === "success") {
  245. if ("torrent-duplicate" in rpcJSON.arguments) {
  246. resultText = "Already added: " + rpcJSON.arguments['torrent-duplicate'].name;
  247. } else {
  248. resultText = "Added: " + rpcJSON.arguments['torrent-added'].name;
  249. }
  250. success = true;
  251. } else {
  252. resultText = 'ERROR: ' + rpcJSON.result;
  253. error = true;
  254. }
  255. unclickable = true;
  256. break;
  257. case 401:
  258. resultText = "Your username/password is not correct.";
  259. error = true;
  260. break;
  261. case 409:
  262. console.log("Setting sessionId");
  263. var headers = response.responseHeaders.split("\n");
  264. console.log(headers.join("; "));
  265. for (var i in headers) {
  266. var header = headers[i].split(":");
  267. if (header[0].toLowerCase() == "x-transmission-session-id") {
  268. sessionId = header[1].trim();
  269. console.log("Got new Session ID: (" + sessionId);
  270. addTorrent(button, result, request, sessionId, tries + 1);
  271. }
  272. }
  273. break;
  274. default:
  275. resultText = "Unknown Transmission Response";
  276. error = true;
  277. alert("Unknown Transmission Response: " + response.status + " " + response.statusText);
  278. }
  279. console.log(resultText);
  280. result.text(resultText);
  281. if (unclickable) {
  282. button.unbind('click');
  283. button.css("cursor", "default");
  284. }
  285. if (success) {
  286. button.css("background-color", "#8FFFA6");
  287. }
  288. if (error) {
  289. button.css("background-color", "#FFBAC2");
  290. }
  291. }
  292. });
  293. }
  294.  
  295. function getCookie() {
  296. // from https://github.com/bulljit/Transmission-Add-Torrent-Bookmarkelet Thanks guys.
  297. var sCookie = "";
  298. var aCookie = document.cookie.split(/;[\s\xA0]*/);
  299. if (aCookie !== "") {
  300. for (var i = 0; i < aCookie.length; i++) {
  301. if (aCookie[i].search(/(^__utm|^__qc)/) == -1) {
  302. sCookie = sCookie + aCookie[i] + '; ';
  303. }
  304. }
  305. }
  306. sCookie = sCookie.replace(/;\s+$/, "");
  307. return sCookie;
  308. }