Event: Override Formats (or View Modes) on folder change

OverrideFormats - an event based DO extension, which allows to override the folder format chosen by DO (or switch viewmode and columns only).

Since v0.3, the expression syntax has changed. Now functions are used to set view/format etc.

Description:
This extends the currently available content-type detection in DO by also taking the number of folders and files into account (e.g.). You can configure simple expressions (rules), to define when to use what viewmode or folder-format. So in case you always want folders containing more than 1000 files to use details mode, here you go.

Features:

  • Black listing of folders (regex based)
  • White listing of folders (regex based)
  • Javascript expressions to define rules
  • Call additional commands after folderchange
  • Debug output (to help nail down any problems with black/white lists and your expressions)

Usage:
The most important thing to know is, how to setup things in the scripts config section under "Expressions". There, you have predefined getter-variables to check the situation. These are "data" (=OnBeforeFolderChangeData), "folderCount", "fileCount", "curView" and "curPath" (which is the DO path object). There's an ifPath() and ifLabel() function as well to tests for paths and drive labels easily (watch default expression for example).

To override a format, there are several function available to modifiy the lister appearance since v0.3:
addCol() - to add a column
remCol() - to remove a column
setView() - to set a view mod (accepts any option of the "Set VIEW" command)
setFormat() - to set a folder format (accepts any option of "Set FORMAT" or "Set CONTENTFORMAT")
setPat() - to switch a path
noQuit() - to not quit on evaluation

Watch these two examples..

//use details view, if more than 3 folders)
folderCount>3 && setView('details')

//switch path to C:\ for empty folders o)
folderCount==0 && fileCount==0 && setPath('C:\\')

These expressions need to be valid javascript code.

Config-Notes:
I won't go into details on how to setup the black and whitelists for folders, you can disable these lists completly or simply put regular expressions in there to restrict the overrider to special locations. There are some sensible regular expressions already included. In case you mess up an expression or folderlist, you'll find errors in the console if debug output is enabled. So go and check this place in case things do not work as expected. If enabled, the whitelist is going to override the blacklist.

Demo-Output - showing all crucial details and expression evaluation results:

Installation:
To install the script, download the *.js.txt file below and drag it to Preferences / Toolbars / Scripts.

Comments and bug reports welcome. o)
cya, tbone

Download:

In 11.6 we've made it easier to install scripts with a .js.txt extension (you can drop them straight on the Preferences page, without having to rename them; Opus will remove the extension itself), but it'd still be worth adding a line or two to your script posts telling people what to do with them, as people end up asking in most threads that leave it out.

I added short installation instructions in the meantime of course. Your wish is my command. o)

I made a little change and uploaded version 0.1a

  • changed order of "Go" and "Set FORMAT" commands (set after go)

Customizing lister backgrounds for empty folders and drives:
With OverrideFormats we now can customize dopus to show something special for empty folders and drives as well. To do so, create a new favourite format named "Empty" in "Preferences -> Folder Formats -> Favourite Formats", and just set a nice lister background for it, nothing else. Then that add "folderCount==0 && fileCount==0 (newFormat='Empty')" to the list of expressions in the script config. After that you should get something like this for every empty directory or drive (think of usb sticks here maybe). Neat? o)


Background image attached (renamed to hide it here):
empty.png.txt (67 KB)

Updated to v0.3

  • skipping non existing additional commands
  • usage of data.tab.format.locked instead of isSet()
  • support for onafterfolderchange event
  • allows adding/removing of columns
  • confighelper
  • min version added
  • prepared for updates/scriptwizard

Updated to v0.3.1

  • added ifLabel() to enable format/column/viewmode changes for specific drivelabels

Does the ifPath() function support negative lookaheads? I know Javascript's implementation of RegEx does.

Example: If I wanted to match every folder except my one music folder:

ifPath('(?!V:\\Music\\Collection\\.+).*') && setFormat('Custom') && setView('details')

Definition of a negative lookahead and its uses in RegEx: regular-expressions.info/lookaround.html

This line currently matches every folder, including everything inside V:\Music\Collection\.

It should match everything, except each folder inside V:\Music\Collection\.

EDIT: Adding a note. This doesn't seem to work in the Blacklist either. Am I doing something wrong? By JS RegEx standards, it should match properly as I want it to. (I am using RegExBuddy)

EDIT 2: Negative lookahead does work in DOpus Path Formats.

Yes negative lookaheads should be supported by JScript, but remember this must not necessarily be the same for what Javascript supports.
In case you cannot get it to work with negative lookaheads, I guess you could also just blacklist that single folder?

This actually is what the ifPath() function looks like, I only do some doubling on the backslashes.

function ifPath(path){
    if (String(curPath).match(path.replace(/\\/g,'\\\\'))) return true; return false;
}

I checked the standards on negative lookaheads in Javascript, and the way I am laying out the RegEx match string should be correct. I even tested with RegEx buddy, and it matches/doesn't match what I want it to. Yet, OverrideFormats won't attempt to check the negative lookahead. It just skips the lookahead pattern and matches what's after it (.*), which means everything. :confused:

Putting the negative lookahead in the Blacklist doesn't work either. Putting the folder in the whitelist didn't seem to help either. I ended up having to hardcode the negative lookahead in a separate Path Format in DOpus settings, and comment out the line in the whitelist, ^.:\\.* (so that it became //^.:\\.*) to disallow OverrideFormats from processing overrides in other folders, which I didn't want to do... lol.

Wait, so your path function is replacing every slash with two backslashes? I don't know javascript very well, but that's what the function looks like it's doing.

See here, so you know what I am attempting to do, though you may already know... lol.

Putting the "nela" pattern into the blacklist is not sensible I guess.
Please try again with the plain path of the folder not to be touched by OF (adding $ at the end maybe, to not make it fit any sub-paths).

It always good to try with the actual regex engine you have problems with. I did some JScript tests and would say "nelas" do work, but maybe not how they are described elsewhere for "regular" expressions. o)

So try this (in case you do not make use of the blacklist for that particular folder), to override format/view for "V:\Music" and any subfolders excluding "Collections":

ifPath('V:\\Music(?!\\Collection$).*') && setFormat('Custom') && setView('details')

Hope that works for you, if not please report back, this is something we all can learn from. o)

I want to make sure everyone understands what I am trying to accomplish.

This image shows what I want: db.3rdn3rd.com/img/2014-12-18_00-14-24.gif

Unfortunately, I soon found out after making that gif that if I went back up past the collection folder, every folder had the inner-most columns-specifications (the 'music' content type format settings). It replaces the default until I return to defaults again. I'll explain in more detail what I did.

I first used just this line below in the Before.Expressions:

ifPath('V:\\Music\\Collection\\.+') && fileCount>2 && setFormat('music') && setView('details')

The filecount check makes sure it doesn't override my preferred thumbnail mode for album views.

This worked, but then the custom "music" format settings I modified became the default for any and every folder outside of the Collection folder. It became the main view, and I would have to forcibly return the folder format to defaults every time I left my Collection folder.

So I thought I'd add another line to reset everything else outside of the Collection folder to default view format (using a Favorite format called "Default"). This is what I am having trouble with.

ifPath('(?!V:\\Music\\Collection\\.+).*') && setFormat('Default') && setView('details')

This would not work, because it would override everything, as if .* is all that was being matched.

I looked at the logs, and it was processing this line for every folder, inside and outside my Music\Collection folder:

I ended up commenting the second addition out, and using a separate Path Format with (?!V:\\Music\\Collection\\.+).* as the path (wildcard match with RegEx option), and setting the folder to detail mode. I don't like hardcoding an 'else-like' case for path matching, because it seems dirty to me. I should only need to specify the folders I want to match, not a complete "non-match" option. This means I have to add exlusions for everything else I may want to change in the future. If I was the type to set custom folder formats for specific formats, this choice of operation would completely wipe those custom format settings away.

@Drakonas, using negative lookahead without anchoring the search is a pita and usually won't do what you expect it to do.
Your last example will return a match for the folder you're trying to avoid matching (it matches from : onwards).

Prefix the regex with ^ and it won't.
In other words:

ifPath('^(?!V:\\Music\\Collection\\.+).*') && setFormat('Default') && setView('details')

Oh, and the matching is casesensitive (regexes is by default casesensitive in most engines).

A caseinsensitive ifPath function would look something like this:

function ifPath(path){
    var re=new RegExp(path.replace(/\\/g,'\\\\'),"i");
    if (String(curPath).match(re)) return true;
    return false;
}

Now see, this shows my inexperience with RegEx. Lol. That fixed my problem entirely.

I would like to use modifiers like (?i) or /i, which are native RegEx case insensitive options that stay inside the RegEx pattern. Unfortunately, it seems Javascript does not support modifiers. Java does though. :confused:

EDIT: My success: db.3rdn3rd.com/img/2014-12-25_02-15-25.gif

Updated to v0.3.2

  • fix to prevent exception for "empty" command object
  • ifPath() method non-casesensitive by default, custom regex modifiers can be passed in 2nd argument

Good! Thanks myarmor for showing your regex solution, it seems achoring is the trick for the "nelas", my example used the $ anchor and should also work.

Javascript and Java have absolutely nothing in common despite some fractions of their syntax and the 4 letters in their name. o)
I uploaded a tiny update, the ifPath() function is non-casesensitive now and allows overriding of the default "gi" modifiers like so ifPath("D:\test", "g")

The trick is to make it impossible for the (back)tracker to work around the nela and still get a match by backtracking or skipping ahead.
Btw, whatever you use as anchors has to be outside the nela, otherwise it isn't anchoring anything (except the regex inside the nela).
In your example it was V:\Music that anchored it, not the $.

@Drakonas, :slight_smile:

By your description of why to use the $ character, I thought I would not want it because I wanted to include subfolders in the match. Forgot it was just an ending-anchor character.

I used this successfully, if anyone's wondering:

^(?!V:\\Music\\Collection\\.+).*

@myarmor
Thanks for explaining, very appreciated! It's not often I tinker with nelas or such, so any lesson welcome. o)

@drako
I see I see, np. o) Still wondering if you could have used the blacklist as well, I'd think so, but anyway, many roads lead to Rome.
What tool did you use to create the little animation? Looks like a cool way to demonstrate specific needs/issues or general functionality.

I guess I just didn't like the idea of having a long line of folders to "not-blacklist" in a single RegEx string. Example:

^(?!V:\\Music\\Collection\\.+)(?!G:\\.*)(?!K:\\.*)(?!P:\\.*)(?!V:\\Videos.*).*

I ended up having to use this in a Path Folder format anyway, since the format/view changes done by OverrideFormats stick permanently until another Content Type Format or OverrideFormat is matched, so now that you mention it, I guess I will just add it to the blacklist.
tries
Oh dear... This happened.

See, I can't very well put this in the blacklist...:

(?!V:\\Music\\Collection\\.+)
(?!G:\\.*).*
(?!K:\\.*).*
(?!P:\\.*).*
(?!V:\\Videos.*).*

...because then they would cross each other out.

Best thing ever: ShareX. It's been passed on from developer to developer, but it's had a stable home for quite some time now, while being constantly active in development. And it's open source. :wink:

Plus, I can do this:

I recommend checking the alpha transparency. :wink:

If those are the folders you want to exclude then you can write it like this:

^(?![GKP]:\\|V:\\(?:Music\\Collection\\.+|Videos)).*

This matches all the folders in the above list, in the same way as you listed them.

In other words:

  • It excludes subfolders/items of V:\Music\Collection, but not the folder itself (remove .+ to include it).
  • It excludes all paths beginning with V:\Videos (e.g. V:\VideosTest), and everything on the G, K and P drives.

These ShareX animations are cool, but I noticed, they're quite huge in size, didn't expect that. But then it's a gif, maybe I should have. o)

Can't you setup DO to apply your "music-type"-format to V:\Music and override just the Collection (and subfolders maybe) with OF?
That's how I use it (I think o), so I do not run into the issue that DO does not reset the format, once it's been changed manually or by script.

Yeah, it all depends on what resolution your gif is going to be. Even though the gif uses less frames per second the larger the gif is, it still ends up being larger in size.

That might work. The problem is there are many other folders in my V:\Music that I don't want in the "music-type" format, because I can't view filenames properly in that format (on purpose).

I have been using your script and DOpus's formats successfully, but one problem still remains. The problem I used to have was the music folder format getting stuck outside of the Collection folder, right? So unless I added '^(?!V:\Music\Collection\.+)(?!G:\.+)(?!K:\.+)(?!P:\.+).*' as a filter for blacklisting via your script or as a wildcard folder format (both set to default format and detail view), the music format would stick after I entered into an album folder in V:\Music\Collection, and then exited the entire collection.

Well, there's a problem with setting those blacklisting filters, regardless of the method. No content type ever gets detected outside of my V:\Music\Collection folder. So, if I want a picture folder somewhere on my computer to be detected as pictures, and thusly have the folder format set to image content type format, I have to add another OverrideFormat or Path Folder Format to DOpus for the specific path, which is redundant.

I thought of an idea that should work, however. But it all depends on whether a "curFormat" as a data check (OnBeforeFolderChangeData) is possible or not.

Consider the example of my blacklist filter in OverrideFormats below:

ifPath('^(?!V:\\Music\\Collection\\.+)(?!G:\\.+)(?!K:\\.+)(?!P:\\.+).*') && setFormat('Default') && setView('details')

The one thing that could be added to erradicate the issue for me is adding a "curFormat" check:

ifPath('^(?!V:\\Music\\Collection\\.+)(?!G:\\.+)(?!K:\\.+)(?!P:\\.+).*') && curFormat='music' && setFormat('Default') && setView('details')

Would this be possible?

EDIT: I think I may have found my problem. I may not have understood the difference between OnAfterFolderChange and OnBeforeFolderChange.

I finally got it working 100% properly! Details below.

I've removed commented, unused lines below.

Here's my Before.Expressions:

#enable thumbnail view for album folders
# EDIT # This is done via Custom Music Path Format, which is set for the following wildcard path:
# EDIT # By putting these in a Path Format RegEx path match, thumbnail view will be used by default in the specified Music Collection folders with proper layout.
# EDIT # This is done so that folders can be viewed as thumbnail'd coverart, and scans can be viewed as thumbnails.
# EDIT # OverrideFormats will override the thumbnail view when the folder contains >2 files (music), as per the filters further down.
# ^V:\\Music\\Collection\\.*
# ^G:\\.*
# ^K:\\.*
# ^P:\\.*

#enable details view and custom format for all folders besides specified
# EDIT # Originally, the better alternative to this is adding the below path to a Path Format filter to reset to 'custom' format.
# ^(?!V:\\Music\\.)(?!G:\\.)(?!K:\\.)(?!P:\\.)(?!V:\\Videos.)(?!V:\\Pictures.).*
# EDIT # But both that and this are DISABLED because it overrides Content Type Formats.
# EDIT # (We are fixing this via other filters.)
#ifPath('^(?!V:\\Music\\.)(?!G:\\.)(?!K:\\.)(?!P:\\.).*') && setFormat('Default')

#force Music format and detail view for specified Music folders/drives with my Music Collection layout, but only if there is music inside (so as not to override the album folder thumbnail view set via Path Formats).
ifPath('^V:\\Music(?!\\Misc)(?!\\Mixmeister\ Projects)(?!\\Radio)(?!\\Sound\ Effects)(?!\\Converted)(?!\\Ableton\ Live\ Projects)(?!\\Action\!).*') && fileCount>2 && setFormat('music') && setView('details')
ifPath('^G:\\.+') && fileCount>2 && setFormat('music') && setView('details')
ifPath('^K:\\.+') && fileCount>2 && setFormat('music') && setView('details')
ifPath('^P:\\.+') && fileCount>2 && setFormat('music') && setView('details')

#reset the folder view after leaving the Music album folders (if going to V:\Music or V:\Music\Collection only [no subfolders], so as not to override everywhere).
# EDIT # This makes sure that when leaving the Overridden folders (from the last filters above) to the outermost Collection folder or Music folder, the view/format gets reset properly.
# EDIT # Otherwise the said outermost folder will keep the music format one-time.
ifPath('^V:\\Music(\\Collection)*(?!\\.)') && setFormat('Default') && setView('details')

Here's my After.Expressions:

#Remove Music-related columns from folders that are not music-related
# EDIT # The start of this RegEx may be confusing. I discovered that there is such a thing as recursive negative lookaheads.
# EDIT # It makes sure that the entire RegEx pattern matches both V:\Music AND V:\Music\Collection, but no subfolders, and nothing in the other specified locations/drives.
# EDIT # One would think this would be a simpler approach: ^V:\\Music(\\Collection)*(?!\\.)
# EDIT # But it could not be used, because it would then be more complex to add the other locations into the RegEx for exclusions.
# EDIT # Reference for columns can be found here: https://www.gpsoft.com.au/help/opus11/index.html#!Documents/Keywords_for_Columns_Set_Command.htm
ifPath('^(?!V:\\Music\\(?!Collection(?!\\.)$).)(?!G:\\.)(?!K:\\.)(?!P:\\.).*') && remCol('thumbnail,mp3track,mp3title,mp3artist,mp3songlength,mp3genre,mp3year,mp3type')

My Before.Blacklist.Folders:

//disallow for non-root network locations
^\\\\.*\\.*
//disallow for ftp locations
^ftp:.*

My Before.Whitelist.Folders:

//allow for all local drives
^.:\\.*

My After.Whitelist.Folders:

//allow for all local drives
^.:\\.*

Set After.AddCommands to "True".