Improve renaming utility
* Improve UI * Add simple example script (the current example script grew quite big and is likely not good to get started) * Add script to format example scripts
This commit is contained in:
parent
b0cd798ec1
commit
596d67387f
|
@ -54,10 +54,11 @@ RenameFilesDialog::RenameFilesDialog(QWidget *parent)
|
||||||
m_ui->notificationLabel->setHidden(true);
|
m_ui->notificationLabel->setHidden(true);
|
||||||
|
|
||||||
// setup pasteScriptButton menu
|
// setup pasteScriptButton menu
|
||||||
QMenu *pasteScriptButtonMenu = new QMenu(m_ui->pasteScriptPushButton);
|
auto *const pasteScriptButtonMenu = new QMenu(m_ui->pasteScriptPushButton);
|
||||||
pasteScriptButtonMenu->addAction(tr("from file"), this, &RenameFilesDialog::showSelectScriptFileDlg);
|
pasteScriptButtonMenu->addAction(tr("File"), this, &RenameFilesDialog::showSelectScriptFileDlg);
|
||||||
pasteScriptButtonMenu->addAction(tr("from clipboard"), this, &RenameFilesDialog::pasteScriptFromClipboard);
|
pasteScriptButtonMenu->addAction(tr("Paste from clipboard"), this, &RenameFilesDialog::pasteScriptFromClipboard);
|
||||||
pasteScriptButtonMenu->addAction(tr("default script"), this, &RenameFilesDialog::pasteDefaultExampleScript);
|
pasteScriptButtonMenu->addAction(tr("Simple example"), this, &RenameFilesDialog::pasteSimpleExampleScript);
|
||||||
|
pasteScriptButtonMenu->addAction(tr("Advanced example"), this, &RenameFilesDialog::pasteAdvancedExampleScript);
|
||||||
m_ui->pasteScriptPushButton->setMenu(pasteScriptButtonMenu);
|
m_ui->pasteScriptPushButton->setMenu(pasteScriptButtonMenu);
|
||||||
|
|
||||||
// setup icons
|
// setup icons
|
||||||
|
@ -76,7 +77,7 @@ RenameFilesDialog::RenameFilesDialog(QWidget *parent)
|
||||||
m_ui->javaScriptPlainTextEdit->setPlainText(settings.editorScript);
|
m_ui->javaScriptPlainTextEdit->setPlainText(settings.editorScript);
|
||||||
m_scriptModified = true;
|
m_scriptModified = true;
|
||||||
} else {
|
} else {
|
||||||
pasteDefaultExampleScript();
|
pasteSimpleExampleScript();
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect signals and slots
|
// connect signals and slots
|
||||||
|
@ -354,9 +355,14 @@ void RenameFilesDialog::pasteScriptFromClipboard()
|
||||||
m_ui->javaScriptPlainTextEdit->setPlainText(script);
|
m_ui->javaScriptPlainTextEdit->setPlainText(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenameFilesDialog::pasteDefaultExampleScript()
|
void RenameFilesDialog::pasteSimpleExampleScript()
|
||||||
{
|
{
|
||||||
pasteScriptFromFile(QStringLiteral(":/scripts/renamefiles/example1"));
|
pasteScriptFromFile(QStringLiteral(":/scripts/renamefiles/simple-example"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenameFilesDialog::pasteAdvancedExampleScript()
|
||||||
|
{
|
||||||
|
pasteScriptFromFile(QStringLiteral(":/scripts/renamefiles/advanced-example"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenameFilesDialog::showTreeViewContextMenu(const QPoint &position)
|
void RenameFilesDialog::showTreeViewContextMenu(const QPoint &position)
|
||||||
|
|
|
@ -45,7 +45,8 @@ private Q_SLOTS:
|
||||||
void previewItemSelected(const QItemSelection &selected, const QItemSelection &deselected);
|
void previewItemSelected(const QItemSelection &selected, const QItemSelection &deselected);
|
||||||
void pasteScriptFromFile(const QString &fileName);
|
void pasteScriptFromFile(const QString &fileName);
|
||||||
void pasteScriptFromClipboard();
|
void pasteScriptFromClipboard();
|
||||||
void pasteDefaultExampleScript();
|
void pasteSimpleExampleScript();
|
||||||
|
void pasteAdvancedExampleScript();
|
||||||
void showTreeViewContextMenu(const QPoint &position);
|
void showTreeViewContextMenu(const QPoint &position);
|
||||||
void showSelectScriptFileDlg();
|
void showSelectScriptFileDlg();
|
||||||
void abortClose();
|
void abortClose();
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pasteScriptPushButton">
|
<widget class="QPushButton" name="pasteScriptPushButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Paste</string>
|
<string>Open/Examples</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="edit-paste">
|
<iconset theme="edit-paste">
|
||||||
|
@ -578,7 +578,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="PathLineEdit" name="scriptFilePathLineEdit">
|
<widget class="PathLineEdit" name="scriptFilePathLineEdit">
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string>select a script file</string>
|
<string>Select a script file</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/scripts/renamefiles">
|
<qresource prefix="/scripts/renamefiles">
|
||||||
<file alias="example1">scripts/renamefiles/example1.js</file>
|
<file alias="simple-example">scripts/renamefiles/simple-example.js</file>
|
||||||
|
<file alias="advanced-example">scripts/renamefiles/advanced-example.js</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"indent_size": 4,
|
||||||
|
"indent_char": " ",
|
||||||
|
"indent_with_tabs": false,
|
||||||
|
"editorconfig": false,
|
||||||
|
"eol": "\n",
|
||||||
|
"end_with_newline": false,
|
||||||
|
"indent_level": 0,
|
||||||
|
"preserve_newlines": true,
|
||||||
|
"max_preserve_newlines": 10,
|
||||||
|
"space_in_paren": false,
|
||||||
|
"space_in_empty_paren": false,
|
||||||
|
"jslint_happy": true,
|
||||||
|
"space_after_anon_function": false,
|
||||||
|
"space_after_named_function": false,
|
||||||
|
"brace_style": "collapse",
|
||||||
|
"unindent_chained_methods": false,
|
||||||
|
"break_chained_methods": false,
|
||||||
|
"keep_array_indentation": false,
|
||||||
|
"unescape_strings": false,
|
||||||
|
"wrap_line_length": 0,
|
||||||
|
"e4x": false,
|
||||||
|
"comma_first": false,
|
||||||
|
"operator_position": "before-newline",
|
||||||
|
"indent_empty_lines": false,
|
||||||
|
"templating": ["auto"]
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ var keepTitleFromFileName = false
|
||||||
// specifies whether track information should be appended (like [H.265-320p AAC-LC-2ch-eng AAC-LC-2ch-ger])
|
// specifies whether track information should be appended (like [H.265-320p AAC-LC-2ch-eng AAC-LC-2ch-ger])
|
||||||
var includeTrackInfo = false
|
var includeTrackInfo = false
|
||||||
// specifies the "distribution directory"
|
// specifies the "distribution directory"
|
||||||
//var distDir = false; // don't move files around
|
//var distDir = false // don't move files around
|
||||||
var distDir = "/path/to/my/music-collection" // move files to an appropriate subdirectory under this path
|
var distDir = "/path/to/my/music-collection" // move files to an appropriate subdirectory under this path
|
||||||
// directory used to store collections which contain songs from multiple artists
|
// directory used to store collections which contain songs from multiple artists
|
||||||
var collectionsDir = "collections"
|
var collectionsDir = "collections"
|
||||||
|
@ -59,16 +59,16 @@ function appropriateDigitCount(pos, total) {
|
||||||
// returns a copy of the specified \a name with characters that might be avoided in file names striped out
|
// returns a copy of the specified \a name with characters that might be avoided in file names striped out
|
||||||
function validFileName(name) {
|
function validFileName(name) {
|
||||||
return name !== undefined ? name.replace(/[\/\\]/gi, " - ").replace(
|
return name !== undefined ? name.replace(/[\/\\]/gi, " - ").replace(
|
||||||
/[<>?!*|:\"\n\f\r]/gi, "") : ""
|
/[<>?!*|:\"\n\f\r]/gi, "") : ""
|
||||||
}
|
}
|
||||||
// returns a copy of the specified \a name with characters that might be avoided in directory names striped out.
|
// returns a copy of the specified \a name with characters that might be avoided in directory names striped out.
|
||||||
function validDirectoryName(name) {
|
function validDirectoryName(name) {
|
||||||
return name !== undefined ? name.replace(/[\/\\]/gi, " - ").replace(
|
return name !== undefined ? name.replace(/[\/\\]/gi, " - ").replace(
|
||||||
/[<>?!*|:\".\n\f\r]/gi, "") : ""
|
/[<>?!*|:\".\n\f\r]/gi, "") : ""
|
||||||
}
|
}
|
||||||
// strips tags from the beginning or end of the string if configured
|
// strips tags from the beginning or end of the string if configured
|
||||||
function tagsStripped(name) {
|
function tagsStripped(name) {
|
||||||
return stripTags ? name.replace(/^(\[[^\]]*\]\s*)+/g, "").replace(/(\s*\[[^\]]*\])+$/g, "") : name;
|
return stripTags ? name.replace(/^(\[[^\]]*\]\s*)+/g, "").replace(/(\s*\[[^\]]*\])+$/g, "") : name
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -90,26 +90,26 @@ var tracks = fileInfo.tracks
|
||||||
var infoFromFileName = tageditor.parseFileName(fileInfo.currentBaseName)
|
var infoFromFileName = tageditor.parseFileName(fileInfo.currentBaseName)
|
||||||
|
|
||||||
// skip hidden and "desktop.ini" files
|
// skip hidden and "desktop.ini" files
|
||||||
if (fileInfo.currentName.indexOf(".") === 0
|
if (fileInfo.currentName.indexOf(".") === 0 ||
|
||||||
|| fileInfo.currentName === "desktop.ini") {
|
fileInfo.currentName === "desktop.ini") {
|
||||||
tageditor.skip()
|
tageditor.skip()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// treat *.lrc files like their corresponding audio files
|
// treat *.lrc files like their corresponding audio files
|
||||||
var keepSuffix;
|
var keepSuffix
|
||||||
if (fileInfo.currentSuffix === "lrc") {
|
if (fileInfo.currentSuffix === "lrc") {
|
||||||
keepSuffix = fileInfo.currentSuffix; // keep the lrc suffix later
|
keepSuffix = fileInfo.currentSuffix // keep the lrc suffix later
|
||||||
for(let extension of ["mp3", "flac", "m4a"]) {
|
for (let extension of ["mp3", "flac", "m4a"]) {
|
||||||
fileInfo = tageditor.parseFileInfo(fileInfo.currentPathWithoutExtension + "." + extension);
|
fileInfo = tageditor.parseFileInfo(fileInfo.currentPathWithoutExtension + "." + extension)
|
||||||
tag = fileInfo.tag;
|
tag = fileInfo.tag
|
||||||
if (!fileInfo.ioErrorOccured) {
|
if (!fileInfo.ioErrorOccured) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fileInfo.ioErrorOccured) {
|
if (fileInfo.ioErrorOccured) {
|
||||||
tageditor.skip("skipping, corresponding audio file not present");
|
tageditor.skip("skipping, corresponding audio file not present")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +133,7 @@ if (fileInfo.currentSuffix === "tmp") {
|
||||||
var fields = []
|
var fields = []
|
||||||
|
|
||||||
// get the artist (preferably album artist), remove invalid characters and add it to fields array
|
// get the artist (preferably album artist), remove invalid characters and add it to fields array
|
||||||
var artist = validFileName(tag.albumartist)
|
var artist = validFileName(tag.albumartist || tag.artist)
|
||||||
if (artist.length === 0) {
|
|
||||||
artist = validFileName(tag.artist)
|
|
||||||
}
|
|
||||||
if (includeArtist && !isPartOfCollection(tag) && notEmpty(artist)) {
|
if (includeArtist && !isPartOfCollection(tag) && notEmpty(artist)) {
|
||||||
fields.push(artist)
|
fields.push(artist)
|
||||||
}
|
}
|
||||||
|
@ -214,10 +211,7 @@ if (!distDir) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var path = [distDir]
|
var path = [distDir]
|
||||||
var artist = validDirectoryName(tag.albumartist)
|
var artist = validDirectoryName(tag.albumartist || tag.artist)
|
||||||
if (artist.length === 0) {
|
|
||||||
artist = validDirectoryName(tag.artist)
|
|
||||||
}
|
|
||||||
if (isPartOfCollection(tag)) {
|
if (isPartOfCollection(tag)) {
|
||||||
path.push(collectionsDir)
|
path.push(collectionsDir)
|
||||||
} else if (isMiscFile(tag)) {
|
} else if (isMiscFile(tag)) {
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
for js_file in *.js; do
|
||||||
|
js-beautify --jslint-happy -r "$js_file"
|
||||||
|
done
|
|
@ -0,0 +1,38 @@
|
||||||
|
// This is a simple example script demonstrating how the renaming tool can be used.
|
||||||
|
// script configuration
|
||||||
|
|
||||||
|
// skip directories in this example script
|
||||||
|
if (!tageditor.isFile) {
|
||||||
|
tageditor.skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse file using the built-in parseFileInfo function
|
||||||
|
const fileInfo = tageditor.parseFileInfo(tageditor.currentPath)
|
||||||
|
const tag = fileInfo.tag
|
||||||
|
const tracks = fileInfo.tracks
|
||||||
|
|
||||||
|
// deduce title and track number from the file name using the built-in parseFileName function (as fallback if tags missing)
|
||||||
|
const infoFromFileName = tageditor.parseFileName(fileInfo.currentBaseName)
|
||||||
|
|
||||||
|
// skip files which don't contain audio or video tracks
|
||||||
|
if (!fileInfo.hasAudioTracks && !fileInfo.hasVideoTracks) {
|
||||||
|
tageditor.skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// make new filename
|
||||||
|
const fieldsToInclude = [tag.albumartist || tag.artist, tag.album, tag.trackPos || infoFromFileName.trackPos, tag.title || infoFromFileName.title]
|
||||||
|
let newName = ""
|
||||||
|
for (let field of fieldsToInclude) {
|
||||||
|
if (typeof field === "number") {
|
||||||
|
for (field = field + "", count = (tag.trackTotal + "").length; field.length < count; field = "0" + field);
|
||||||
|
}
|
||||||
|
if (field && field.length !== 0) {
|
||||||
|
newName = newName.concat(newName.length === 0 ? "" : " - ", field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newName = newName.concat(".", fileInfo.suitableSuffix || fileInfo.currentSuffix)
|
||||||
|
|
||||||
|
// apply new name
|
||||||
|
tageditor.rename(newName)
|
Loading…
Reference in New Issue