// DOpus Addin: ColEpisodes //Requires Directory Opus 11.8 or higher //As usual, no guarantees and so on, but it works for me. // //Columns: // NoBrackets: Filename without prefixing brackets // // HighestNumber: Display a folder's highest prefixing number. // In other words, if you have the files 01.txt,02.txt,03.txt then the column would // display 03 for that folder. // // If recursive is true, check in subfolders too. // Files are excluded from consideration if they match one of the filespecs in exclusionFilter. // // FilteredName: Filename filtered according to regexFilters // Each regex/JSON line operates on the result of the previous. // Operates on filename including its extension. // // Common: // Can use {flags:options} at the beginning of a line to set // regex flags. Valid 'options' are: g, i and m. They can be combined. // If you write {flags:} it disables default flags, making it replace only // the first casesensitive match. // Default flags: i (caseinsensitive) // // Can use regex comments inside the regexes, in other words these: (?# text here) // A line can be prefixed by :: to comment the entire line. // // Regular Expressions: // Write regexes like you normally would, one per line. // All matched text will be removed. // JSON: // If the line, after removing {flags:} and regex comments, contains " as its first // character, treat the rest of the LINE as json (no need for {}). // You can specify a replacement text (allows $0..$n, and all the others). // // All backslashes (this:\) must be doubled for JSON. // In other words, like this: // Literal backslash: \\\\ // Quote: \\\" // \s\w = \\s\\w. // // JSON Properties: // regex = regular expression // replace = text to replace with (default: remove matched text) // flags = regex flags (default: i). Tries to use {flags:} when unavailable. // // This is how a JSON line should look (only the regex property is required): // "regex":"yourregexhere","replace":"yourreplacementhere","flags":"yourflagshere" // "regex":"yourregexhere","replace":"yourreplacementhere" // "regex":"yourregexhere" //Examples: //(?# Remove initial brackets)^(?:*\]+\]*)+ //(?# Remove CRC)\s*{8}(?:?$|)_}-]) //(?# Place The at the end, but before extension. Use JSON)"regex":"^(The)\\s+(.*?)(\\.+|)$","replace":"$2, $1$3" // //(?# You can't use the ending parenthesis inside regex comments) //:: This is a commented line (:: is only special when they are the two first characters in a line) //(?# Disable default flags){flags:}Match once, casesensitive. // // //I'd appreciate comments, eventual improvements and so on. ///// LOGGING // If true, turn on logging. var gbUseLogging=false; // If enabled, outputs verbose logging. var gbUseVerboseLogging=false; // ----------------------------------------------------------------- var gvExclusionFilter; // Global array for caching regex filters. var gaRegexFilters; // Write text to output if gbUseLogging is true. // If verbose is true, only write if also gbUseVerboseLogging is true. function Log(s,verbose){ if (gbUseLogging){ if ((!verbose)||(gbUseVerboseLogging && verbose)){ DOpus.Output(s); } } } function LogError(s){ DOpus.Output(s); } function OnInit(initData){ initData.name = "ColEpisodes"; initData.desc = "Add columns related to episodes/tracks/filtering."; initData.copyright = "myarmor"; initData.version="0.1"; initData.min_version="11.8"; initData.default_enable=true; initData.config.exclusionFilter=DOpus.Create.Vector('*Bookmark.txt'); initData.config.recursive=false; initData.config.regexFilters=DOpus.Create.Vector('(?# Remove initial brackets)^(?:[\\s_-]*\\[[^\\]]+\\][\\s_-]*)+','(?# Remove CRC)\s*[[_({-][0-9A-F]{8}(?:[_-]?$|[\\])_}-])'); initData.config.useLogging=false; initData.config.useVerboseLogging=false; initData.config_desc=DOpus.Create.Map( 'exclusionFilter','Filespecs to exclude when determining highest number', 'recursive', 'Determine highest number based on files in subfolders too', 'regexFilters','Regular Expressions for Filtered Name. Use {flags:opt} in front of a line to set regex flags (default: i). One regex per line.', 'useLogging','Enable logging to script output', 'useVerboseLogging','Enable verbose logging (useLogging must also be enabled)' ); } function OnAddColumns(addColData){ var col; col=addColData.AddColumn(); col.name = 'HighestNumber'; col.label = 'Highest Number'; col.method = "OnHighestNumber"; col.autogroup= true; col.namerefresh=true; col.justify = "right"; col.nogroup=true; col=addColData.AddColumn(); col.name = 'NoBrackets'; col.label = 'No Brackets'; col.method = "OnNoBrackets"; col.autogroup= true; col.namerefresh=true; col.justify = "left"; col=addColData.AddColumn(); col.name = 'FilteredName'; col.label = 'Filtered Name'; col.method = "OnFilteredName"; col.autogroup= true; col.namerefresh=true; col.justify = "left"; } function isAllowed(item){ if (!gvExclusionFilter){ return true; } var len; var objWild=DOpus.FSutil.NewWild(); len=gvExclusionFilter.count; if (!len){ return true; } for (var i=0;imaxNum){ maxNum=curNum; } } } } folderEnum.Close(); } return maxNum; } function RemoveBrackets(filename){ var name; var ext; var re; var fnamere=/^([^\\\/]*)(\.[^\.]+)$/; // Split filename into name and extension if (filename.search(fnamere)>=0){ name=RegExp.$1; ext=RegExp.$2; } else{ name=filename; ext=''; } if (name!=''){ name=name.replace(/^(?:[\s_-]*\[[^\]]+\][\s_-]*)+/gi,""); if (ext!=''){ return name+ext; } else{ return name; } } return filename; } function PrintError(e,pos){ var msg; if (e instanceof Error){ switch(e.name){ case "SyntaxError": msg='JSON: '+e.description;//+' ('+(e.number & 0xFFFF)+')'; break; case "RegExpError": msg='Regex: '+e.description;//+' ('+(e.number & 0xFFFF)+')'; break; } } else { msg=e.replace('SyntaxError: ','JSON:'); msg=msg.replace('RegExpError: ','Regex:'); } DOpus.Output('ERROR: regexFilters line '+(pos+1)+': '+msg); } // Make a search and replace object // Returns null if 's' don't contain an actual regex after removing // comments and flags. Otherwise return an object containing: // re = regex object. // replace = replacetext (default: "") function MakeSR(s,defaultopt){ var reflags; var bHasReFlags=false; var regex; var replwith=''; // If line begins with :: we should ignore it. if ((s.length>=2)&&(s[0]==':')&&(s[1]==':')){ return null; } regex=s.replace(/\(\?#[^)]*\)/g,''); regex=regex.replace(/^{flags:([gim]*)}/ig, function (match,theflags){ reflags=theflags; bHasReFlags=true; return ''; }); if (regex!==''){ if (regex.charAt(0)=='"'){ var rejson=JSON.parse('{'+regex+'}'); if (gbUseVerboseLogging){ var bHasItems=false; Log(' JSON result: '+JSON.stringify(rejson)); if (typeof rejson.regex!=='undefined'){ Log(' regex:'+rejson.regex,true); } if (typeof rejson.replace!=='undefined'){ Log(' replace:'+rejson.replace,true); } else { Log(' replace: Remove matched text'); } if (typeof rejson.flags!=='undefined'){ Log(' flags:'+rejson.flags,true); } else { if (typeof reflags==='undefined'){ Log(' flags: Use default flags'); } else { Log(' flags: Use flags from {flags:'+reflags+'}'); } } } regex=rejson.regex; if (typeof rejson.flags!=='undefined'){ reflags=rejson.flags; } else if (bHasReFlags===false){ if (typeof defaultopt==='undefined'){ reflags='ig'; } else { reflags=defaultopt; } } if (typeof rejson.replace!=='undefined'){ replwith=rejson.replace; } } else { if (bHasReFlags===false){ if (typeof defaultopt==='undefined'){ reflags='ig'; } else { reflags=defaultopt; } } } return {re:new RegExp(regex,reflags),replace:replwith}; } return null; } // Build the replacement filters. function MakeReplaceFilters(){ var regexFilters=Script.config.regexFilters; var curRegex; var sr; var bIsOk=true; if ((typeof regexFilters!=='undefined') && (regexFilters.length>0)){ Log('MakeReplaceFilters: Creating replacement filters.',true); gaRegexFilters=[]; for (var i=0;i0){ if (gbUseVerboseLogging){ bHasLogged=false; } for (var i=0;i=0){ scriptColData.value=((maxNum<10)?'0':'')+maxNum; scriptColData.sort=maxNum; } else { scriptColData.sort=-1; } } } function OnNoBrackets(scriptColData){ if (scriptColData.col!="NoBrackets"){ return; } gbUseLogging=Script.config.useLogging; gbUseVerboseLogging=Script.config.useVerboseLogging; scriptColData.value=RemoveBrackets(scriptColData.item.name); } function OnFilteredName(scriptColData){ if (scriptColData.col!="FilteredName"){ return; } gbUseLogging=Script.config.useLogging; gbUseVerboseLogging=Script.config.useVerboseLogging; scriptColData.value=FilterName(scriptColData.item.name); }