How to dynamically update a File Collection when new files are added to a folder?

How to dynamically update a File Collection when new files are added to a folder?

I would like to achieve the following:

When a folder is added to a File Collection, if new files are later added to that folder, I want those new files to automatically appear in the collection — essentially achieving a "dynamic update" for the collection.

Is there any script or button that can be used to refresh a collection, so it updates to reflect newly added files in the original folder?

Thank you!

Using Libraries may make more sense, if the aim is to have something that always reflects what’s in a combination of folders.

But there are several other ways to do similar things as well. Which is best will depend on exactly what you’re aiming to do. For example, do you want to be able to remove items without deleting them from disk.

Thanks for the suggestion! To clarify my goal:

I would like to have a File Collection that automatically includes all the files from a specific folder (i.e., it updates when new files are added to that folder), but I also want to be able to manually remove certain items from the collection without deleting them from the original folder on disk.

Is there a way to achieve this combination — a collection that auto-updates but still allows manual pruning of entries independently?

Thanks again!

This should be doable with a script that monitors the folder and sends new files to the collection.

That sounds like the best solution! A script that monitors the folder and updates the collection automatically would be perfect.

However, since I’m not familiar with scripting or programming, it might be a bit challenging for me to implement. Still, I really appreciate your patient and helpful explanation — thank you, lxp!

Give this script a try.

function OnInit(initData) {
    initData.name = 'WatchFolderForCollection';
    initData.version = '2025-05-28';
    initData.url = 'https://resource.dopus.com/t/how-to-dynamically-update-a-file-collection-when-new-files-are-added-to-a-folder/55902';
    initData.desc = 'WatchFolderForCollection';
    initData.default_enable = true;
    initData.min_version = '13.0';
}

function OnAddCommands(addCmdData) {
    var cmd = addCmdData.AddCommand();
    cmd.name = 'WatchFolderForCollectionStart';
    cmd.method = 'OnWatchFolderForCollectionStart';
    cmd.desc = 'WatchFolderForCollectionStart';
    cmd.label = 'WatchFolderForCollectionStart';
    cmd.template = '';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'WatchFolderForCollectionStop';
    cmd.method = 'OnWatchFolderForCollectionStop';
    cmd.desc = 'WatchFolderForCollectionStop';
    cmd.label = 'WatchFolderForCollectionStop';
    cmd.template = '';
    cmd.hide = false;
    cmd.icon = 'script';
}

var folderToWatch = 'D:\\test';
var targetCollection = 'coll://WatchedFolderCollection';

var itemID = 'FolderForCollection';
var fsu = DOpus.FSUtil();

if (!fsu.Exists(folderToWatch)) {
    var cmd = DOpus.Create().Command();
    cmd.RunCommand('CreateFolder NAME="' + folderToWatch + '"');
}

if (!fsu.Exists(targetCollection)) {
    var cmd = DOpus.Create().Command();
    cmd.RunCommand('CreateFolder NAME="' + targetCollection + '"');
}

function OnWatchFolderForCollectionStart(scriptCmdData) {
    fsu.WatchChanges(itemID, folderToWatch, 'f');
    var ssi = DOpus.Create().StringSetI(fsu.ReadDir(folderToWatch).Next(-1));
    Script.vars.Set('ssi', ssi);
    DOpus.vars.Set('WatchFolderForCollection', 'on');
}

function OnWatchFolderForCollectionStop(scriptCmdData) {
    fsu.CancelWatchChanges(itemID);
    DOpus.vars.Set('WatchFolderForCollection', 'off');
}

function OnFilesystemChange(FilesystemChangeData) {
    if (FilesystemChangeData.id != itemID) return;

    var ssi = Script.vars.Get('ssi');

    var cmd = DOpus.Create().Command();
    cmd.ClearFiles();

    var folderEnum = fsu.ReadDir(folderToWatch);
    while (!folderEnum.complete) {
        var folderItem = folderEnum.Next();
        if (ssi.insert(folderItem)) {
            cmd.AddFile(folderItem);
        }
    }
    folderEnum.Close();

    Script.vars.Set('ssi', ssi);

    cmd.SetDest(targetCollection);
    cmd.RunCommand('Copy COPYTOCOLL=member');
}

Save CommandWatchFolderForCollection.js.txt to   

%appdata%\GPSoftware\Directory Opus\Script AddIns

You can define the folder and the collection in the script via

var folderToWatch = 'D:\\test';
var targetCollection = 'coll://WatchedFolderCollection';

and toggle the monitoring with this button:

XML
<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<label>WatchFolderForCollection</label>
	<icon1>#folder</icon1>
	<function type="normal">
		<instruction>@evalalways:WatchFolder = $glob:WatchFolderForCollection == &quot;on&quot;</instruction>
		<instruction>@label:&quot;Monitoring is &quot; + (WatchFolder ? &quot;&lt;b&gt;on&lt;/b&gt;&quot; : &quot;off&quot;)</instruction>
		<instruction>@toggle:update</instruction>
		<instruction />
		<instruction>=return WatchFolder ? &quot;WatchFolderForCollectionStop&quot; : &quot;WatchFolderForCollectionStart&quot;</instruction>
		<instruction />
		<instruction />
		<instruction>// https://resource.dopus.com/t/how-to-dynamically-update-a-file-collection-when-new-files-are-added-to-a-folder/55902</instruction>
	</function>
</button>

Files added to the folder after switching the monitoring on will be sent to the collection.

Thank you so much, lxp! Your script and detailed instructions have perfectly solved my problem.

What seemed like a difficult task at first became completely manageable thanks to your help. I really appreciate the time and effort you put into this, especially for someone like me who isn’t familiar with scripting. Your support has been incredibly valuable — thank you again!

Good to hear :slight_smile:

Two things I haven't mentioned:

  • Subfolders are not monitored (non-recursive)
  • The list of files that are marked "not new" will be cleared when Opus is restarted (non-persistent)

Both features could be implemented, but might come with a decrease in performance.

Hi lxp,

First of all, thank you again for your generous help and patient explanations — I really appreciate your support throughout this process.

After some testing, I did notice the limitation you mentioned regarding subfolders not being monitored. Since many of the folders I want to track contain nested directories, this does affect my use case. As for the second point about the "non-persistent" tracking of processed files, I haven’t encountered any major issues with it so far, but I’ll keep an eye on it in longer-term use.

I also have a suggestion — would it be possible to allow the script to monitor multiple folder-to-collection pairs at the same time? For example, being able to configure something like:

makefile

复制编辑

D:\Folder1 → Collection1  
D:\Folder2 → Collection2

This could be very useful for people managing multiple projects or file sources.

Thanks again for all your effort — your work has been incredibly helpful!

This update lets you monitor an unlimited number of folder/collection pairs.

CommandWatchFolderForCollection.js.txt

Define the pairs in the script via

AddFolder('L:\\Folder1', 'coll://WatchedFolderCollection1');  

Pass a third parameter to enable recursive scanning. Use false to explicitly ask for non-recursive.

AddFolder('L:\\Folder2', 'coll://WatchedFolderCollection2', true);

The button works as before.


function OnInit(initData) {
    initData.name = 'WatchFolderForCollection';
    initData.version = '2025-05-29';
    initData.url = 'https://resource.dopus.com/t/how-to-dynamically-update-a-file-collection-when-new-files-are-added-to-a-folder/55902';
    initData.desc = 'WatchFolderForCollection';
    initData.default_enable = true;
    initData.min_version = '13.0';
}

function OnAddCommands(addCmdData) {
    var cmd = addCmdData.AddCommand();
    cmd.name = 'WatchFolderForCollectionStart';
    cmd.method = 'OnWatchFolderForCollectionStart';
    cmd.desc = 'WatchFolderForCollectionStart';
    cmd.label = 'WatchFolderForCollectionStart';
    cmd.template = '';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'WatchFolderForCollectionStop';
    cmd.method = 'OnWatchFolderForCollectionStop';
    cmd.desc = 'WatchFolderForCollectionStop';
    cmd.label = 'WatchFolderForCollectionStop';
    cmd.template = '';
    cmd.hide = false;
    cmd.icon = 'script';
}

var cmd = DOpus.Create().Command();
var fsu = DOpus.FSUtil();

var folderWatchConfig = {};
var idCounter = 1;

AddFolder('L:\\Folder1', 'coll://WatchedFolderCollection1');        // Non-recursive (default)
AddFolder('L:\\Folder2', 'coll://WatchedFolderCollection2', true);  // Recursive

function AddFolder(folderPath, targetCollection, isRecursive) {
    var watchID = 'folderWatch' + idCounter++;

    folderWatchConfig[watchID] = {
        id: watchID,
        folder: folderPath,
        collection: targetCollection,
        recursive: !!isRecursive
    };
}

function OnWatchFolderForCollectionStart(scriptCmdData) {
    for (var id in folderWatchConfig) {
        var item = folderWatchConfig[id];
        var folder = item.folder;
        var collection = item.collection;
        var recursive = item.recursive;
        var watchFlags = recursive ? 'fr' : 'f';
        var readFlags = recursive ? 'r' : '';

        cmd.RunCommand('CreateFolder' +
            ' NAME="' + folder + '"' +
            ' NAME="' + collection + '"');

        fsu.WatchChanges(id, folder, watchFlags);
        Script.vars.Set('ssi' + id, DOpus.Create().StringSetI(fsu.ReadDir(folder, readFlags).Next(-1)));
    }

    DOpus.vars.Set('WatchFolderForCollection', 'on');
}

function OnWatchFolderForCollectionStop(scriptCmdData) {
    for (var id in folderWatchConfig) {
        fsu.CancelWatchChanges(id);
    }

    DOpus.vars.Set('WatchFolderForCollection', 'off');
}

function OnFilesystemChange(FilesystemChangeData) {
    var id = FilesystemChangeData.id;
    var item = folderWatchConfig[id];
    if (!item) return;

    var ssi = Script.vars.Get('ssi' + id);
    var folder = item.folder;
    var collection = item.collection;
    var recursive = item.recursive;
    var readFlags = recursive ? 'r' : '';

    cmd.ClearFiles();

    var folderEnum = fsu.ReadDir(folder, readFlags);
    while (!folderEnum.complete) {
        var folderItem = folderEnum.Next();
        if (!ssi.insert(folderItem)) continue;
        cmd.AddFile(folderItem);
    }
    folderEnum.Close();

    cmd.SetDest(collection);
    cmd.RunCommand('Copy' +
        ' COPYTOCOLL=member' +
        ' WHENEXISTS=skip');

    Script.vars.Set('ssi' + id, DOpus.Create().StringSetI(fsu.ReadDir(folder, readFlags).Next(-1)));
}

Hi lxp,

Wow — thank you so much for the updated script and for adding support for multiple folder/collection pairs, as well as recursive monitoring! This really goes above and beyond, and I’m incredibly grateful for the time and expertise you’ve put into helping me.

I tested the new version and it's working wonderfully. The ability to monitor multiple folders at once, each mapped to its own collection, fits my workflow perfectly. Adding the recursive option is especially helpful, as many of my folders have subdirectories that I need to track as well.

Your support has completely resolved my original request — and in fact, provided an even better and more flexible solution than I had imagined. Thank you again for your generosity and detailed guidance!

Best regards