List Tags and Labels

This script scans the selection for tags and labels. It lists the tags and labels it has found in the log panel and creates two dated text files with them in the source. Folders get scanned recursively. Reading metadata is time-consuming, you will need a bit of patience when scanning many files, especially media files.

// https://resource.dopus.com/t/list-tags-and-labels/41360

// 2022-05-31

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    var fsu = DOpus.FSUtil();
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var tagSet = DOpus.Create().StringSet();
    var labelSet = DOpus.Create().StringSet();
    var currDate = DOpus.Create().Date().Format('D#yyyyMMdd-T#HHmmss');
    cmd.deselect = false;

    function GetTagsFromItem(item) {
        var itemTags = item.metadata.tags;
        if (typeof itemTags == 'undefined') return;
        if (itemTags.count == 0) return;
        for (var e = new Enumerator(itemTags); !e.atEnd(); e.moveNext()) {
            tagSet.insert(e.item());
        }
    }

    function GetLabelsFromItem(item) {
        var itemLabels = item.Labels();
        if (typeof itemLabels == 'undefined') return;
        if (itemLabels.count == 0) return;
        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {
            labelSet.insert(e.item());
        }
    }

    if (tab.selected.count == 0) return;

    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    DOpus.Output('Enumerating...');

    for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (item.is_dir) {
            var folderEnum = fsu.ReadDir(item, 'r')
            while (!folderEnum.complete) {
                var folderItem = folderEnum.Next();
                if (folderItem.is_dir) continue;
                GetTagsFromItem(folderItem);
                GetLabelsFromItem(folderItem);
            }
        } else {
            GetTagsFromItem(item);
            GetLabelsFromItem(item);
        }
    }

    DOpus.Output('\n... done!');

    var tagsFile = fso.CreateTextFile(tab.path + '\\Tags-' + currDate + '.txt');

    DOpus.Output('\n\n*** Tags:\n');
    if (tagSet.empty) {
        DOpus.Output('<<<none>>>');
        tagsFile.WriteLine('<<<none>>>');
    } else {
        for (var e = new Enumerator(tagSet); !e.atEnd(); e.moveNext()) {
            DOpus.Output(e.item());
            tagsFile.WriteLine(e.item());
        }
    }
    tagsFile.Close();

    var labelsFile = fso.CreateTextFile(tab.path + '\\Labels-' + currDate + '.txt');

    DOpus.Output('\n\n*** Labels:\n');
    if (labelSet.empty) {
        DOpus.Output('<<<none>>>');
        labelsFile.WriteLine('<<<none>>>');
    } else {
        for (var e = new Enumerator(labelSet); !e.atEnd(); e.moveNext()) {
            DOpus.Output(e.item());
            labelsFile.WriteLine(e.item());
        }
    }
    labelsFile.Close();
}
Button as XML
<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<label>List Tags and Labels</label>
	<tip>Scan selection for tags and labels</tip>
	<icon1>#newcommand</icon1>
	<function type="script">
		<instruction>@script JScript</instruction>
		<instruction>// https://resource.dopus.com/t/list-tags-and-labels/41360</instruction>
		<instruction />
		<instruction>// 2022-05-31</instruction>
		<instruction />
		<instruction>function OnClick(clickData) {</instruction>
		<instruction>    var cmd = clickData.func.command;</instruction>
		<instruction>    var tab = clickData.func.sourcetab;</instruction>
		<instruction>    var fsu = DOpus.FSUtil();</instruction>
		<instruction>    var fso = new ActiveXObject(&apos;Scripting.FileSystemObject&apos;);</instruction>
		<instruction>    var tagSet = DOpus.Create().StringSet();</instruction>
		<instruction>    var labelSet = DOpus.Create().StringSet();</instruction>
		<instruction>    var currDate = DOpus.Create().Date().Format(&apos;D#yyyyMMdd-T#HHmmss&apos;);</instruction>
		<instruction>    cmd.deselect = false;</instruction>
		<instruction />
		<instruction>    function GetTagsFromItem(item) {</instruction>
		<instruction>        var itemTags = item.metadata.tags;</instruction>
		<instruction>        if (typeof itemTags == &apos;undefined&apos;) return;</instruction>
		<instruction>        if (itemTags.count == 0) return;</instruction>
		<instruction>        for (var e = new Enumerator(itemTags); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>            tagSet.insert(e.item());</instruction>
		<instruction>        }</instruction>
		<instruction>    }</instruction>
		<instruction />
		<instruction>    function GetLabelsFromItem(item) {</instruction>
		<instruction>        var itemLabels = item.Labels();</instruction>
		<instruction>        if (typeof itemLabels == &apos;undefined&apos;) return;</instruction>
		<instruction>        if (itemLabels.count == 0) return;</instruction>
		<instruction>        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>            labelSet.insert(e.item());</instruction>
		<instruction>        }</instruction>
		<instruction>    }</instruction>
		<instruction />
		<instruction>    if (tab.selected.count == 0) return;</instruction>
		<instruction />
		<instruction>    cmd.RunCommand(&apos;Set UTILITY=otherlog&apos;);</instruction>
		<instruction>    DOpus.ClearOutput();</instruction>
		<instruction>    DOpus.Output(&apos;Enumerating...&apos;);</instruction>
		<instruction />
		<instruction>    for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>        var item = e.item();</instruction>
		<instruction>        if (item.is_dir) {</instruction>
		<instruction>            var folderEnum = fsu.ReadDir(item, &apos;r&apos;)</instruction>
		<instruction>            while (!folderEnum.complete) {</instruction>
		<instruction>                var folderItem = folderEnum.Next();</instruction>
		<instruction>                if (folderItem.is_dir) continue;</instruction>
		<instruction>                GetTagsFromItem(folderItem);</instruction>
		<instruction>                GetLabelsFromItem(folderItem);</instruction>
		<instruction>            }</instruction>
		<instruction>        } else {</instruction>
		<instruction>            GetTagsFromItem(item);</instruction>
		<instruction>            GetLabelsFromItem(item);</instruction>
		<instruction>        }</instruction>
		<instruction>    }</instruction>
		<instruction />
		<instruction>    DOpus.Output(&apos;\n... done!&apos;);</instruction>
		<instruction />
		<instruction>    var tagsFile = fso.CreateTextFile(tab.path + &apos;\\Tags-&apos; + currDate + &apos;.txt&apos;);</instruction>
		<instruction />
		<instruction>    DOpus.Output(&apos;\n\n*** Tags:\n&apos;);</instruction>
		<instruction>    if (tagSet.empty) {</instruction>
		<instruction>        DOpus.Output(&apos;&lt;&lt;&lt;none&gt;&gt;&gt;&apos;);</instruction>
		<instruction>        tagsFile.WriteLine(&apos;&lt;&lt;&lt;none&gt;&gt;&gt;&apos;);</instruction>
		<instruction>    } else {</instruction>
		<instruction>        for (var e = new Enumerator(tagSet); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>            DOpus.Output(e.item());</instruction>
		<instruction>            tagsFile.WriteLine(e.item());</instruction>
		<instruction>        }</instruction>
		<instruction>    }</instruction>
		<instruction>    tagsFile.Close();</instruction>
		<instruction />
		<instruction>    var labelsFile = fso.CreateTextFile(tab.path + &apos;\\Labels-&apos; + currDate + &apos;.txt&apos;);</instruction>
		<instruction />
		<instruction>    DOpus.Output(&apos;\n\n*** Labels:\n&apos;);</instruction>
		<instruction>    if (labelSet.empty) {</instruction>
		<instruction>        DOpus.Output(&apos;&lt;&lt;&lt;none&gt;&gt;&gt;&apos;);</instruction>
		<instruction>        labelsFile.WriteLine(&apos;&lt;&lt;&lt;none&gt;&gt;&gt;&apos;);</instruction>
		<instruction>    } else {</instruction>
		<instruction>        for (var e = new Enumerator(labelSet); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>            DOpus.Output(e.item());</instruction>
		<instruction>            labelsFile.WriteLine(e.item());</instruction>
		<instruction>        }</instruction>
		<instruction>    }</instruction>
		<instruction>    labelsFile.Close();</instruction>
		<instruction>}</instruction>
	</function>
</button>

5 Likes

Thanks for this! Can you point me to a method for having it match the filenames to the labels/tags output? I ran it through a large directory and while it enumerates the tags, I don't know which belongs to which file.

The idea of the script is to be a help in situations like this:

https://resource.dopus.com/t/working-with-tags-tag-list-of-all-tags-available/41355/1

Once you have the tags, you can easily FIND files that carry them:

Additionally, you could modify the script to automatically start a search with the tags it finds.

Tags are also visible as a column and in the metadata pane.

1 Like

Thanks!

If you want an offline list of files and their tags, you can find all files with * (use wildcards) as a tag, then turn on the column which shows them, and use Tools > Print / Export Folder Listing to save it to a text file.

(The CSV or TSV formats are best, as then you don't have to worry about column widths, and you can import them into Excel or Google Sheets. Make sure the Export dialog is set up to include the columns you need as well. Full Path is probably one you would want.)

3 Likes

Hi @lxp, could you help me please:

  1. To make the script search all files/folders in the current folder and not just the selected files, what would I have to do?

  2. And to also search for files that contain some type of comment (descriptions).

Another question, should the script show the name/path of the files with tags/labels, or just the tags/labels?

Thank you so much!

I've made some changes to the original @lxp script, but there are still two things I haven't been able to do, can someone help me?

  1. Make the script work for all files/folders and not just selected files/folders.
  2. That the TXT document also include the full path of the files, and not just the labels?

Thank

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    var fsu = DOpus.FSUtil();
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var labelSet = DOpus.Create().StringSet();
    var currDate = DOpus.Create().Date().Format('D#dd-MM-yy');
    cmd.deselect = false;
	
    function GetLabelsFromItem(item) {
        var itemLabels = item.Labels();
        if (typeof itemLabels == 'undefined') return;
        if (itemLabels.count == 0) return;
        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {
            labelSet.insert(e.item());
        }
    }

    if (tab.selected.count == 0) return;
    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();   
    for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (item.is_dir) {
            var folderEnum = fsu.ReadDir(item, 'r')
            while (!folderEnum.complete) {
                var folderItem = folderEnum.Next();
                if (folderItem.is_dir) continue;
                GetLabelsFromItem(folderItem);
            }
        } else {
            GetLabelsFromItem(item);
        }
    }
	
    var labelsFile = fso.CreateTextFile(tab.path + '\\Etiquetas (' + currDate + ').txt'); 
    DOpus.Output('ETIQUETAS ENCONTRADAS\n'); 
    labelsFile.WriteLine('ETIQUETAS ENCONTRADAS\n'); 
    if (labelSet.empty)
	        DOpus.Output('< ninguna >');
        labelsFile.WriteLine('< ninguna >');
    } else {
        for (var e = new Enumerator(labelSet); !e.atEnd(); e.moveNext()) {
            DOpus.Output(e.item());
            labelsFile.WriteLine(e.item());	
        }
    }
    labelsFile.Close();
}

The script is doing things with tab.selected. The same tab object can give you the list of all files if that's what you want. It's all in the manual. :slight_smile:

Thank you very much @Leo, I already solved a problem, it was only to replace tab.selected with tab.all, you and that Manual do magic. :grinning:

Now I am going to focus on the second situation. :thinking:

For your #2:

If you haven't already, take a look at item.path

https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/Item.htm

Thinking better now, this line can be removed: if (tab.all.count == 0) return;

Thank you very much @Chuck , I will read now!

Thank you very much again @Chuck , I got it, inserting the line labelsFile.WriteLine(item.realpath);

I will show the complete code in case someone might be interested. This is executed from a button on the toolbar, in JScript mode, and its objective is to make a report, both in a TXT document and in the Utilities Panel, of all the files/folders that contain labels in the current folder (of recursive way).

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    var fsu = DOpus.FSUtil();
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var labelSet = DOpus.Create().StringSet();
    var currDate = DOpus.Create().Date().Format('D#dd-MM-yy');
    cmd.deselect = false;
	
    function GetLabelsFromItem(item) {
        var itemLabels = item.Labels();
        if (typeof itemLabels == 'undefined') return;
        if (itemLabels.count == 0) return;
        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {
            labelSet.insert(e.item());
        }
    }
	
    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    for (var e = new Enumerator(tab.all); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (item.is_dir) {
            var folderEnum = fsu.ReadDir(item, 'r')
            while (!folderEnum.complete) {
                var folderItem = folderEnum.Next();
                if (folderItem.is_dir) continue;
                GetLabelsFromItem(folderItem);
            }
        } else {
            GetLabelsFromItem(item);
        }
    }
	
    var labelsFile = fso.CreateTextFile(tab.path + '\\Labels (' + currDate + ').txt');
    DOpus.Output('LABELS\n');
    labelsFile.WriteLine('LABELS\n');
    if (labelSet.empty) {
	        DOpus.Output('< none >');
        labelsFile.WriteLine('< none >');
    } else {
        for (var e = new Enumerator(labelSet); !e.atEnd(); e.moveNext()) {
            DOpus.Output(item.realpath);		
            DOpus.Output(e.item());
            DOpus.Output("");
						
            labelsFile.WriteLine(item.realpath);
            labelsFile.WriteLine(e.item());
			labelsFile.WriteLine("");
        }
    }
	
    labelsFile.Close();
}

I have detected an error, it is always reported as path, the path of the last file analyzed, that of the previously analyzed files, no?

Hello @Chuck and @bytespiller, could you help me, please? Since yesterday I've been trying to solve this problem and I can't, and it hasn't been due to a lack of dedication because I've studied and tried a lot, a lot.

The problem I'm having is that all the labels found are always given the name of the last file in the folder, whether it has this label or not?

01

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    var fsu = DOpus.FSUtil();
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var labelSet = DOpus.Create().StringSet();
    cmd.deselect = false;
	
    function GetLabelsFromItem(item) {
        var itemLabels = item.Labels();
        if (typeof itemLabels == 'undefined') return;
        if (itemLabels.count == 0) return;
        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {
            labelSet.insert(e.item());
        }
    }
	
    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    for (var e = new Enumerator(tab.all); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (item.is_dir) {
            var folderEnum = fsu.ReadDir(item, 'r')
            while (!folderEnum.complete) {
                var folderItem = folderEnum.Next();
                if (folderItem.is_dir) continue;
                GetLabelsFromItem(folderItem);
            }
        } else {
            GetLabelsFromItem(item);
        }
    }

    DOpus.Output('LABELS\n');
    if (labelSet.empty) {
	        DOpus.Output('< none >');
    } else {
        for (var e = new Enumerator(labelSet); !e.atEnd(); e.moveNext()) {
            DOpus.Output(item.realpath);
            DOpus.Output(e.item());
            DOpus.Output("");
        }
    }
}

The reason it's printing only the final file is because the item variable you're using always contains only the final file (the variable gets overwritten each loop and ends up with whatever was the last file in the loop).

Here's the modification where I've added a new filesWithLabels variable which is a Map type. It remembers all files with all their labels so it's easy to print the results:

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    var fsu = DOpus.FSUtil();
    var fso = new ActiveXObject('Scripting.FileSystemObject');
    var labelSet = DOpus.Create().StringSet();
	var filesWithLabels = DOpus.Create.Map();
    cmd.deselect = false;
	
    function GetLabelsFromItem(item) {
        var itemLabels = item.Labels();
        if (typeof itemLabels == 'undefined') return;
        if (itemLabels.count == 0) return;
        for (var e = new Enumerator(itemLabels); !e.atEnd(); e.moveNext()) {
            labelSet.insert(e.item());
        }
		filesWithLabels(item.realpath) = itemLabels;
    }
	
    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    for (var e = new Enumerator(tab.all); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (item.is_dir) {
            var folderEnum = fsu.ReadDir(item, 'r')
            while (!folderEnum.complete) {
                var folderItem = folderEnum.Next();
                if (folderItem.is_dir) continue;
                GetLabelsFromItem(folderItem);
            }
        } else {
            GetLabelsFromItem(item);
        }
    }

    DOpus.Output('LABELS\n');
    if (labelSet.empty) {
	        DOpus.Output('< none >');
    } else {
        for (var e = new Enumerator(filesWithLabels); !e.atEnd(); e.moveNext()) {
			var filepath = e.item(); // key
			var labels = filesWithLabels(filepath); // values
            DOpus.Output(filepath);

			var strLabels = "";
			for (var i = 0; i < labels.count; i++) {
				strLabels += labels(i) + ", ";
			}
			strLabels = strLabels.slice(0, -2); // Gets rid of final comma & space ", "
			
            DOpus.Output(strLabels);
            DOpus.Output("");
        }
    }
}

This code will now display all the file paths with labels (multiple labels are comma-separated, see strLabels var).

1 Like

@bytespiller No wonder I was not getting it, nothing I did is similar to what you did, who knows, knows. I have no words to thank you so much, THANK YOU SO MUCH!!! :smiling_face_with_three_hearts:

Hi @bytespiller, me again, sorry, but I wanted to ask you something. I have the following labels...

01

The first ones (Colores) are applied automatically according to the type of file (images, audio, etc.), and the second (Estado) are applied by me. I would like the script to only consider the labels that I apply, that is, "Favorito", "Ok" and "Posición Actual".

I tried to create the following condition but it didn't work...

if (labels == "Favorito" || labels == "Ok" || labels == "Posición actual") {
    labels == labels;
	   } else {
	   labels == "";
	   }

I have two doubts:

  1. What is the variable that contains the name of the label before the label string is formed?
  2. Where should I insert the condition?

Or do you recommend another way to solve this situation? Thank you so much!

You can try changing this:

var itemLabels = item.Labels();

for this:

var itemLabels = item.Labels("*","explicit");

PS: I think you should ask these questions in the appropriate Help section in a new post, as asking about modifications or uploading modified versions of the original script may dilute its original purpose. Your questions and doubts are always welcome, but this section is for posting finished scripts only.

3 Likes

Thank you so much @errante for the code, that worked PERFECT, as for the recommendation to ask in the appropriate section (Help section), I had not perceived that I was asking in the finished scripts section, sorry everyone, mushas thanks once again!!! :pray: