Improve content file/folder names handling

Move files/folders renaming functions to core classes.
Query file/folder for renaming by its current path.
Add ability to rename content folders from WebAPI/WebUI.
This commit is contained in:
Vladimir Golovnev (Glassez)
2020-12-17 11:57:06 +03:00
committed by sledgehammer999
parent dd3a8d5d56
commit b418f65c2f
16 changed files with 309 additions and 299 deletions

View File

@@ -1251,44 +1251,44 @@ void TorrentsController::tagsAction()
void TorrentsController::renameFileAction()
{
requireParams({"hash", "id", "name"});
requireParams({"hash", "oldPath", "newPath"});
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());
const QString oldPath = params()["oldPath"];
const QString newPath = params()["newPath"];
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)
try
{
if (i == fileIndex) continue;
if (Utils::Fs::sameFileNames(torrent->filePath(i), newFilePath))
throw APIError(APIErrorType::Conflict, tr("Name is already in use"));
torrent->renameFile(oldPath, newPath);
}
catch (const RuntimeError &error)
{
throw APIError(APIErrorType::Conflict, error.message());
}
}
void TorrentsController::renameFolderAction()
{
requireParams({"hash", "oldPath", "newPath"});
const QString hash = params()["hash"];
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent)
throw APIError(APIErrorType::NotFound);
const QString oldPath = params()["oldPath"];
const QString newPath = params()["newPath"];
try
{
torrent->renameFolder(oldPath, newPath);
}
catch (const RuntimeError &error)
{
throw APIError(APIErrorType::Conflict, error.message());
}
torrent->renameFile(fileIndex, newFilePath);
}

View File

@@ -84,4 +84,5 @@ private slots:
void toggleSequentialDownloadAction();
void toggleFirstLastPiecePrioAction();
void renameFileAction();
void renameFolderAction();
};

View File

@@ -8,6 +8,7 @@
<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 src="scripts/filesystem.js?v=${CACHEID}"></script>
<script>
'use strict';
@@ -31,14 +32,15 @@
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 path = new URI().getData('path');
const isFolder = ((new URI().getData('isFolder')) === 'true');
const decodedName = decodeURIComponent(name);
$('rename').value = decodedName;
const oldPath = decodeURIComponent(path);
const oldName = window.qBittorrent.Filesystem.fileName(oldPath);
$('rename').value = oldName;
$('rename').focus();
$('rename').setSelectionRange(0, decodedName.lastIndexOf('.'));
if (!isFolder)
$('rename').setSelectionRange(0, oldName.lastIndexOf('.'));
$('renameButton').addEvent('click', function(e) {
new Event(e).stop();
@@ -49,20 +51,24 @@
return;
}
if (newName === name) {
if (newName === oldName) {
alert('QBT_TR(Name is unchanged)QBT_TR[CONTEXT=HttpServer]');
return;
}
$('renameButton').disabled = true;
const parentPath = window.qBittorrent.Filesystem.folderName(oldPath)
const newPath = parentPath
? parentPath + window.qBittorrent.Filesystem.PathSeparator + newName
: newName;
new Request({
url: 'api/v2/torrents/renameFile',
url: isFolder ? 'api/v2/torrents/renameFolder' : 'api/v2/torrents/renameFile',
method: 'post',
data: {
hash: hash,
id: id,
name: newName
oldPath: oldPath,
newPath: newPath
},
onSuccess: function() {
window.parent.closeWindows();

View File

@@ -117,6 +117,7 @@ window.qBittorrent.FileTree = (function() {
const FileNode = new Class({
name: "",
path: "",
rowId: null,
size: 0,
checked: TriState.Unchecked,

View File

@@ -423,9 +423,9 @@ window.qBittorrent.PropFiles = (function() {
rows.forEach(function(row) {
let parent = rootNode;
const pathFolders = row.fileName.split(window.qBittorrent.Filesystem.PathSeparator);
pathFolders.pop();
pathFolders.forEach(function(folderName) {
let folderPath = window.qBittorrent.Filesystem.folderName(row.fileName);
while (folderPath) {
const folderName = window.qBittorrent.Filesystem.fileName(folderPath);
if (folderName === '.unwanted')
return;
@@ -439,8 +439,10 @@ window.qBittorrent.PropFiles = (function() {
}
}
}
if (parentNode === null) {
parentNode = new window.qBittorrent.FileTree.FolderNode();
parentNode.path = folderPath;
parentNode.name = folderName;
parentNode.rowId = rowId;
parentNode.root = parent;
@@ -450,12 +452,14 @@ window.qBittorrent.PropFiles = (function() {
}
parent = parentNode;
});
folderPath = window.qBittorrent.Filesystem.folderName(folderPath);
}
const isChecked = row.checked ? TriState.Checked : TriState.Unchecked;
const remaining = (row.priority === FilePriority.Ignored) ? 0 : row.remaining;
const childNode = new window.qBittorrent.FileTree.FileNode();
childNode.name = row.name;
childNode.path = row.fileName;
childNode.rowId = rowId;
childNode.size = row.size;
childNode.checked = isChecked;
@@ -527,17 +531,16 @@ window.qBittorrent.PropFiles = (function() {
if (rowId === undefined) 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;
const node = torrentFilesTable.getNode(rowId);
const path = node.path;
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),
contentURL: 'rename_file.html?hash=' + hash + '&isFolder=' + node.isFolder
+ '&path=' + encodeURIComponent(path),
scrollbars: false,
resizable: false,
maximizable: false,
@@ -570,13 +573,6 @@ 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');
}
});