mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-25 22:14:32 +00: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
@ -1154,3 +1154,46 @@ void TorrentsController::tagsAction()
|
|||||||
result << tag;
|
result << tag;
|
||||||
setResult(result);
|
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 setForceStartAction();
|
||||||
void toggleSequentialDownloadAction();
|
void toggleSequentialDownloadAction();
|
||||||
void toggleFirstLastPiecePrioAction();
|
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>
|
<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>
|
||||||
<ul id="torrentFilesMenu" class="contextMenu">
|
<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>
|
<a href="#FilePrio" class="arrow-right"><span style="display: inline-block; width: 16px;"></span> QBT_TR(Priority)QBT_TR[CONTEXT=PropertiesWidget]</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#FilePrioIgnore"><span style="display: inline-block; width: 16px;"></span> QBT_TR(Do not download)QBT_TR[CONTEXT=PropListDelegate]</a></li>
|
<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();
|
}).send();
|
||||||
},
|
},
|
||||||
onError: function() {
|
onFailure: function() {
|
||||||
alert("QBT_TR(Unable to create category)QBT_TR[CONTEXT=HttpServer] " + window.qBittorrent.Misc.escapeHtml(categoryName));
|
alert("QBT_TR(Unable to create category)QBT_TR[CONTEXT=HttpServer] " + window.qBittorrent.Misc.escapeHtml(categoryName));
|
||||||
}
|
}
|
||||||
}).send();
|
}).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',
|
targets: '#torrentFilesTableDiv tr',
|
||||||
menu: 'torrentFilesMenu',
|
menu: 'torrentFilesMenu',
|
||||||
actions: {
|
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) {
|
FilePrioIgnore: function(element, ref) {
|
||||||
filesPriorityMenuClicked(FilePriority.Ignored);
|
filesPriorityMenuClicked(FilePriority.Ignored);
|
||||||
@ -543,6 +570,13 @@ window.qBittorrent.PropFiles = (function() {
|
|||||||
this.hideItem('FilePrio');
|
this.hideItem('FilePrio');
|
||||||
else
|
else
|
||||||
this.showItem('FilePrio');
|
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/newcategory.html</file>
|
||||||
<file>private/newtag.html</file>
|
<file>private/newtag.html</file>
|
||||||
<file>private/rename.html</file>
|
<file>private/rename.html</file>
|
||||||
|
<file>private/rename_file.html</file>
|
||||||
<file>private/scripts/client.js</file>
|
<file>private/scripts/client.js</file>
|
||||||
<file>private/scripts/contextmenu.js</file>
|
<file>private/scripts/contextmenu.js</file>
|
||||||
<file>private/scripts/download.js</file>
|
<file>private/scripts/download.js</file>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user