Columns: Movie Filename Database

This is a script I made for a friend who has a huge movie collection. He wanted to keep track of movie's directors, countries and a few other fields. He bought Opus just for this script. I thought it was so cool I had to perfect it and share it.

This is what the script does for movies in any file format. There are many other columns not shown.


There's also a cool button that opens the imdb page for the selected movie.


I'm really excited about this way of working with files and look forward to feedback and a fruitful discussion. Apart from feedback and brainstorming on this script, I am particularly interested in hearing your thoughts about using file naming conventions to manage metadata.

Quick Tour

1. The script is based on RegexColumnsReloaded (mmm, actually it's the other way around)

2. There is a full tutorial on my new page about Using File Names to Make a Database

3. It showcases how if you use a simple naming convention, Opus can display any column you invent for files of any kind.

4. You can adapt this simple naming convention to files of any kind.
In fact I adapted it to make Columns: Books & Comics Filename Database.

The basic convention for a file is:
Title [metadata].extension

Inside the brackets, the metadata looks like this:
[year=2004_dir=Martin Scorcese]

  • It is a sequence of key=value, separated by underscores.
  • The fields can be specified in any order.
  • Many fields have aliases in case you don't remember the name.
  • For each file, you only specify the fields you want.

5. Adding or editing columns is a snap. The column definitions have really cool features. See the section of the tutorial on editing and defining fields.

6. The Magic Button

2020-04-15 21-09-16 Clipboard Image

Movies.dcf (7.87 KB)
(How to use buttons and scripts from this forum)

The button has three functions:

  • Toggles a Movies format you specify in Prefs / Folder Formats / Favorite Formats. (If you prefer to use the Content Type Format in the same menu, the function's code is easy to adapt.)
  • Launches the imdb page for the selected movie. For that, the filename must already contain a TT field corresponding to the movie page. For instance, set tt=tt0258463 for The Bourne Identity [LINK imdb.com/title/tt0258463/ ]
  • Google searches for the movie's imdb page when the tt field is not yet in the filename. The first one is usually right, so just double-click the tt code and add it to the file name.

7. List of fields


8. Movies format
You will want to make a Books+Comics format either in
Prefs / Folder Formats / Favorite Formats
or in
Prefs / Folder Formats / Content Type Formats

In that format, I recommend shrinking the filename column, as you don't need to display it. Even when the file name is shrunk, you can easily select the file when enable full row selection in on (clicking anywhere on the row selects the file). The Movie button toggles full row selection so you shouldn't have to worry about that.

This is what my current view looks like.

9. Bulk addition of metadata on many files
This is a rename problem. See the bulk metadata operations section of the tutorial.

In short, you can set up rename presets.

Here's one which inserts a sample token ( cc=US token ) if you already have [metadata in brackets]:

  • Opus rename in regex mode
  • Search for ^([^\]]+)(\].*)
  • Replace with \1_cc=US\2
  • Save the preset, adapt when needed.

10. Limitation
Please bear in mind that Windows has a limit on the total length of path + file name: 260 characters. That's a lot of characters but it's good to keep in mind. Better now bury the files deep in the file hierarchy.

11. Script Add-In Download
MovieFilenameDB_underscores_only.js.txt (37.1 KB)
(To install, download the file and drag it to the list under Preferences / Toolbars / Scripts.)

12. Changelog
0.9.3 Small suggested fix
0.9.2 At tbone's request, changed the column prefix from Movies_ to Movies.
0.9.1 Added three properties (got these ideas from Apocalypse): fileOnly, dirOnly, fullCupValue.


The code in the two downloads above is reproduced here for reference. This is just to help people browsing the forum for scripting techniques.

Code for 6. The Magic Button:

The button is a button-menu with five functions.

Main button part:

var FirstFileOnly = true;
///////////////////////////////////////////////////////////////////////////////
function OnClick(data) {
  LaunchUrl(data, FirstFileOnly);
}
///////////////////////////////////////////////////////////////////////////////
function LaunchUrl( data, firstFileOnly){
  var cmd = data.func.command, tab = data.func.sourcetab;
  var pattern = /\[(?:[^\]]+_)?tt=([^\]_]+)/i;
  cmd.ClearFiles();
  for (var iEnum = new Enumerator(tab.selected); !iEnum.atEnd(); iEnum.moveNext()){
      var file = iEnum.item();
      var matchArray = pattern.exec(file);
      if (matchArray != null) {
         var tt = matchArray[1];
         var url = "http://www.imdb.com/title/" + tt;
         cmd.RunCommand(url);
      }
      if (firstFileOnly) break;
  }
}

Toggle Movie View menu item:

@ifset:FULLROWSELECT=on
Set FULLROWSELECT=off
Set FORMAT !custom
@ifset:else
Set FULLROWSELECT=on
Set Format "Movies"

Search IMDb menu item:

var FirstFileOnly = true;
///////////////////////////////////////////////////////////////////////////////
function OnClick(data) {
  LaunchUrl(data, FirstFileOnly);
}
///////////////////////////////////////////////////////////////////////////////
function LaunchUrl( data, firstFileOnly){
  var cmd = data.func.command, tab = data.func.sourcetab;
  var pattern = /^(?:[^ ]| (?!\[))+(?=.*\..)/;
  cmd.ClearFiles();
  for (var iEnum = new Enumerator(tab.selected); !iEnum.atEnd(); iEnum.moveNext()){
      var file = iEnum.item();
      var fileName = new String(file.name);
      var matchArray = pattern.exec(fileName);
      if (matchArray != null) {
         var tt = matchArray[0];
         // var url = "https://www.google.com/search?q=site:imdb.com" + encodeURIComponent(" " + tt);
         // NOTE THAT the % char is escaped: %%20
		 var url = "https://www.google.com/search?q=site:imdb.com%%20" + tt.replace(/ /g,"-");
		 // DOpus.Output(tt);
		 // DOpus.Output(url);
         cmd.RunCommand(url);
      }
      if (firstFileOnly) break;
  }
}

Launch IMDb (First File) menu item:

var FirstFileOnly = true;
///////////////////////////////////////////////////////////////////////////////
function OnClick(data) {
  LaunchUrl(data, FirstFileOnly);
}
///////////////////////////////////////////////////////////////////////////////
function LaunchUrl( data, firstFileOnly){
  var cmd = data.func.command, tab = data.func.sourcetab;
  var pattern = /\[(?:[^\]]+_)?tt=([^\]_]+)/i;
  cmd.ClearFiles();
  for (var iEnum = new Enumerator(tab.selected); !iEnum.atEnd(); iEnum.moveNext()){
      var file = iEnum.item();
      var matchArray = pattern.exec(file);
      if (matchArray != null) {
         var tt = matchArray[1];
         var url = "http://www.imdb.com/title/" + tt;
         cmd.RunCommand(url);
      }
      if (firstFileOnly) break;
  }
}

Launch IMDb (All Files) menu item:

var FirstFileOnly = false;
///////////////////////////////////////////////////////////////////////////////
function OnClick(data) {
  LaunchUrl(data, FirstFileOnly);
}
///////////////////////////////////////////////////////////////////////////////
function LaunchUrl( data, firstFileOnly){
  var cmd = data.func.command, tab = data.func.sourcetab;
  var pattern = /\[(?:[^\]]+_)?tt=([^\]_]+)/i;
  cmd.ClearFiles();
  for (var iEnum = new Enumerator(tab.selected); !iEnum.atEnd(); iEnum.moveNext()){
      var file = iEnum.item();
      var matchArray = pattern.exec(file);
      if (matchArray != null) {
         var tt = matchArray[1];
         var url = "http://www.imdb.com/title/" + tt;
         cmd.RunCommand(url);
      }
      if (firstFileOnly) break;
  }
}

Code for 11. Script Add-In Download:

///////////////////////////////////////////////////////////////
//              Movie Filename Database                      //
//                                                           //
//  Add movie columns to Opus, using either                  //
//              - file naming convention + regex search      //
//              - other means                                //
//                                                           //  
///////////////////////////////////////////////////////////////


/*
                   ___   
                  |   | 
                  |   |  
                  |   |  
                  |   |  
                  |   |  
                __!   !__
                \       /
                 \     / 
                  \   /  
                   \ /   
                    Y    
==> TO DEFINE THE COLUMNS, SCROLL ONE PAGE DOWN <==              
  Full Tutorial: http://www.dearopus.com/filename-database.html


*/


///////////////////////////////////////////////////////////////
//      ADAPTING THE SCRIPT FOR OTHER KINDS OF FILES         //
//   1. Edit the initData fields just below                  //
//   2. Edit the ColumnPrefix value right below initData     //
//   3. DEFINE THE COLUMNS: SCROLL ONE PAGE DOWN             //
///////////////////////////////////////////////////////////////


// Opus calls OnInit to initialize the script add-in
function OnInit(initData) {
	//uid added via script wizard (do not change after publishing this script)
	var uid = "98D528BF-0B42-4F51-85E0-6770DABF47BE";
	//resource center url added via script wizard (required for updating)
	var url = "http://resource.dopus.com/viewtopic.php?f=35&t=24708";
// basic information about the script
  initData.name = "Movie Filename Database";
  initData.desc = "Adds columns defined by regex search against filenames.";
  initData.copyright = "playful & contributors 2015";
  initData.min_version = "11.5.1"
  initData.version = "0.9.2";
  initData.default_enable = true;

  // The following prefix is added to the column names when looking at columns in 
  // the Folder Format panel, in order to distinguish the column from 
  // similar columns from other scripts. 
  // The prefix will not show in the actual column header
  var ColumnPrefix = "Movies.";



// Add all columns (create ScriptColumn objects via AddColumn()
// See http://www.gpsoft.com.au/help/opus11/index.html#!Documents/Scripting/ScriptColumn.htm
  for(var key in columns) {
      if (columns.hasOwnProperty(key)) {
       var column = columns[key];
       var cmd = initData.AddColumn();
       cmd.autorefresh = true;     
       cmd.defsort =  (typeof column.sort === 'undefined') || (column.sort != "DESC")  ? 1 : -1;     
       cmd.defwidth =  (typeof column.width === 'undefined') ? 5 : column.width;     
       cmd.header = key;
       cmd.infotiponly = (typeof column.infotiponly === 'undefined') ? false : column.infotiponly;
       cmd.justify = (typeof column.justify === 'undefined') ? "left" : column.justify;
       cmd.label = ColumnPrefix + key;
       cmd.method = "OnRegexColumn";
       cmd.name = key;
       cmd.namerefresh = true;
       cmd.type = (typeof column.type === 'undefined') ? null : column.type;
   }
  }
} // End OnInit

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
/////       DEFINE YOUR FIELDS (i.e. COLUMNS) HERE        /////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

 // Most columns will use a regex pattern, but you can also set columns
 // that don't use regex (see EXAMPLES OF NON-REGEX COLUMN below) 

 // For the regex fields / columns, you set several properties: 
 // 1. "pattern", i.e. the regex pattern,
 // 2. "target" (optional), i.e. the subject for the regex (e.g. the file name, the extension: see TARGET section below for details),
 // 3. "group" (optional), i.e. the capture group containing the column text (0 by default, i.e. the entire match)
 // 4. "width" (optional) to set the columns default width in characters.
 // 5. "justify" (optional), i.e. should the column be justified "left", "right", "center" or "path". The default is "left".
 // 6. "sort" (optional). When set to "DESC", if you click on the column to sort it, it will first sort in descending order
 // 7. "type" (optional). The column defaults to plain text, but it can also be set to number, double, size, zip, percent, igraph, date, time, datetime, stars 
 // 8. "infotiponly" (optional): when set to true, the column will only dispay in file hover info tips, which are defined for file types in the file type editor
 // 9. "subjectPrefix" (optional): a string that gets preppended to the target string to form the regex subject. This facility enables you to transform the text in the regex without writing a special column case.   
 // 10. "returnTheFirstNonEmptyGroup" (optional): a Boolean (true/false) that indicates we should return the first group that is not-empty. Takes precedence over "group"
 // 11. "fileOnly": restrict the column to files (don't display for folders)
 // 12. "dirOnly": restrict the column to folders (don't display for files) 
 // 13. "fullCupValue" (optional): using this value, convert to a scale of 5 or 100 depending on whether the type is stars (5) or percent, graph and igraph (100)

 // TARGETS
 // The regex pattern can be applied to several properties of the file item
 // We configure which property to run the regex on by setting "target" 
 // Possible values for target:
 // 1. default: no value or "name_stem: (the file name without the extension) 
 // 2. "realpath"  (the pattern applies to the full pathname, i.e. path plus filename) 
 // 3. "name" (the full file name including the extension)
 // 4. "ext" (the extension)
 // and more: see http://www.gpsoft.com.au/help/opus11/index.html#!Documents/Scripting/Item.htm


var columns = { 
/////// EXAMPLES OF REGEX COLUMNS //////////
// You can delete these if you don't need them

'Title' :    { 
    // The title (stripping [the keys=values] )
    pattern: /^(?:[^ ]| (?!\[))*/,
    width: 30
    },
'Actor' :   { 
    // Who featured in it?
    // acceptable aliases for key: act, actor, actress
    pattern: /\[(?:[^\]]+_)?act(?:or|ress)?=([^\]_]+)/i,
    group: 1
    },
'Again' :    { 
    // Would you like to watch it again some day?
    // acceptable aliases for key: again
    pattern: /\[(?:[^\]]+_)?again=([^\]_]+)/i,
    group: 1,
    width: 3
    },
'Award' :   { 
    // awards won. e.g. oscar, palme d'or
    // acceptable aliases for key: awd, award
    pattern: /\[(?:[^\]]+_)?aw(?:ar)?d=([^\]_]+)/i,
    group: 1
    },
'Camera' :   { 
    // Cinematographer e.g. Robby Muller
    // acceptable aliases for key: cam, camera, cin
    pattern: /\[(?:[^\]]+_)?c(?:am(?:era)?|in)=([^\]_]+)/i,
    group: 1
    },
'Color' :  { 
    // Is the movie in color? b&W?
    // acceptable aliases for key: col, color
    pattern: /\[(?:[^\]]+_)?col(?:or)?=([^\]_]+)/i,
    group: 1
    }, 
'CC' :  { 
    // Country code: Which country is the movie from?
    // acceptable aliases for key: cc, country
    pattern: /\[(?:[^\]]+_)?c(?:c|ountry)?=([^\]_]+)/i,
    group: 1,
    width: 2
    },
'Critique' :  { 
    // Critique, e.g. great, meh
    // acceptable aliases for key: crit, critique
    pattern: /\[(?:[^\]]+_)?crit(?:ique)?=([^\]_]+)/i,
    group: 1
    },
'Director' :   { 
    // Who directed it?
    // acceptable aliases for key: dir, director 
    pattern: /\[(?:[^\]]+_)?dir(?:ector)?=([^\]_]+)/i,
    group: 1,
    width: 15
    },
'IR' :  { 
    // imdb rating, e.g. 7.5
    // acceptable aliases for key: ir
    pattern: /\[(?:[^\]]+_)?ir=([^\]_]+)/i,
    group: 1,
    width: 3,
    sort: "DESC"
    },
'Lang' :  { 
    // Language, e.g. english
    // acceptable aliases for key: lang, lng
    pattern: /\[(?:[^\]]+_)?la?ng=([^\]_]+)/i,
    group: 1,
    width: 3
    },
'Min' :  { 
    // Duration, e.g. 120
    // acceptable aliases for key: min, dur, duration
    pattern: /\[(?:[^\]]+_)?(?:min|dur(?:ation)?)=([^\]_]+)/i,
    group: 1,
    width: 3,
    sort: "DESC"
    },
'Num' :  { 
    // Number in the series, e.g. 01
    // acceptable aliases for key: num, nb, no
    pattern: /\[(?:[^\]]+_)?n(?:[ob]|um)=([^\]_]+)/i,
    group: 1,
    width: 3
    },
'Qual' :  { 
    // Quality, e.g. great, blurry
    // acceptable aliases for key: q, qual, quality
    pattern: /\[(?:[^\]]+_)?q(?:ual(?:ity)?)?=([^\]_]+)/i,
    group: 1
    },
'Rating' :  { 
    // your rating
    // acceptable aliases for key: rat, rating
    pattern: /\[(?:[^\]]+_)?rat(?:ing)?=([^\]_]+)/i,
    group: 1,
    sort: "DESC"
    },
'Script' :  { 
    // Who wrote the script?
    // acceptable aliases for key: txt, text, scr, script
    pattern: /\[(?:[^\]]+_)?(?:te?xt|scr(?:ipt)?)=([^\]_]+)/i,
    group: 1
    },
'Seen' :  { 
    // have you watched it? E.g. yes, T, false, N, 1, 0...
    // acceptable aliases for key: seen, sn
    pattern: /\[(?:[^\]]+_)?s(?:een?|n)=([^\]_]+)/i,
    group: 1,
    width: 1,
    sort: "DESC"
    },
'Series' :  { 
    // e.g. 
    // acceptable aliases for key: ser, series
    pattern: /\[(?:[^\]]+_)?ser(?:ies)?=([^\]_]+)/i,
    group: 1
    },
'Subs' :  { 
    // subtitles, e.g. en,eng, de, fr
    // acceptable aliases for key: sb, sub, subs, sbs, subtitle, subtitles
    pattern: /\[(?:[^\]]+_)?s(?:b|ub(?:title)?)s?=([^\]_]+)/i,
    group: 1,
    width: 5
    },
'Tags' :  { 
    // tags, e.g. "comedy,romance"
    // acceptable aliases for key: tag, tags
    pattern: /\[(?:[^\]]+_)?tags?=([^\]_]+)/i,
    group: 1
    },
'TT' :  { 
    // imdb code, e.g. tt0478331
    // acceptable aliases for key: tt
    pattern: /\[(?:[^\]]+_)?tt=([^\]_]+)/i,
    group: 1,
    width: 2
    },
'Year' :  { 
    // What year was it released?
    // acceptable aliases for key: y, yr, year
    pattern: /\[(?:[^\]]+_)?y(?:(?:ea)?r)?=([^\]_]+)/i,
    group: 1,
    justify: "center",
    width: 4,
    sort: "DESC"
    },


/////// EXAMPLES OF NON-REGEX COLUMN //////////
// You can delete these if you don't need them 
// Define the columns here (name, width if appropriate etc)
// then add an "if" or "else if" case in the "First, handle special NON-REGEX Columns" section 

'Namelen' : { 
     // This column gives you the length of the file name
     },
'Charsleft' :  { 
    // This column gives you the number of chars still available to use in the path + file name
    // Windows imposes a 260 maximum length for the Path+Filename
    },

     
/////// EXAMPLES OF TRICK COLUMNS ////////////////    
// You can delete these if you don't need them
// For explanations, see www.dearopus.com/filename-database.html/filename-database.html#inspectiontrick

// Trick Column, feel free to delete
'modify' : { 
     // This column illustrates how you can display one of the file properties in a column
     pattern: /.*/,
     target: "modify"
     },
// Trick Column, feel free to delete
'3-deep' : { 
     // This column illustrates how you can create a Boolean column without creating a 
     // special if case in the code
     pattern: /^(Y)(?:[^\\]*\\){4}/,
     target: "realpath",
     group: 1,
     subjectPrefix: "Y"
     },
// Trick Column, feel free to delete
'3-deep YN' : { 
     // This variation on the previous column not only displays "Y" if the path is at least   
     // 3-deep, it displays "N" if it isn't
     pattern: /^Y(?=(?:[^\\]*\\){4})|N/,
     target: "realpath",
     subjectPrefix: "YN"
     },
// Trick Column, feel free to delete     
'NumCapsLow' : { 
     // This column shows "num" if a file stem is all numeric, "CAPS" if it is all uppercase, "low" if it is all lowercase
     pattern: /^(num)CAPSlow\d+$|^num(CAPS)low[A-Z]+$|^numCAPS(low)[a-z]+$/,
     subjectPrefix: "numCAPSlow",
     returnTheFirstNonEmptyGroup: true
     },
// Trick Column, feel free to delete     
'pathdepth' : { 
     // This column shows one of three values: "0-2" if a file's path depth is less than 3, "4-5", or "6+"
     pattern: /^0-2(3-5)6\+(?:[^\\]*\\){4,6}[^\\]*$|^0-23-5(6\+)(?:[^\\]*\\){7}|(0-2)/,
     target: "realpath",
     subjectPrefix: "0-23-56+",
     returnTheFirstNonEmptyGroup: true
     }
     
 };
 
 
///////////////////////////////////////////////////////////////
/////         END OF FIELD / COLUMN DEFINITIONS           /////
///////////////////////////////////////////////////////////////



function OnRegexColumn(ColumnData) {
  // OnRegexColumn is an OnScriptColumn method
  // See http://www.gpsoft.com.au/help/opus11/index.html#!Documents/Scripting/OnScriptColumn.htm
  // ColumnData is a ScriptColumnData object
  // See http://www.gpsoft.com.au/help/opus11/index.html#!Documents/Scripting/ScriptColumnData.htm
  var colName = ColumnData.col;
  if(!columns[colName]) return;

   ////////////////////////////////////////////////////////////////
   //// Is the column only restricted to files or to folders?  ////
   //// If so, bail if needed                                  ////                                   
   ////////////////////////////////////////////////////////////////
  var dirOnly = (typeof columns[colName].dirOnly === 'undefined') ? false : columns[colName].dirOnly;
  var fileOnly = (typeof columns[colName].fileOnly === 'undefined') ? false : columns[colName].fileOnly;    
  var haveFileButDirOnly = (dirOnly && ! ColumnData.item.is_dir);
  var haveDirButFileOnly = (fileOnly && ColumnData.item.is_dir);
  if (haveFileButDirOnly || haveDirButFileOnly) {
     // we're not supposed to compute the column for this item: let's bail
     return;
  }

  
  /////////////////////////////////////////////////
  //// First, handle special NON-REGEX Columns ////
  /////////////////////////////////////////////////


  // Is this the filename length column?
  if (colName == 'Namelen') {
    ColumnData.value = ColumnData.item.name.length.toString();
  }

  // Is this the "how many chars available in the filename" column?
  else if (colName == 'Charsleft') {
    var PathLength = new String(ColumnData.item.realpath).length;
    // how many chars available in the path + filename? Max = 260
    ColumnData.value = (260-PathLength).toString();
  }

  /////////////////////////////////////////////////
  ////      Next, handle REGEX Columns         ////
  /////////////////////////////////////////////////

  else { // it's a regex column
    var regexMatch;
    var fileSubject;
    var subject;
    
    // Did we specify a target, or are we matching on the default name_stem?
    if(!columns[colName].target)   {
      fileSubject = ColumnData.item["name_stem"];
     }
    else {
      fileSubject = ColumnData.item[columns[colName].target];
    }

    // Add prefix to the subject if present
    subject = (typeof columns[colName].subjectPrefix === 'undefined') ? fileSubject : columns[colName].subjectPrefix + fileSubject;      
    regexMatch = columns[colName].pattern.exec(subject);

    if (regexMatch != null)    {
      // The general case: we have not set the returnTheFirstNonEmptyGroup property
      if (typeof columns[colName].returnTheFirstNonEmptyGroup === 'undefined') {
         // display the value for the correct capture group
         var capturegroup = (typeof columns[colName].group === 'undefined') ? 0 : columns[colName].group;
         ColumnData.value = regexMatch[capturegroup];
      }
      else if(columns[colName].returnTheFirstNonEmptyGroup) {
      // What is the first non-empty group (apart from zero)?
         for(i = 1; i < regexMatch.length + 1; i++){
            if (regexMatch[i] != '') {
               ColumnData.value = regexMatch[i];
               break;
            }
         }
      }
    }  // regexmatch  
  }  // regex column






  //////////////////////////////////////////////////////
  ////      Optionally, TRANSFORM the value         ////
  //////////////////////////////////////////////////////





////////////////////////////////////////////////////////////////
//      Handle percent, graph, igraph and star values         //
//         - convert value to 0 if it is not numeric          //
//         - scale of 1 for percentage and graphs             //
//         - scale of 5 for stars                             //
////////////////////////////////////////////////////////////////
   var haveType = ! (typeof columns[colName].type === 'undefined') ;
   var haveCup =  ! (typeof columns[colName].fullCupValue === 'undefined') ;
   if ( haveType ) {
      var colType = columns[colName].type;
      
      // Is it graph, igraph, percent or stars?
      if (colType=="graph"||colType=="igraph"||colType=="percent"||colType=="stars") {

        // Not a number? Set to 0
        if (isNaN(ColumnData.value)) {
        ColumnData.value = 0;
        }
        
        // If we have a fullCupValue, convert the numbers
        else if ( haveCup ){
           // Stars? Scale of 5
           if(colType == "stars"  ) {
              ColumnData.value = ColumnData.value * 5 / columns[colName].fullCupValue;
           }
           // Then it must be graph, igraph or percent: scale of 100
           else {
              ColumnData.value = ColumnData.value * 100 / columns[colName].fullCupValue;
           }
        }
      } // relevant type
   } // haveType

   // If we have a fullCupValue but no type: convert to a scale of 100
   // i.e. assume the type is percent, graph or igraph rather than stars 
   else if ( haveCup ) {
     ColumnData.value = ColumnData.value * 100 / columns[colName].fullCupValue;
   }
//////////// End graph, igraph, stars, percent ///////////////// 



// End Transformations








} // OnRegexColumn
 
///////////////////////////////////////////////////////////////////////////////
function OnAboutScript(data){ //v0.1
	var cmd = DOpus.Create.Command();
	if (!cmd.Commandlist('s').exists("ScriptWizard")){
		if (DOpus.Dlg.Request("The 'ScriptWizard' add-in has not been found.\n\n"+
"Install 'ScriptWizard' from [resource.dopus.com].\nThe add-in enables this dialog and also offers "+
"easy updating of scripts and many more.","Yes, take me there!|Cancel", "No About.. ", data.window))
		cmd.RunCommand('http://resource.dopus.com/viewtopic.php?f=35&t=23179');}
	else
		cmd.RunCommand('ScriptWizard ABOUT WIN='+data.window+' FILE="'+Script.File+'"');
}
//MD5 = "525b552d92437c52bbc6c672013f63ab"; DATE = "2015.06.26 - 17:39:03"
3 Likes

I have a small suggestion to your database columns, would you mind changing the Movies_ prefix into Movies.?
The dot . has already been used to separate the prefix from the column name in other scripts, so we'd yield some standard and consistency in the long run.

(Sidenote: I wish for an enhancement on the folder options column-selection dialog. This dialog (and also the filter-editor iirc) does not allow to select columns of a specific script, which is the only reason we need to put some kind of prefix into the columns names. Leo, Jon, reading this? o) )

I wonder, why did you choose _ as separator for the fields?
I guess your weapon of choice to parse these filenames is regex and I guess _ does not really raise any problems (yet?), but a more common character to separate fields like this is ; - from my experience at least. Many people tend to use _ in filenames, don't know if that could lead to parsing errors at some time?

Hi tbone,

I wish for an enhancement on the folder options column-selection dialog. This dialog (and also the filter-editor iirc) does not allow to select columns of a specific script, which is the only reason we need to put some kind of prefix into the columns names.

+1, I've been wishing for the same.

A picture to explain what we're talking about here, all the Script columns are mixed together. That's why we use a prefix:


Contrast with the column picker (easier to use because Script columns are grouped according to their script):


Sure! One question before doing that, if I don't feel like going from 0.9.1 to 0.9.2, where do I go from there to make sure the sequence works with ScriptWizard? 0.9.1.1 or 0.9.10? (Or is 0.9.10 after 0.9.9?)

Maybe just go for 0.9.2 to prevent any issues (version comparison has been enhanced, but that SW is not released yet o).
Thanks for doing the prefix-issue demonstration and glad you agree on the "dot"! o))

  • Okay, done this for the three scripts.
  • In 0.9.1 I had added three properties (fileOnly, dirOnly, fullCupValue), if you or anyone else thinks of other useful ones please let me know.
  • Explained that the Movie button toggles full row selection (had forgotten to mention that but your mention of full row reminded me)
  • Added the button to toggle Book+Comics mode, had forgotten to do that

Hey I've been messing around with your script for the past two days and its amazing, really.
I can see it being the solution for a number of needs that I have within Opus.

I have a question though, the character _ is reserved as a separator by your script between two keys. I really need to use this character for column values.

Is there any chance to change this and use another character as its replacement? I really wish I knew RegEX!

Thanks allot for any help!

Hey there, really pleased that you're enjoying the script.
Yes you can use something else, on my current version I use space as a separator.
Here you go, move that to your /scripts folder. You might need to remove the txt extension, not sure.
With this version lots of fields don't need the something=something syntax, you can have
Movie Name [2010 tt45526 7.5

Also attaching a button that lets you press Ctrl+I when you're on a movie where the imdb tt tag has been filled to launch imdb for that movie.

Launch imdb (first file).dcf (1.8 KB)

MovieFilenameDB.js.txt (40.8 KB)

1 Like

playfull that is very kind of you. much appreciated!
I decided to take your advice and learn RegEx properly, its insane the amount one can leverage with it.

Thanks allot indeed

How can I change it so it's searching for the title itself, not the imdb code?

For example: A.simple.movie.title.2024
So it searches for everything including the year?

Played with Copilot which gave me this script

function LaunchUrl( data, firstFileOnly){
  var cmd = data.func.command
  var tab = data.func.sourcetab
  var title_pattern = /^([^.]+\.)+[12]\d{3}/;
  var year_pattern = /[12]\d{3}/;
  cmd.ClearFiles();
  for (var iEnum = new Enumerator(tab.selected); !iEnum.atEnd(); iEnum.moveNext()){
      var file = iEnum.item();
      var fileName = new String(file.name_stem);
      var title_match = title_pattern.exec(fileName);
      if (title_match != null) {
         var title = title_match[0].replace(year_pattern, '').replace(/\./g, ' ').trim();
         var year_match = year_pattern.exec(fileName)
         var url = "https://www.google.com/search?q=site:imdb.com%%20" + title.replace(/ /g,"-");
         if (year_match != null) {
            url = url + "-" + year_match[0];
         }
         cmd.RunCommand(url);
      }
      if (firstFileOnly) break;
  }
}

The problem is, this line throws an error in Opus:

      var title = title_match[0].replace(year_pattern, '').replace(/\./g, ' ').trim();```

trim() is not supported.

Thanks @lxp

I asked Copilot to create a script for Directory Opus and it created this one which really works quite well now. I'm blown away by AI.

function OnClick(data) {
  LaunchUrl(data, true);
}

function LaunchUrl(data, firstFileOnly) {
  var cmd = data.func.command;
  var tab = data.func.sourcetab;
  var title_pattern = /^(.*?)(?=\.\d{4})/;
  var year_pattern = /\b\d{4}\b/;
  cmd.ClearFiles();
  
  for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {
    var file = e.item();
    var fileName = String(file.name_stem);
    var title_match = title_pattern.exec(fileName);
    var year_match = year_pattern.exec(fileName);
    
    if (title_match != null && year_match != null) {
      var title = title_match[0].replace(/\./g, ' ');
      var year = year_match[0];
      var url = "https://www.google.com/search?q=site:imdb.com%%20" + title.replace(/ /g,"-") + "-" + year;
      cmd.RunCommand('\"' + url + '\"');
    }
    
    if (firstFileOnly) break;
  }
}

Yes, AI can create a framework of seemingly nice program structure, but it is not likely to improve on the logic of the requestor. And it often suffers from hallucinations with successive iterations of back and forth with the requestor. It merely mimics intelligence by being able to regurgitate samples from its vast database of information. As always, your mileage may vary.

Dave

Better script

function OnClick(clickData) {
    var cmd = clickData.func.command;
    cmd.deselect = false; // Prevent automatic deselection
    cmd.ClearFiles(); // Clear the selected files

    var tab = clickData.func.sourcetab;
    var title_pattern = /^(.*?)(?=\.\d{4})/;

    for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {
        var file = e.item();
        var fileName = String(file.name_stem);
        var title_match = title_pattern.exec(fileName);

        if (title_match != null) {
            var title = title_match[0].replace(/\./g, ' ');
            var url = "https://www.imdb.com/find?q=" + title;
            cmd.RunCommand('\"' + url + '\"');
        }
    }
}