/////////////////////////////////////////////////////////////// // 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.3"; 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; if (typeof column.type != 'undefined') cmd.type = 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 // Separators for MovieFilenameDB: currently, spaces only. // To change the separator, replace these two patterns: [ ] and ((?:[^\] ]| (?![ \]]|[a-z]+=))+) /* The regex after the equal sign: ((?:[^\] ]| (?![ \]]|[a-z]+=))+) The goal is to use SPACE as the delimiter, while allowing spaces in "Luc Besson", so we have to discriminate when it is NOT a delimiter. ( # start capture group 1 (?: ... )+ # match one or more of these: [^\] ] # one character that is NOT A SPACE | # OR A SPACE... (?! ... ) # that is not followed by... [ \]] # a space or a closing square bracket |[a-z]+= # OR the start of a field, e.g. tt= */ '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)?=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/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=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1 }, 'Camera' : { // Cinematographer e.g. Robby Muller // acceptable aliases for key: cam, camera, cin pattern: /\[(?:[^\]]+[ ])?c(?:am(?:era)?|in)=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/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)?=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1 }, 'Director' : { // Who directed it? // acceptable aliases for key: dir, director pattern: /\[(?:[^\]]+[ ])?dir(?:ector)?=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1, width: 15 }, 'Female_Lead' : { // Who is the male lead? // acceptable aliases for key: fem, muj pattern: /\[(?:[^\]]+[ ])?(?:fem|muj)=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1, width: 15 }, 'IR' : { // imdb rating, e.g. 7.5 // acceptable aliases for key: ir pattern: /\[(?:[^\]]+[ ])?(?:ir=)?(\d\.\d\b)/i, // 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 }, 'Male_Lead' : { // Who is the male lead? // acceptable aliases for key: mal, hom pattern: /\[(?:[^\]]+[ ])?(?:mal|hom)=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1, width: 15 }, 'Min' : { // Duration, e.g. 120 // acceptable aliases for key: min, dur, duration pattern: /\[(?:[^\]]+[ ])?(?:(?:min|dur(?:ation)?)=)?(\d{1,3}\b(?!\.\d))/i, // 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?=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1 }, 'Topic' : { // What is the topic? // acceptable aliases for key: top, wht pattern: /\[(?:[^\]]+[ ])?(?:top|wht)=((?:[^\]\d ]|\d(?!\d{3}\b)| (?![ \]]|[a-z]+=))+)/i, group: 1, width: 15 }, 'TT' : { // imdb code, e.g. tt0478331 // acceptable aliases for key: tt, OR JUST WRITE THE TAG pattern: /\[(?:[^\]]+[ ])?(?:tt=)?(tt\d+)/i, group: 1, width: 2 }, 'Year' : { // What year was it released? // acceptable aliases for key: y, yr, year, OR JUST WRITE THE YEAR pattern: /\[(?:[^\]]+[ ])?(?:y(?:(?:ea)?r)?=)?([12]\d{3}\b)/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"