mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-26 19:26:59 +03:00
Merge pull request #11029 from Piccirello/webui-rename-file
Add ability to rename torrent files from the WebUI
This commit is contained in:
commit
a652c39394
7 changed files with 172 additions and 2 deletions
|
@ -1154,3 +1154,46 @@ void TorrentsController::tagsAction()
|
|||
result << tag;
|
||||
setResult(result);
|
||||
}
|
||||
|
||||
void TorrentsController::renameFileAction()
|
||||
{
|
||||
requireParams({"hash", "id", "name"});
|
||||
|
||||
const QString hash = params()["hash"];
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (!torrent)
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QString newName = params()["name"].trimmed();
|
||||
if (newName.isEmpty())
|
||||
throw APIError(APIErrorType::BadParams, tr("Name cannot be empty"));
|
||||
if (!Utils::Fs::isValidFileSystemName(newName))
|
||||
throw APIError(APIErrorType::Conflict, tr("Name is not valid"));
|
||||
if (newName.endsWith(QB_EXT))
|
||||
newName.chop(QB_EXT.size());
|
||||
|
||||
bool ok = false;
|
||||
const int fileIndex = params()["id"].toInt(&ok);
|
||||
if (!ok || (fileIndex < 0) || (fileIndex >= torrent->filesCount()))
|
||||
throw APIError(APIErrorType::Conflict, tr("ID is not valid"));
|
||||
|
||||
const QString oldFileName = torrent->fileName(fileIndex);
|
||||
const QString oldFilePath = torrent->filePath(fileIndex);
|
||||
|
||||
const bool useFilenameExt = BitTorrent::Session::instance()->isAppendExtensionEnabled()
|
||||
&& (torrent->filesProgress()[fileIndex] != 1);
|
||||
const QString newFileName = (newName + (useFilenameExt ? QB_EXT : QString()));
|
||||
const QString newFilePath = (oldFilePath.leftRef(oldFilePath.size() - oldFileName.size()) + newFileName);
|
||||
|
||||
if (oldFileName == newFileName)
|
||||
return;
|
||||
|
||||
// check if new name is already used
|
||||
for (int i = 0; i < torrent->filesCount(); ++i) {
|
||||
if (i == fileIndex) continue;
|
||||
if (Utils::Fs::sameFileNames(torrent->filePath(i), newFilePath))
|
||||
throw APIError(APIErrorType::Conflict, tr("Name is already in use"));
|
||||
}
|
||||
|
||||
torrent->renameFile(fileIndex, newFilePath);
|
||||
}
|
||||
|
|
|
@ -83,4 +83,5 @@ private slots:
|
|||
void setForceStartAction();
|
||||
void toggleSequentialDownloadAction();
|
||||
void toggleFirstLastPiecePrioAction();
|
||||
void renameFileAction();
|
||||
};
|
||||
|
|
|
@ -197,7 +197,8 @@
|
|||
<li class="separator"><a href="#banPeer"><img src="images/qbt-theme/user-group-delete.svg" alt="QBT_TR(Ban peer permanently)QBT_TR[CONTEXT=PeerListWidget]"/> QBT_TR(Ban peer permanently)QBT_TR[CONTEXT=PeerListWidget]</a></li>
|
||||
</ul>
|
||||
<ul id="torrentFilesMenu" class="contextMenu">
|
||||
<li>
|
||||
<li><a href="#Rename"><img src="images/qbt-theme/edit-rename.svg" alt="QBT_TR(Rename...)QBT_TR[CONTEXT=PropertiesWidget]"/> QBT_TR(Rename...)QBT_TR[CONTEXT=PropertiesWidget]</a></li>
|
||||
<li class="separator">
|
||||
<a href="#FilePrio" class="arrow-right"><span style="display: inline-block; width: 16px;"></span> QBT_TR(Priority)QBT_TR[CONTEXT=PropertiesWidget]</a>
|
||||
<ul>
|
||||
<li><a href="#FilePrioIgnore"><span style="display: inline-block; width: 16px;"></span> QBT_TR(Do not download)QBT_TR[CONTEXT=PropListDelegate]</a></li>
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
}
|
||||
}).send();
|
||||
},
|
||||
onError: function() {
|
||||
onFailure: function() {
|
||||
alert("QBT_TR(Unable to create category)QBT_TR[CONTEXT=HttpServer] " + window.qBittorrent.Misc.escapeHtml(categoryName));
|
||||
}
|
||||
}).send();
|
||||
|
|
90
src/webui/www/private/rename_file.html
Normal file
90
src/webui/www/private/rename_file.html
Normal file
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="${LANG}">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>QBT_TR(Renaming)QBT_TR[CONTEXT=TorrentContentTreeView]</title>
|
||||
<link rel="stylesheet" href="css/style.css?v=${CACHEID}" 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 src="scripts/misc.js?locale=${LANG}&v=${CACHEID}"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
new Keyboard({
|
||||
defaultEventType: 'keydown',
|
||||
events: {
|
||||
'Enter': function(event) {
|
||||
$('renameButton').click();
|
||||
event.preventDefault();
|
||||
},
|
||||
'Escape': function(event) {
|
||||
window.parent.closeWindows();
|
||||
event.preventDefault();
|
||||
},
|
||||
'Esc': function(event) {
|
||||
window.parent.closeWindows();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}).activate();
|
||||
|
||||
window.addEvent('domready', function() {
|
||||
const hash = new URI().getData('hash');
|
||||
const name = new URI().getData('name');
|
||||
const id = new URI().getData('id');
|
||||
if (!hash || !name || !id) return;
|
||||
|
||||
const decodedName = decodeURIComponent(name);
|
||||
$('rename').value = decodedName;
|
||||
$('rename').focus();
|
||||
$('rename').setSelectionRange(0, decodedName.indexOf('.'));
|
||||
|
||||
$('renameButton').addEvent('click', function(e) {
|
||||
new Event(e).stop();
|
||||
// check field
|
||||
const newName = $('rename').value.trim();
|
||||
if (newName === '') {
|
||||
alert('QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newName === name) {
|
||||
alert('QBT_TR(Name is unchanged)QBT_TR[CONTEXT=HttpServer]');
|
||||
return;
|
||||
}
|
||||
|
||||
$('renameButton').disabled = true;
|
||||
|
||||
new Request({
|
||||
url: 'api/v2/torrents/renameFile',
|
||||
method: 'post',
|
||||
data: {
|
||||
hash: hash,
|
||||
id: id,
|
||||
name: newName
|
||||
},
|
||||
onSuccess: function() {
|
||||
window.parent.closeWindows();
|
||||
},
|
||||
onFailure: function() {
|
||||
alert('QBT_TR(Failed to update name)QBT_TR[CONTEXT=HttpServer]');
|
||||
$('renameButton').disabled = false;
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="padding: 10px 10px 0px 10px;">
|
||||
<p style="font-weight: bold;">QBT_TR(New name:)QBT_TR[CONTEXT=TorrentContentTreeView]</p>
|
||||
<input type="text" id="rename" value="" maxlength="100" style="width: 220px;" />
|
||||
<div style="text-align: center; padding-top: 10px;">
|
||||
<input type="button" value="QBT_TR(Save)QBT_TR[CONTEXT=HttpServer]" id="renameButton" />
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -520,6 +520,33 @@ window.qBittorrent.PropFiles = (function() {
|
|||
targets: '#torrentFilesTableDiv tr',
|
||||
menu: 'torrentFilesMenu',
|
||||
actions: {
|
||||
Rename: function(element, ref) {
|
||||
const hash = torrentsTable.getCurrentTorrentHash();
|
||||
if (!hash) return;
|
||||
const rowId = torrentFilesTable.selectedRowsIds()[0];
|
||||
if (!rowId) return;
|
||||
const row = torrentFilesTable.rows[rowId];
|
||||
if (!row) return;
|
||||
const node = torrentFilesTable.getNode(rowId);
|
||||
if (node.isFolder) return;
|
||||
|
||||
const name = row.full_data.name;
|
||||
const fileId = row.full_data.fileId;
|
||||
|
||||
new MochaUI.Window({
|
||||
id: 'renamePage',
|
||||
title: "QBT_TR(Renaming)QBT_TR[CONTEXT=TorrentContentTreeView]",
|
||||
loadMethod: 'iframe',
|
||||
contentURL: 'rename_file.html?hash=' + hash + '&id=' + fileId + '&name=' + encodeURIComponent(name),
|
||||
scrollbars: false,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 0,
|
||||
width: 250,
|
||||
height: 100
|
||||
});
|
||||
},
|
||||
|
||||
FilePrioIgnore: function(element, ref) {
|
||||
filesPriorityMenuClicked(FilePriority.Ignored);
|
||||
|
@ -543,6 +570,13 @@ window.qBittorrent.PropFiles = (function() {
|
|||
this.hideItem('FilePrio');
|
||||
else
|
||||
this.showItem('FilePrio');
|
||||
|
||||
const rowId = torrentFilesTable.selectedRowsIds()[0];
|
||||
const node = torrentFilesTable.getNode(rowId);
|
||||
if (node.isFolder)
|
||||
this.hideItem('Rename');
|
||||
else
|
||||
this.showItem('Rename');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<file>private/newcategory.html</file>
|
||||
<file>private/newtag.html</file>
|
||||
<file>private/rename.html</file>
|
||||
<file>private/rename_file.html</file>
|
||||
<file>private/scripts/client.js</file>
|
||||
<file>private/scripts/contextmenu.js</file>
|
||||
<file>private/scripts/download.js</file>
|
||||
|
|
Loading…
Reference in a new issue