mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-11 15:27:54 +00:00
Add WebUI Trackers context menu
This commit is contained in:
parent
4947b0a44f
commit
33351e3d8d
@ -377,7 +377,7 @@ void TorrentsController::trackersAction()
|
||||
checkParams({"hash"});
|
||||
|
||||
const QString hash {params()["hash"]};
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
const BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (!torrent)
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
@ -613,15 +613,82 @@ void TorrentsController::addTrackersAction()
|
||||
const QString hash = params()["hash"];
|
||||
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (torrent) {
|
||||
QList<BitTorrent::TrackerEntry> trackers;
|
||||
for (QString url : asConst(params()["urls"].split('\n'))) {
|
||||
url = url.trimmed();
|
||||
if (!url.isEmpty())
|
||||
trackers << url;
|
||||
}
|
||||
torrent->addTrackers(trackers);
|
||||
if (!torrent)
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QList<BitTorrent::TrackerEntry> trackers;
|
||||
for (const QString &urlStr : asConst(params()["urls"].split('\n'))) {
|
||||
const QUrl url {urlStr.trimmed()};
|
||||
if (url.isValid())
|
||||
trackers << url.toString();
|
||||
}
|
||||
torrent->addTrackers(trackers);
|
||||
}
|
||||
|
||||
void TorrentsController::editTrackerAction()
|
||||
{
|
||||
checkParams({"hash", "origUrl", "newUrl"});
|
||||
|
||||
const QString hash = params()["hash"];
|
||||
const QString origUrl = params()["origUrl"];
|
||||
const QString newUrl = params()["newUrl"];
|
||||
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (!torrent)
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
const QUrl origTrackerUrl(origUrl);
|
||||
const QUrl newTrackerUrl(newUrl);
|
||||
if (origTrackerUrl == newTrackerUrl)
|
||||
return;
|
||||
if (!newTrackerUrl.isValid())
|
||||
throw APIError(APIErrorType::BadParams, "New tracker URL is invalid");
|
||||
|
||||
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
bool match = false;
|
||||
for (BitTorrent::TrackerEntry &tracker : trackers) {
|
||||
const QUrl trackerUrl(tracker.url());
|
||||
if (trackerUrl == newTrackerUrl)
|
||||
throw APIError(APIErrorType::Conflict, "New tracker URL already exists");
|
||||
if (trackerUrl == origTrackerUrl) {
|
||||
match = true;
|
||||
BitTorrent::TrackerEntry newTracker(newTrackerUrl.toString());
|
||||
newTracker.setTier(tracker.tier());
|
||||
tracker = newTracker;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
throw APIError(APIErrorType::Conflict, "Tracker not found");
|
||||
|
||||
torrent->replaceTrackers(trackers);
|
||||
if (!torrent->isPaused())
|
||||
torrent->forceReannounce();
|
||||
}
|
||||
|
||||
void TorrentsController::removeTrackersAction()
|
||||
{
|
||||
checkParams({"hash", "urls"});
|
||||
|
||||
const QString hash = params()["hash"];
|
||||
const QStringList urls = params()["urls"].split('|');
|
||||
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (!torrent)
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QList<BitTorrent::TrackerEntry> remainingTrackers;
|
||||
const QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
for (const BitTorrent::TrackerEntry &entry : trackers) {
|
||||
if (!urls.contains(entry.url()))
|
||||
remainingTrackers.push_back(entry);
|
||||
}
|
||||
|
||||
if (remainingTrackers.size() == trackers.size())
|
||||
throw APIError(APIErrorType::Conflict, "No trackers were removed");
|
||||
|
||||
torrent->replaceTrackers(remainingTrackers);
|
||||
if (!torrent->isPaused())
|
||||
torrent->forceReannounce();
|
||||
}
|
||||
|
||||
void TorrentsController::pauseAction()
|
||||
|
@ -59,6 +59,8 @@ private slots:
|
||||
void addAction();
|
||||
void deleteAction();
|
||||
void addTrackersAction();
|
||||
void editTrackerAction();
|
||||
void removeTrackersAction();
|
||||
void filePrioAction();
|
||||
void uploadLimitAction();
|
||||
void downloadLimitAction();
|
||||
|
@ -9,6 +9,17 @@
|
||||
<script src="scripts/lib/mootools-1.2-more.js"></script>
|
||||
<script>
|
||||
window.addEvent('domready', function() {
|
||||
var setLocationKeyboardEvents = new Keyboard({
|
||||
defaultEventType: 'keydown',
|
||||
events: {
|
||||
'enter': function(event) {
|
||||
$('addTrackersButton').click();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
setLocationKeyboardEvents.activate();
|
||||
|
||||
$('trackersUrls').focus();
|
||||
$('addTrackersButton').addEvent('click', function(e) {
|
||||
new Event(e).stop();
|
||||
|
@ -450,12 +450,6 @@ td.generalLabel {
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
#addTrackersPlus {
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
.unselectable {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
|
65
src/webui/www/private/edittracker.html
Normal file
65
src/webui/www/private/edittracker.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="${LANG}">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>QBT_TR(Tracker editing)QBT_TR[CONTEXT=TrackerListWidget]</title>
|
||||
<link rel="stylesheet" href="css/style.css" type="text/css" />
|
||||
<script src="scripts/lib/mootools-1.2-core-yc.js"></script>
|
||||
<script src="scripts/lib/mootools-1.2-more.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
window.addEvent('domready', function() {
|
||||
var setLocationKeyboardEvents = new Keyboard({
|
||||
defaultEventType: 'keydown',
|
||||
events: {
|
||||
'enter': function(event) {
|
||||
$('editTrackerButton').click();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
setLocationKeyboardEvents.activate();
|
||||
|
||||
var currentUrl = new URI().getData('url');
|
||||
if (!currentUrl)
|
||||
return false;
|
||||
|
||||
var decodedUrl = decodeURIComponent(currentUrl);
|
||||
$('trackerUrl').value = decodedUrl;
|
||||
$('trackerUrl').focus();
|
||||
|
||||
$('editTrackerButton').addEvent('click', function(e) {
|
||||
new Event(e).stop();
|
||||
var hash = new URI().getData('hash');
|
||||
new Request({
|
||||
url: 'api/v2/torrents/editTracker',
|
||||
method: 'post',
|
||||
data: {
|
||||
hash: hash,
|
||||
origUrl: decodedUrl,
|
||||
newUrl: $('trackerUrl').value
|
||||
},
|
||||
onComplete: function() {
|
||||
window.parent.closeWindows();
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="text-align: center;">
|
||||
<br/>
|
||||
<h2 class="vcenter">QBT_TR(Tracker URL:)QBT_TR[CONTEXT=TrackerListWidget]</h2>
|
||||
<div style="text-align: center; padding-top: 10px;">
|
||||
<input id="trackerUrl" style="width: 90%;" />
|
||||
</div>
|
||||
<br/>
|
||||
<input type="button" value="QBT_TR(Edit)QBT_TR[CONTEXT=HttpServer]" id="editTrackerButton" />
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -158,6 +158,12 @@
|
||||
<li><a href="#PauseTorrentsByCategory"><img src="images/qbt-theme/media-playback-pause.svg" alt="QBT_TR(Pause torrents)QBT_TR[CONTEXT=CategoryFilterWidget]"/> QBT_TR(Pause torrents)QBT_TR[CONTEXT=CategoryFilterWidget]</a></li>
|
||||
<li><a href="#DeleteTorrentsByCategory"><img src="images/qbt-theme/edit-delete.svg" alt="QBT_TR(Delete torrents)QBT_TR[CONTEXT=CategoryFilterWidget]"/> QBT_TR(Delete torrents)QBT_TR[CONTEXT=CategoryFilterWidget]</a></li>
|
||||
</ul>
|
||||
<ul id="torrentTrackersMenu" class="contextMenu">
|
||||
<li><a href="#AddTracker"><img src="images/qbt-theme/list-add.svg" alt="QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Add a new tracker...)QBT_TR[CONTEXT=TrackerListWidget]</a></li>
|
||||
<li class="separator"><a href="#EditTracker"><img src="images/qbt-theme/document-edit.svg" alt="QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Edit tracker URL...)QBT_TR[CONTEXT=TrackerListWidget]</a></li>
|
||||
<li><a href="#RemoveTracker"><img src="images/qbt-theme/list-remove.svg" alt="QBT_TR(Remove tracker)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Remove tracker)QBT_TR[CONTEXT=TrackerListWidget]</a></li>
|
||||
<li><a href="#CopyTrackerUrl" id="CopyTrackerUrl"><img src="images/qbt-theme/edit-copy.svg" alt="QBT_TR(Copy tracker URL)QBT_TR[CONTEXT=TrackerListWidget]"/> QBT_TR(Copy tracker URL)QBT_TR[CONTEXT=TrackerListWidget]</a></li>
|
||||
</ul>
|
||||
<div id="desktopFooterWrapper">
|
||||
<div id="desktopFooter">
|
||||
<span id="error_div"></span>
|
||||
|
@ -85,7 +85,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">QBT_TR(#)QBT_TR[CONTEXT=TrackerListWidget]</th>
|
||||
<th style="width: 30%;">QBT_TR(URL)QBT_TR[CONTEXT=TrackerListWidget] <img src="images/qbt-theme/list-add.svg" id="addTrackersPlus" alt="Add Trackers" /></th>
|
||||
<th style="width: 30%;">QBT_TR(URL)QBT_TR[CONTEXT=TrackerListWidget]</th>
|
||||
<th style="width: 10%;">QBT_TR(Status)QBT_TR[CONTEXT=TrackerListWidget]</th>
|
||||
<th style="width: 5%;">QBT_TR(Peers)QBT_TR[CONTEXT=TrackerListWidget]</th>
|
||||
<th style="width: 5%;">QBT_TR(Seeds)QBT_TR[CONTEXT=TrackerListWidget]</th>
|
||||
|
@ -2,9 +2,10 @@ var trackersDynTable = new Class({
|
||||
|
||||
initialize: function() {},
|
||||
|
||||
setup: function(table) {
|
||||
setup: function(table, contextMenu) {
|
||||
this.table = $(table);
|
||||
this.rows = new Hash();
|
||||
this.contextMenu = contextMenu;
|
||||
},
|
||||
|
||||
removeRow: function(url) {
|
||||
@ -46,11 +47,13 @@ var trackersDynTable = new Class({
|
||||
td.set('html', row[i]);
|
||||
td.injectInside(tr);
|
||||
}
|
||||
this.contextMenu.addTarget(tr);
|
||||
tr.injectInside(this.table);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var current_hash = "";
|
||||
var selectedTracker = "";
|
||||
|
||||
var loadTrackersDataTimer;
|
||||
var loadTrackersData = function() {
|
||||
@ -61,13 +64,13 @@ var loadTrackersData = function() {
|
||||
}
|
||||
var new_hash = torrentsTable.getCurrentTorrentHash();
|
||||
if (new_hash === "") {
|
||||
tTable.removeAllRows();
|
||||
torrentTrackersTable.removeAllRows();
|
||||
clearTimeout(loadTrackersDataTimer);
|
||||
loadTrackersDataTimer = loadTrackersData.delay(10000);
|
||||
return;
|
||||
}
|
||||
if (new_hash != current_hash) {
|
||||
tTable.removeAllRows();
|
||||
torrentTrackersTable.removeAllRows();
|
||||
current_hash = new_hash;
|
||||
}
|
||||
var url = new URI('api/v2/torrents/trackers?hash=' + current_hash);
|
||||
@ -82,6 +85,8 @@ var loadTrackersData = function() {
|
||||
},
|
||||
onSuccess: function(trackers) {
|
||||
$('error_div').set('html', '');
|
||||
torrentTrackersTable.removeAllRows();
|
||||
|
||||
if (trackers) {
|
||||
// Update Trackers data
|
||||
trackers.each(function(tracker) {
|
||||
@ -96,12 +101,9 @@ var loadTrackersData = function() {
|
||||
escapeHtml(tracker.msg)
|
||||
];
|
||||
|
||||
tTable.insertRow(row);
|
||||
torrentTrackersTable.insertRow(row);
|
||||
});
|
||||
}
|
||||
else {
|
||||
tTable.removeAllRows();
|
||||
}
|
||||
clearTimeout(loadTrackersDataTimer);
|
||||
loadTrackersDataTimer = loadTrackersData.delay(10000);
|
||||
}
|
||||
@ -113,11 +115,42 @@ var updateTrackersData = function() {
|
||||
loadTrackersData();
|
||||
};
|
||||
|
||||
tTable = new trackersDynTable();
|
||||
tTable.setup($('trackersTable'));
|
||||
var torrentTrackersContextMenu = new ContextMenu({
|
||||
targets: '.torrentTrackersMenuTarget',
|
||||
menu: 'torrentTrackersMenu',
|
||||
actions: {
|
||||
AddTracker: function(element, ref) {
|
||||
addTrackerFN();
|
||||
},
|
||||
EditTracker: function(element, ref) {
|
||||
editTrackerFN(element);
|
||||
},
|
||||
RemoveTracker: function(element, ref) {
|
||||
removeTrackerFN(element);
|
||||
}
|
||||
},
|
||||
offsets: {
|
||||
x: -15,
|
||||
y: 2
|
||||
},
|
||||
onShow: function() {
|
||||
var element = this.options.element;
|
||||
selectedTracker = element;
|
||||
if (element.childNodes[1].innerText.indexOf("** [") === 0) {
|
||||
this.hideItem('EditTracker');
|
||||
this.hideItem('RemoveTracker');
|
||||
this.hideItem('CopyTrackerUrl');
|
||||
}
|
||||
else {
|
||||
this.showItem('EditTracker');
|
||||
this.showItem('RemoveTracker');
|
||||
this.showItem('CopyTrackerUrl');
|
||||
}
|
||||
this.options.element.firstChild.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Add trackers code
|
||||
$('addTrackersPlus').addEvent('click', function addTrackerDlg() {
|
||||
var addTrackerFN = function() {
|
||||
if (current_hash.length === 0) return;
|
||||
new MochaUI.Window({
|
||||
id: 'trackersPage',
|
||||
@ -131,6 +164,62 @@ $('addTrackersPlus').addEvent('click', function addTrackerDlg() {
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 0,
|
||||
width: 500,
|
||||
height: 250
|
||||
height: 250,
|
||||
onCloseComplete: function() {
|
||||
updateTrackersData();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var editTrackerFN = function(element) {
|
||||
if (current_hash.length === 0) return;
|
||||
|
||||
var trackerUrl = encodeURIComponent(element.childNodes[1].innerText);
|
||||
new MochaUI.Window({
|
||||
id: 'trackersPage',
|
||||
title: "QBT_TR(Tracker editing)QBT_TR[CONTEXT=TrackerListWidget]",
|
||||
loadMethod: 'iframe',
|
||||
contentURL: 'edittracker.html?hash=' + current_hash + '&url=' + trackerUrl,
|
||||
scrollbars: true,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
closable: true,
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 0,
|
||||
width: 500,
|
||||
height: 150,
|
||||
onCloseComplete: function() {
|
||||
updateTrackersData();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var removeTrackerFN = function(element) {
|
||||
if (current_hash.length === 0) return;
|
||||
|
||||
var trackerUrl = element.childNodes[1].innerText;
|
||||
new Request({
|
||||
url: 'api/v2/torrents/removeTrackers',
|
||||
method: 'post',
|
||||
data: {
|
||||
hash: current_hash,
|
||||
urls: trackerUrl
|
||||
},
|
||||
onSuccess: function() {
|
||||
updateTrackersData();
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
|
||||
torrentTrackersTable = new trackersDynTable();
|
||||
torrentTrackersTable.setup($('trackersTable'), torrentTrackersContextMenu);
|
||||
|
||||
new ClipboardJS('#CopyTrackerUrl', {
|
||||
text: function(trigger) {
|
||||
if (selectedTracker) {
|
||||
var url = selectedTracker.childNodes[1].innerText;
|
||||
selectedTracker = "";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -11,6 +11,7 @@
|
||||
<file>private/css/Window.css</file>
|
||||
<file>private/download.html</file>
|
||||
<file>private/downloadlimit.html</file>
|
||||
<file>private/edittracker.html</file>
|
||||
<file>private/filters.html</file>
|
||||
<file>private/index.html</file>
|
||||
<file>private/installsearchplugin.html</file>
|
||||
|
Loading…
Reference in New Issue
Block a user