this transmission-rpc adaptation is still a little broken, but it'll be ready soon.
This commit is contained in:
16
README.md
16
README.md
@@ -1,14 +1,14 @@
|
||||
I2P in Private Browsing Mode(Firefox-Only)
|
||||
==========================================
|
||||
|
||||
This is an **Experimental** webextension which introduces a set of new "Private
|
||||
Browsing" modes to Firefox-based browsers(Supporting webextensions) that makes
|
||||
it easier to configure a browser to use I2P securely and adds features for
|
||||
making I2P applications easier to use. It does this by isolating I2P-specific
|
||||
settings to Contextual Identities within Firefox, then loading them
|
||||
automatically when the user requests them. It also adds convenience and
|
||||
management features specific to I2P like protocol handlers and native messaging
|
||||
systems.
|
||||
This is an webextension which introduces a set of new "Private Browsing" modes
|
||||
to Firefox-based browsers(Supporting webextensions) that makes it easier to
|
||||
configure a browser to use I2P securely and adds features for making I2P
|
||||
applications easier to use. It does this by isolating I2P-specific settings to
|
||||
Contextual Identities within Firefox, then loading them automatically when the
|
||||
user requests them. It also adds convenience and management features, like an
|
||||
embedded I2P console and Bittorrent integration with clients using the
|
||||
transmission-rpc API.
|
||||
|
||||
Installation(Cross-Platform):
|
||||
-----------------------------
|
||||
|
||||
@@ -93,7 +93,7 @@ gettingInfo.then(got => {
|
||||
let port = info.value.http.split(":")[1];
|
||||
if (port == "7644") {
|
||||
var createBookmark = browser.bookmarks.create({
|
||||
url: "http://localhost:7647/i2ptunnelmgr",
|
||||
url: "http://localhost:7647/i2ptunnel",
|
||||
title: "Hidden Services Manager",
|
||||
parentId: bookmarkToolbar[0].id
|
||||
});
|
||||
@@ -101,11 +101,7 @@ gettingInfo.then(got => {
|
||||
} else {
|
||||
var createRhizomeBookmark = browser.bookmarks.create({
|
||||
url:
|
||||
"http://" +
|
||||
control_host +
|
||||
":" +
|
||||
control_port +
|
||||
"/i2ptunnelmgr",
|
||||
"http://" + control_host + ":" + control_port + "/i2ptunnel",
|
||||
title: "Hidden Services Manager",
|
||||
parentId: bookmarkToolbar[0].id
|
||||
});
|
||||
|
||||
12
home.html
12
home.html
@@ -87,19 +87,23 @@
|
||||
</li>-->
|
||||
|
||||
<li class="application">
|
||||
<a class="applicationName" href="toopie.html" id="window-visit-toopie" target="_blank">Toopie</a> <span class="applicationDesc" id="toopie">For information about your I2P router status, go here:</span>
|
||||
<a class="applicationName" href="toopie.html" id="window-visit-toopie">Toopie</a> <span class="applicationDesc" id="toopie">For information about your I2P router status, go here:</span>
|
||||
</li>
|
||||
|
||||
<li class="application">
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/i2ptunnel" id="window-visit-i2ptunnel" target="_blank">Hidden Services Manager</a> <span class="applicationDesc" id="i2ptunnel">I2P has a web-based interface for configuring .i2p services like web sites, to set up your own web sites, go here:</span>
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/" id="window-visit-router">Router Console</a> <span class="applicationDesc" id="routerconsole">The entrypoint for all other I2P applications is the I2P Router Console. To visit it, click here.</span>
|
||||
</li>
|
||||
|
||||
<li class="application">
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/susimail" id="window-visit-susimail" target="_blank">E-Mail</a> <span class="applicationDesc" id="susimail">I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here:</span>
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/i2ptunnel" id="window-visit-i2ptunnel">Hidden Services Manager</a> <span class="applicationDesc" id="i2ptunnel">I2P has a web-based interface for configuring .i2p services like web sites, to set up your own web sites, go here:</span>
|
||||
</li>
|
||||
|
||||
<li class="application">
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/i2psnark" id="window-visit-snark" target="_blank">BitTorrent</a> <span class="applicationDesc" id="snark">I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client go here:</span>
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/susimail" id="window-visit-susimail">E-Mail</a> <span class="applicationDesc" id="susimail">I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here:</span>
|
||||
</li>
|
||||
|
||||
<li class="application">
|
||||
<a class="applicationName" href="http://127.0.0.1:7657/i2psnark" id="window-visit-snark">BitTorrent</a> <span class="applicationDesc" id="snark">I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client go here:</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
BIN
i2ppb@eyedeekay.github.io.xpi
Normal file
BIN
i2ppb@eyedeekay.github.io.xpi
Normal file
Binary file not shown.
4
info.js
4
info.js
@@ -87,7 +87,7 @@ document.addEventListener("click", clickEvent => {
|
||||
showBrowsing();
|
||||
} else if (clickEvent.target.id === "torrent-action") {
|
||||
console.log("showing a torrent action");
|
||||
showTorrents();
|
||||
showTorrentsMenu();
|
||||
} else if (clickEvent.target.id === "window-preface-title") {
|
||||
console.log("attempting to create homepage tab");
|
||||
goHome();
|
||||
@@ -151,7 +151,7 @@ function showBrowsing() {
|
||||
y.style.display = "none";
|
||||
}
|
||||
|
||||
function showTorrents() {
|
||||
function showTorrentsMenu() {
|
||||
var x = document.getElementById("browserpanel");
|
||||
x.style.display = "none";
|
||||
var y = document.getElementById("torrentpanel");
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
},
|
||||
"permissions": [
|
||||
"theme",
|
||||
"alarms",
|
||||
"browsingData",
|
||||
"bookmarks",
|
||||
"contextMenus",
|
||||
"management",
|
||||
"notifications",
|
||||
"proxy",
|
||||
@@ -48,7 +50,10 @@
|
||||
"page": "options/options.html"
|
||||
},
|
||||
"background": {
|
||||
"persistent": true,
|
||||
"scripts": [
|
||||
"torrent/common.js",
|
||||
"torrent/background.js",
|
||||
"config.js",
|
||||
"i2pcontrol/i2pcontrol.js",
|
||||
"host.js",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</select>
|
||||
</section>
|
||||
|
||||
<section class="scheme-options proxy-options">
|
||||
<section class="scheme-options proxy-options" id="proxy-options">
|
||||
<div class="title">
|
||||
Proxy Options
|
||||
</div>
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</section>-->
|
||||
|
||||
<section class="scheme-options control-options">
|
||||
<section class="scheme-options console-options" id="console-options">
|
||||
<div>
|
||||
<div class="title">
|
||||
Router Console Options
|
||||
@@ -49,7 +49,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="scheme-options control-options">
|
||||
<section class="scheme-options control-options" id="control-options">
|
||||
<div>
|
||||
<div class="title">
|
||||
I2PControl RPC Client Options
|
||||
@@ -66,23 +66,24 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="scheme-options control-options">
|
||||
<section class="scheme-options transmission-options" id="transmission-options">
|
||||
<div>
|
||||
<div class="title">
|
||||
Bittorrent RPC Client Options
|
||||
</div>
|
||||
|
||||
<p id="rpcHelpText">Configure your Bittorrent options here.</p>
|
||||
<label id="btRpcPortText">Torrent RPC Host:</label> <input data="btrpchost" id="btrpchost" type="text" value="127.0.0.1">
|
||||
<label id="btRpcHostText">Torrent RPC Host:</label> <input data="btrpchost" id="btrpchost" type="text" value="127.0.0.1">
|
||||
<br>
|
||||
<label id="btRpcHostText">Torrent RPC Port:</label> <input data="btrpcport" id="btrpcport" type="text" value="7657">
|
||||
<label id="btRpcPortText">Torrent RPC Port:</label> <input data="btrpcport" id="btrpcport" type="text" value="7657">
|
||||
<br>
|
||||
<label id="btRpcPathText">Torrent RPC Path:</label> <input data="btrpcpath" id="btrpcpath" type="text" value="transmission/rpc">
|
||||
<label id="btRpcPathText">Torrent RPC Path:</label> <input data="btrpcpath" id="btrpcpath" type="text" value="transmission/">
|
||||
<br>
|
||||
<label id="rpcPassText">Torrent RPC Password:</label> <input data="btrpcpass" id="btrpcpass" type="text" value="itoopie">
|
||||
<label id="rpcPassText">Torrent RPC Password:</label> <input data="btrpcpass" id="btrpcpass" type="text" value="">
|
||||
</div>
|
||||
</section>
|
||||
<input id="save-button" type="button" value="Save preferences">
|
||||
<script src="options.js"></script>
|
||||
<script src="options.js"></script> <!--<script src="/torrent/browser-polyfill.min.js"></script>
|
||||
<script src="/torrent/options.js"></script>-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -217,14 +217,23 @@ function checkStoredSettings(storedSettings) {
|
||||
} else defaultSettings["bt_rpc_pass"] = storedSettings.bt_rpc_pass;
|
||||
|
||||
console.log("(options)(browserinfo) NATIVE PROXYSETTINGS", info.value);
|
||||
defaultSettings["base_url"] =
|
||||
"http://" +
|
||||
defaultSettings["bt_rpc_host"] +
|
||||
":" +
|
||||
defaultSettings["bt_rpc_port"] +
|
||||
"/" +
|
||||
defaultSettings["bt_rpc_path"];
|
||||
console.log(
|
||||
"(options)",
|
||||
defaultSettings["proxy_sheme"],
|
||||
defaultSettings["proxy_scheme"],
|
||||
defaultSettings["proxy_host"],
|
||||
defaultSettings["proxy_port"],
|
||||
defaultSettings["control_host"],
|
||||
defaultSettings["control_port"]
|
||||
defaultSettings["control_port"],
|
||||
defaultSettings["base_url"]
|
||||
);
|
||||
|
||||
chrome.storage.local.set(defaultSettings);
|
||||
return defaultSettings;
|
||||
}
|
||||
@@ -323,6 +332,8 @@ function storeSettings() {
|
||||
let bt_rpc_port = getBTRPCPort();
|
||||
let bt_rpc_path = getBTRPCPath();
|
||||
let bt_rpc_pass = getBTRPCPass();
|
||||
let base_url =
|
||||
"http://" + bt_rpc_host + ":" + bt_rpc_port + "/" + bt_rpc_path;
|
||||
chrome.storage.local.set({
|
||||
proxy_scheme,
|
||||
proxy_host,
|
||||
|
||||
247
torrent/background.js
Normal file
247
torrent/background.js
Normal file
@@ -0,0 +1,247 @@
|
||||
"use strict";
|
||||
|
||||
////// Session extraction
|
||||
|
||||
function setupExtractor() {
|
||||
browser.webRequest.onHeadersReceived.removeListener(extractSession);
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
console.log("Session extractor setup for", server.base_url);
|
||||
browser.webRequest.onBeforeSendHeaders.addListener(
|
||||
extractSession,
|
||||
{ urls: [server.base_url + "*"] },
|
||||
["requestHeaders"]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
setupExtractor();
|
||||
|
||||
function extractSession(requestDetails) {
|
||||
const hdr = requestDetails.requestHeaders.filter(
|
||||
x => x.name.toLowerCase() === "x-transmission-session-id"
|
||||
)[0];
|
||||
if (!hdr) {
|
||||
return;
|
||||
}
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
server.session = hdr.value;
|
||||
browser.storage.local.set({ server });
|
||||
});
|
||||
}
|
||||
|
||||
////// Adding
|
||||
|
||||
function blobToBase64(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const rdr = new FileReader();
|
||||
rdr.onload = () => resolve(rdr.result.substr(rdr.result.indexOf(",") + 1));
|
||||
rdr.onerror = reject;
|
||||
rdr.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
function addUrl(torrentUrl, downloadDir) {
|
||||
let p,
|
||||
params = {};
|
||||
if (downloadDir) {
|
||||
params = { "download-dir": downloadDir };
|
||||
}
|
||||
if (torrentUrl.startsWith("magnet:")) {
|
||||
console.log("Adding magnet", torrentUrl);
|
||||
params.filename = torrentUrl;
|
||||
p = rpcCall("torrent-add", params);
|
||||
} else {
|
||||
// Download the torrent file *in the browser* to support private torrents
|
||||
console.log("Downloading torrent", torrentUrl);
|
||||
p = fetch(torrentUrl, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
})
|
||||
.then(resp => {
|
||||
if (resp.ok) {
|
||||
return resp.blob();
|
||||
}
|
||||
throw new Error("Could not download torrent");
|
||||
})
|
||||
.then(blobToBase64)
|
||||
.then(b64 => {
|
||||
params.metainfo = b64;
|
||||
return rpcCall("torrent-add", params);
|
||||
});
|
||||
}
|
||||
return p.then(x => {
|
||||
updateBadge();
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
////// magnet: Handler
|
||||
|
||||
function handleUrl(requestDetails) {
|
||||
return addUrl(
|
||||
decodeURIComponent(
|
||||
requestDetails.url.replace("http://transmitter.web-extension/", "")
|
||||
)
|
||||
).then(x => {
|
||||
return browser.storage.local.get("server").then(({ server }) => {
|
||||
return { redirectUrl: server.base_url + "web/" };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
handleUrl,
|
||||
{ urls: ["http://transmitter.web-extension/*"] },
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
////// Context menu
|
||||
|
||||
function createContextMenu() {
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
browser.contextMenus.removeAll();
|
||||
if (!server || !server.locations || !server.locations.length) {
|
||||
browser.contextMenus.create({
|
||||
id: "transmitter-add",
|
||||
title: "Download with Transmission remote",
|
||||
contexts: ["link"]
|
||||
});
|
||||
} else {
|
||||
browser.contextMenus.create({
|
||||
id: "transmitter-add",
|
||||
title: "Download to Default location",
|
||||
contexts: ["link"]
|
||||
});
|
||||
server.locations.forEach(location => {
|
||||
browser.contextMenus.create({
|
||||
id: "transmitter-add-loc-" + location.index,
|
||||
title: "Download to " + location.name,
|
||||
contexts: ["link"]
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createContextMenu();
|
||||
|
||||
browser.contextMenus.onClicked.addListener((info, tab) => {
|
||||
if (info.menuItemId === "transmitter-add") {
|
||||
return addUrl(info.linkUrl);
|
||||
} else if (info.menuItemId.startsWith("transmitter-add-loc-")) {
|
||||
let index = parseInt(info.menuItemId.substr("transmitter-add-loc-".length));
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
let path = server.locations[index].path;
|
||||
addUrl(info.linkUrl, path);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
////// Badge
|
||||
|
||||
function updateBadge() {
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
if (
|
||||
server.badge !== "num" &&
|
||||
server.badge !== "dl" &&
|
||||
server.badge !== "ul" &&
|
||||
server.badge !== "auto"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return rpcCall("session-stats", {}).then(response => {
|
||||
const args = response.arguments; // lol the name 'arguments' means destructuring in strict mode is impossible
|
||||
switch (server.badge) {
|
||||
case "num":
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "gray" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: "" + args.activeTorrentCount
|
||||
});
|
||||
break;
|
||||
case "dl":
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "green" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: formatSpeed(args.downloadSpeed)
|
||||
});
|
||||
break;
|
||||
case "ul":
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "blue" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: formatSpeed(args.uploadSpeed)
|
||||
});
|
||||
break;
|
||||
case "auto":
|
||||
if (args.downloadSpeed > 0) {
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "green" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: formatSpeed(args.downloadSpeed)
|
||||
});
|
||||
} else if (args.uploadSpeed > 0) {
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "blue" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: formatSpeed(args.uploadSpeed)
|
||||
});
|
||||
} else {
|
||||
browser.browserAction.setBadgeBackgroundColor({ color: "gray" });
|
||||
browser.browserAction.setBadgeText({
|
||||
text: "" + args.activeTorrentCount
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
if (alarm.name === "transmitter-badge-update") {
|
||||
return updateBadge();
|
||||
}
|
||||
});
|
||||
|
||||
function setupBadge() {
|
||||
browser.alarms.clear("transmitter-badge-update").then(x => {
|
||||
browser.storage.local.get("server").then(({ server }) => {
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
browser.alarms.create("transmitter-badge-update", {
|
||||
periodInMinutes: parseInt(server.badge_interval || "1")
|
||||
});
|
||||
updateBadge();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupBadge();
|
||||
|
||||
////// Storage updates
|
||||
|
||||
browser.storage.onChanged.addListener((changes, area) => {
|
||||
if (!Object.keys(changes).includes("server")) {
|
||||
return;
|
||||
}
|
||||
const oldv = changes.server.oldValue;
|
||||
const newv = changes.server.newValue;
|
||||
if (
|
||||
!oldv ||
|
||||
oldv.base_url !== newv.base_url ||
|
||||
oldv.username !== newv.username ||
|
||||
oldv.password !== newv.password ||
|
||||
oldv.badge_interval !== newv.badge_interval ||
|
||||
oldv.badge !== newv.badge ||
|
||||
arraysEqualDeep(oldv.locations, newv.locations)
|
||||
) {
|
||||
setupExtractor();
|
||||
setupBadge();
|
||||
updateBadge();
|
||||
createContextMenu();
|
||||
}
|
||||
});
|
||||
|
||||
function arraysEqualDeep(arr1, arr2) {
|
||||
return JSON.stringify(arr1) !== JSON.stringify(arr2);
|
||||
}
|
||||
60
torrent/common.js
Normal file
60
torrent/common.js
Normal file
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
|
||||
////// RPC
|
||||
|
||||
function rpcCall(meth, args) {
|
||||
return browser.storage.local.get(function(server) {
|
||||
const myHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
"x-transmission-session-id": server.session
|
||||
};
|
||||
//console.log("(torrent)", server.session)
|
||||
if (server.username !== "" || server.btrpcpass !== "") {
|
||||
myHeaders["Authorization"] =
|
||||
"Basic " +
|
||||
btoa((server.username || "") + ":" + (server.btrpcpass || ""));
|
||||
}
|
||||
//console.log("(torrent) rpc", server.base_url);
|
||||
return fetch(server.base_url + "rpc", {
|
||||
method: "POST",
|
||||
headers: myHeaders,
|
||||
body: JSON.stringify({ method: meth, arguments: args }),
|
||||
credentials: "include" // allows HTTPS client certs!
|
||||
})
|
||||
.then(function(response) {
|
||||
const session = response.headers.get("x-transmission-session-id");
|
||||
if (session) {
|
||||
browser.storage.local.get({}).then(function(storage) {
|
||||
storage.session = session;
|
||||
browser.storage.local.set(storage);
|
||||
});
|
||||
}
|
||||
if (response.status === 409) {
|
||||
return rpcCall(meth, args);
|
||||
}
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response;
|
||||
}
|
||||
const error = new Error(response.statusText);
|
||||
error.response = response;
|
||||
throw error;
|
||||
})
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
////// Util
|
||||
|
||||
function formatSpeed(s) {
|
||||
// Firefox shows 4 characters max
|
||||
if (s < 1000 * 1000) {
|
||||
return (s / 1000).toFixed() + "K";
|
||||
}
|
||||
if (s < 1000 * 1000 * 1000) {
|
||||
return (s / 1000 / 1000).toFixed() + "M";
|
||||
}
|
||||
// You probably don't have that download speed…
|
||||
return (s / 1000 / 1000 / 1000).toFixed() + "T";
|
||||
}
|
||||
107
torrent/popup.js
Normal file
107
torrent/popup.js
Normal file
@@ -0,0 +1,107 @@
|
||||
"use strict";
|
||||
|
||||
const torrentsPane = document.getElementById("torrents-pane");
|
||||
const configPane = document.getElementById("config-pane");
|
||||
|
||||
for (const opener of document.querySelectorAll(".config-opener")) {
|
||||
opener.addEventListener("click", e => {
|
||||
browser.runtime.openOptionsPage();
|
||||
});
|
||||
}
|
||||
|
||||
function showConfig(server) {
|
||||
torrentsPane.hidden = true;
|
||||
configPane.hidden = false;
|
||||
}
|
||||
|
||||
const torrentsSearch = document.getElementById("torrents-search");
|
||||
const torrentsList = document.getElementById("torrents-list");
|
||||
const torrentsTpl = document.getElementById("torrents-tpl");
|
||||
const torrentsError = document.getElementById("torrents-error");
|
||||
const getArgs = {
|
||||
fields: ["name", "percentDone", "rateDownload", "rateUpload", "queuePosition"]
|
||||
};
|
||||
let cachedTorrents = [];
|
||||
|
||||
function renderTorrents(newTorrents) {
|
||||
if (torrentsList.children.length < newTorrents.length) {
|
||||
const dif = newTorrents.length - torrentsList.children.length;
|
||||
for (let i = 0; i < dif; i++) {
|
||||
const node = document.importNode(torrentsTpl.content, true);
|
||||
torrentsList.appendChild(node);
|
||||
}
|
||||
} else if (torrentsList.children.length > newTorrents.length) {
|
||||
const oldLen = torrentsList.children.length;
|
||||
const dif = oldLen - newTorrents.length;
|
||||
for (let i = 1; i <= dif; i++) {
|
||||
torrentsList.removeChild(torrentsList.children[oldLen - i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < newTorrents.length; i++) {
|
||||
const torr = newTorrents[i];
|
||||
const cont = torrentsList.children[i];
|
||||
const speeds =
|
||||
"↓ " +
|
||||
formatSpeed(torr.rateDownload) +
|
||||
"B/s ↑ " +
|
||||
formatSpeed(torr.rateUpload) +
|
||||
"B/s";
|
||||
cont.querySelector(".torrent-name").textContent = torr.name;
|
||||
cont.querySelector(".torrent-speeds").textContent = speeds;
|
||||
cont.querySelector(".torrent-progress").value = torr.percentDone * 100;
|
||||
}
|
||||
}
|
||||
|
||||
function searchTorrents() {
|
||||
let newTorrents = cachedTorrents;
|
||||
const val = torrentsSearch.value.toLowerCase().trim();
|
||||
if (val.length > 0) {
|
||||
newTorrents = newTorrents.filter(x => x.name.toLowerCase().includes(val));
|
||||
}
|
||||
renderTorrents(newTorrents);
|
||||
}
|
||||
torrentsSearch.addEventListener("change", searchTorrents);
|
||||
torrentsSearch.addEventListener("keyup", searchTorrents);
|
||||
|
||||
function refreshTorrents(server) {
|
||||
return rpcCall("torrent-get", getArgs).then(function(response) {
|
||||
console.log("(torrent) refreshing", response);
|
||||
let newTorrents = response.arguments.torrents;
|
||||
newTorrents.sort((x, y) => y.queuePosition - x.queuePosition);
|
||||
cachedTorrents = newTorrents;
|
||||
torrentsSearch.hidden = newTorrents.length <= 8;
|
||||
if (torrentsSearch.hidden) {
|
||||
torrentsSearch.value = "";
|
||||
renderTorrents(newTorrents);
|
||||
} else {
|
||||
searchTorrents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refreshTorrentsLogErr(server) {
|
||||
return refreshTorrents(server).catch(err => {
|
||||
console.error(err);
|
||||
torrentsError.textContent = "Error: " + err.toString();
|
||||
});
|
||||
}
|
||||
|
||||
function showTorrents(server) {
|
||||
torrentsPane.hidden = false;
|
||||
configPane.hidden = true;
|
||||
for (const opener of document.querySelectorAll(".webui-opener")) {
|
||||
opener.href = server.base_url + "web/";
|
||||
}
|
||||
refreshTorrents(server).catch(_ => refreshTorrentsLogErr(server));
|
||||
setInterval(() => refreshTorrentsLogErr(server), 2000);
|
||||
}
|
||||
|
||||
//let store =
|
||||
browser.storage.local.get(function(server) {
|
||||
console.log("(torrent) querying storage", server);
|
||||
if (server && server.base_url && server.base_url !== "") {
|
||||
showTorrents(server);
|
||||
} else {
|
||||
showConfig(server);
|
||||
}
|
||||
});
|
||||
@@ -1,91 +0,0 @@
|
||||
var hellot = "hello bittorrent";
|
||||
var xTransmissionSessionId = "";
|
||||
|
||||
function makeid(length) {
|
||||
var result = "";
|
||||
var characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
var charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function torrentsend(
|
||||
message,
|
||||
control_host = "127.0.0.1",
|
||||
control_port = "7657",
|
||||
control_path = "transmission/rpc"
|
||||
) {
|
||||
async function postData(url = "", data = {}) {
|
||||
// Default options are marked with *
|
||||
let requestBody = JSON.stringify(data);
|
||||
console.log("(torrent-rpc) send", requestBody, data);
|
||||
let opts = {
|
||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||
mode: "cors", // no-cors, *cors, same-origin
|
||||
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
|
||||
credentials: "same-origin", // include, *same-origin, omit
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Transmission-Session-Id": xTransmissionSessionId
|
||||
},
|
||||
redirect: "follow", // manual, *follow, error
|
||||
referrerPolicy: "no-referrer", // no-referrer, *client
|
||||
body: requestBody // body data type must match "Content-Type" header
|
||||
};
|
||||
const response = await fetch(url, opts);
|
||||
console.log("(torrent-rpc) response", response);
|
||||
return await response.json(); // parses JSON response into native JavaScript objects
|
||||
}
|
||||
|
||||
return postData(
|
||||
"http://" + control_host + ":" + control_port + "/" + control_path + "/",
|
||||
message
|
||||
);
|
||||
/* return postData(
|
||||
"http://" + control_host + ":" + control_port + "/" + control_path,
|
||||
message
|
||||
);*/
|
||||
}
|
||||
|
||||
function sessionStats(
|
||||
password = "transmission",
|
||||
control_host = "127.0.0.1",
|
||||
control_port = "7657",
|
||||
control_path = "transmission/rpc"
|
||||
) {
|
||||
var json = new Object();
|
||||
json["id"] = makeid(6);
|
||||
json["jsonrpc"] = "2.0";
|
||||
json["method"] = "session-stats";
|
||||
//json["params"] = new Object();
|
||||
return torrentsend(json, control_host, control_port, control_path);
|
||||
}
|
||||
|
||||
async function GetTorrentToken(
|
||||
password,
|
||||
control_host = "127.0.0.1",
|
||||
control_port = "7657",
|
||||
control_path = "transmission/rpc"
|
||||
) {
|
||||
let me = sessionStats(password);
|
||||
return await me.then(gettorrenttoken);
|
||||
}
|
||||
|
||||
function gettorrenttoken(authtoken) {
|
||||
console.log(authtoken);
|
||||
return authtoken.result.Token;
|
||||
}
|
||||
|
||||
function TorrentDone(result) {
|
||||
console.log("(torrent-rpc) recv", result);
|
||||
}
|
||||
|
||||
function TorrentError(result) {
|
||||
console.log("(torrent-rpc) recv err", result);
|
||||
}
|
||||
|
||||
var result = GetTorrentToken();
|
||||
result.then(TorrentDone, TorrentError);
|
||||
78
window.html
78
window.html
@@ -4,7 +4,8 @@
|
||||
<meta charset="utf-8">
|
||||
<link href="search.css" rel="stylesheet">
|
||||
<link href="home.css" rel="stylesheet">
|
||||
<link href="info.css" rel="stylesheet">
|
||||
<link href="info.css" rel="stylesheet"><!--<link href="torrent/popup.css" rel="stylesheet">-->
|
||||
|
||||
<title>
|
||||
</title>
|
||||
</head>
|
||||
@@ -111,26 +112,63 @@
|
||||
<p>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="torrentpanel">
|
||||
<div class="panel" id="torrentstatus">
|
||||
<div class="section-header panel-section panel-section-header">
|
||||
<div class="text-section-header" id="text-section-torrents-header">
|
||||
<h3>Torrent Downloads</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="torrentsection">
|
||||
Torrents go here.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="context.js"></script>
|
||||
<script src="privacy.js"></script>
|
||||
<script src="info.js"></script>
|
||||
<script crossorigin="anonymous" src="content.js"></script>
|
||||
<script src="i2pcontrol/i2pcontrol.js"></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="torrentpanel">
|
||||
<div class="panel" id="torrentstatus">
|
||||
<div class="section-header panel-section panel-section-header">
|
||||
<div class="text-section-header" id="text-section-torrents-header">
|
||||
<h3>Torrent Downloads</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div hidden="" id="config-pane">
|
||||
<strong>Torrent RPC Configuration</strong>
|
||||
<br>
|
||||
The server address is not set yet.
|
||||
<br>
|
||||
<a class="config-opener" href="#">Open the settings</a> to continue.
|
||||
</div>
|
||||
|
||||
<div hidden="" id="torrents-pane">
|
||||
<header>
|
||||
<h1>Torrent Controls</h1>
|
||||
<a class="webui-opener" href="#" target="_blank"><img alt="Open Web UI" src="icon.svg"></a> <!--<a class="config-opener" href="#">
|
||||
<img alt="Settings" src="gear.svg"></a>
|
||||
<a class="info-opener" href="https://github.com/myfreeweb/transmitter" target="_blank">
|
||||
<img alt="Extension Info" src="info.svg"></a>-->
|
||||
</header>
|
||||
<input id="torrents-search" placeholder="Search…" type="search">
|
||||
<template id="torrents-tpl">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="torrent-head">
|
||||
<div class="torrent-name">
|
||||
</div>
|
||||
|
||||
<div class="torrent-speeds">
|
||||
</div>
|
||||
</div>
|
||||
<progress class="torrent-progress" max="100"></progress>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<ul id="torrents-list">
|
||||
</ul>
|
||||
|
||||
<div id="torrents-error">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="context.js"></script>
|
||||
<script src="privacy.js"></script>
|
||||
<script src="i2pcontrol/i2pcontrol.js"></script>
|
||||
<script src="info.js"></script>
|
||||
<script crossorigin="anonymous" src="content.js"></script>
|
||||
<script src="torrent/common.js"></script>
|
||||
<script src="torrent/popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user