function OnInit(initData) { DOpus.ClearOutput Log("0001000 OnInit Enter", true); initData.name = "Command.SelectByDate"; initData.version = "1.31 (2021.10.30)"; initData.copyright = "(c) 2021 Felix"; initData.url = "https://resource.dopus.com/t/command-select-bydate-dynamic-command-to-select-files-by-various-dates-and-parameters/39697"; initData.desc = "Selecting files by date"; initData.default_enable = true; initData.min_version = "12.0"; initData.group = "Command"; var cmd = initData.AddCommand(); cmd.name = "SelectByDate"; cmd.method = "OnSelectByDate"; cmd.desc = "Selecting files by date"; cmd.label = "SelectByDate"; //https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Argument_Types.htm/S //https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Internal_Command_Arguments.htm //cmd.template = "DATESOURCE/K[access,create,modify,doccreateddate,docedittime,doclastsaveddate,datedigitized,datetaken,recordingtime,releasedate,mp3year],ONLYFROMSELECTEDFILES/S"; cmd.template = "DATESOURCE/K[access,create,modify,doccreateddate,docedittime,doclastsaveddate,datedigitized,datetaken,recordingtime,releasedate],ONLYFROMSELECTEDITEMS/S,DEFAULTSELECTOR/K[matchingselector,bydate,bydaterange,bydatetimerange],ITEMTYPE/K[all,files,folders]"; cmd.hide = false; cmd.icon = "setdate"; Log("0009010 OnInit Exit", true); } //Command entrypoint function OnSelectByDate(scriptCmdData) { Log(" 0002000 OnSelectByDate Enter", true); var source = scriptCmdData.func.sourcetab; var args = scriptCmdData.func.args; var dateSource = null; var defaultSelector = args.got_arg.DEFAULTSELECTOR ? args.DEFAULTSELECTOR.toLowerCase() : null; var defaultItemType = args.got_arg.ITEMTYPE ? args.ITEMTYPE.toLowerCase() : null; var selectOnlyFromSelectedItems = args.got_arg.ONLYFROMSELECTEDITEMS ? true : null; //not pretty but used for dialog if(!args.got_arg.DATESOURCE) { Log(" 0002010 !args.got_arg.DATESOURCE call ShowSourceDateSelectionDialog", true); var result = ShowSourceDateSelectionDialog(scriptCmdData, selectOnlyFromSelectedItems, defaultSelector, defaultItemType); if(!result) return; dateSource = result.dateSource; selectOnlyFromSelectedItems = result.selectOnlyFromSelectedItems; defaultSelector = result.defaultSelector; defaultItemType = result.defaultItemType; } else dateSource = args.DATESOURCE; if(selectOnlyFromSelectedItems == null) selectOnlyFromSelectedItems = false; if(defaultItemType == null) defaultItemType = "all"; Log(" 0002020 call RunSelectByDateCommand", true); RunSelectByDateCommand(scriptCmdData, source, dateSource, defaultItemType, selectOnlyFromSelectedItems, defaultSelector, defaultItemType); Log(" 0002090 OnSelectByDate Exit", true); } //Dialog where to choose source date, default selector and if select only from selected files function ShowSourceDateSelectionDialog(scriptCmdData, selectOnlyFromSelectedItems, defaultSelector, defaultItemType) { Log(" 0003000 ShowSourceDateSelectionDialog Enter", true); var tab = scriptCmdData.func.sourcetab; var dlg = DOpus.Dlg; dlg.window = tab; dlg.template = "DateSourceSelectionDialog"; dlg.detach = false; dlg.Create(); var itemTypes = ["all", "files", "folders"]; var comboSourceDate = dlg.Control("comboSourceDate"); var comboItemType = dlg.Control("comboItemType"); var comboDefaultSelector = dlg.Control("comboDefaultSelector"); var checkOnlySelectedItems = dlg.Control("checkOnlySelectedItems"); comboSourceDate.value = GetDefaultDate(); comboItemType.value = GetDefaultItemType(defaultItemType); comboDefaultSelector.value = GetDefaultSelector(defaultSelector); checkOnlySelectedItems.value = GetOnlyFromSelectedValue(selectOnlyFromSelectedItems); var items = MapItemType(tab, itemTypes[comboItemType.value], true); //always true because here we only want to know count of selected items var count = items ? items.count : 0; checkOnlySelectedItems.label = "Select only from selected " + MapItemTypeToString(itemTypes[comboItemType.value]) + " (" + count + ")"; dlg.Show(); while (true) { var msg = dlg.GetMsg(); if (!msg.result) break; if(msg.event == "selchange" && msg.control == "comboItemType" || msg.event == "click" && msg.control == "checkOnlySelectedItems") { var items = MapItemType(tab, itemTypes[comboItemType.value], true);//always true because here we only want to know count of selected items var count = items ? items.count : 0; checkOnlySelectedItems.label = "Select only from selected " + MapItemTypeToString(itemTypes[comboItemType.value]) + " (" + count + ")"; } } var result = dlg.result; // Int Maybe 0=Ok 1=Cancel etc Button to close the dialog if(result == 1) //ok { var selectedDateSourceIndex = comboSourceDate.value; var selectedItemTypeIndex = comboItemType.value; var selectedDefaultSelectorIndex = comboDefaultSelector.value; var selectOnlyFromSelectedItems = checkOnlySelectedItems.value; Script.vars.Set(LAST_PICKED_DATESOURCE, selectedDateSourceIndex); Script.vars.Set(LAST_PICKED_DEFAULTSELECTOR, selectedDefaultSelectorIndex); Script.vars.Set(LAST_PICKED_ITEM_TYPE, selectedItemTypeIndex); Script.vars.Set(LAST_USED_ONLYFROMSELECTEDITEMS_VALUE, selectOnlyFromSelectedItems); var dateSource = ["access", "create", "modify", "doccreateddate", "docedittime", "doclastsaveddate", "datedigitized", "datetaken", "recordingtime", "releasedate", "mp3year"][selectedDateSourceIndex]; defaultItemType = itemTypes[selectedItemTypeIndex]; defaultSelector = ["matchingselector","bydate","bydaterange","bydatetimerange"][selectedDefaultSelectorIndex]; Log(" 0003010 ShowSourceDateSelectionDialog result = 1 Exit", true); return { dateSource : dateSource, selectOnlyFromSelectedItems : selectOnlyFromSelectedItems, defaultSelector : defaultSelector, defaultItemType : defaultItemType}; } else if(result == 0) //cancel { Log(" 0003020 ShowSourceDateSelectionDialog result = 0 Exit", true); return null; } } var LAST_PICKED_DATESOURCE = "LastPickedDateSource"; var LAST_PICKED_DEFAULTSELECTOR = "LastPickedDefaultSelector"; var LAST_PICKED_ITEM_TYPE = "LastPickedItemType"; var LAST_USED_ONLYFROMSELECTEDITEMS_VALUE = "LastUsedOnlyFromSelectedItemsValue"; //Returns index for datesource which was picked last function GetDefaultDate() { if(Script.vars.Exists(LAST_PICKED_DATESOURCE)) return Script.vars.Get(LAST_PICKED_DATESOURCE); return 1; } //Get which selector to be default, if not specified get from settings else default value (by date) function GetDefaultSelector(defaultSelector) { if(defaultSelector) { var selectors = ["matchingselector","bydate","bydaterange","bydatetimerange"]; for(var i = 0; i < selectors.length; i++) if(selectors[i] == defaultSelector) return i; } if(Script.vars.Exists(LAST_PICKED_DEFAULTSELECTOR)) return Script.vars.Get(LAST_PICKED_DEFAULTSELECTOR); return 1; } //Select between all items, files onyl, folders only function GetDefaultItemType(defaultItemType) { if(defaultItemType) { var itemTypes = ["all", "files", "folders"]; for(var i = 0; i < itemTypes.length; i++) if(itemTypes[i] == defaultItemType) return i; } if(Script.vars.Exists(LAST_PICKED_ITEM_TYPE)) return Script.vars.Get(LAST_PICKED_ITEM_TYPE); return 0; } //Map to a readable string function MapItemTypeToString(itemType) { if(itemType == null || itemType == "all") return "items"; else return itemType; } //return items depending on itemtype and selectOnlyFromSelectedItems function MapItemType(tab, itemType, selectOnlyFromSelectedItems) { Log(itemType + " " + selectOnlyFromSelectedItems); if(itemType == "all") { if(selectOnlyFromSelectedItems) return tab.selected; else return tab.all; } else if(itemType == "files") { if(selectOnlyFromSelectedItems) return tab.selected_files; else return tab.files; } else if(itemType == "folders") { if(selectOnlyFromSelectedItems) return tab.selected_dirs; else return tab.dirs; } return null; } //Get if use the ONLYFROMSELECTEDFILES param either from args, settings or default value function GetOnlyFromSelectedValue(selectOnlyFromSelectedItems) { if(selectOnlyFromSelectedItems) //could be null return true; if(Script.vars.Exists(LAST_USED_ONLYFROMSELECTEDITEMS_VALUE)) return Script.vars.Get(LAST_USED_ONLYFROMSELECTEDITEMS_VALUE); return false; } //Actual functionality function RunSelectByDateCommand(scriptCmdData, tab, dateSource, itemType, selectOnlyFromSelectedItems, defaultSelector) { Log(" 0004000 RunSelectByDateCommand Enter", true); var cmd = scriptCmdData.func.command; var progress = scriptCmdData.func.command.progress; progress.abort = progress.pause = true; var dateSelectorFunction = CreateSourceDateSelector(dateSource); var result = ShowSelectionDetailsDialog(tab, dateSelectorFunction, dateSource, progress, itemType, selectOnlyFromSelectedItems, defaultSelector); if(!result) return; progress.abort = progress.pause = false; progress.Restart(); var filesToSelect = SelectFiles(tab, result.selectorFunction, result.cachedDates, result.fileCount, progress); if(filesToSelect) { cmd.SetFiles(filesToSelect); cmd.RunCommand("Select FROMSCRIPT EXACT MAKEVISIBLE SETFOCUS"); } Log(" 0004090 RunSelectByDateCommand Exit", true); } //Display a dialog that shows the date ranges / selection options function ShowSelectionDetailsDialog(tab, dateSelectorFunction, dateSource, progress, itemType, selectOnlyFromSelectedItems, defaultSelector) { Log(" 0010000 ShowSelectionDetailsDialog Enter", true); var fileQueryResult = QueryFileDates(tab, dateSelectorFunction, dateSource, progress, itemType, selectOnlyFromSelectedItems); if(!fileQueryResult) return null; var dlg = DOpus.Dlg; dlg.window = tab; if(fileQueryResult.validFileCount == 0) { dlg.message = "No files found in \"" + tab.path + "\" with '" + dateSource + "' property."; dlg.buttons = "OK"; dlg.title = "No files found"; dlg.Show(); return null; } dlg.template = "SelectionDetailsDialog"; dlg.detach = true; dlg.title = "How should the files be selected by '" + dateSource + "' date selector"; dlg.Create(); var comboDate = dlg.Control("comboDate"); var comboDateStart = dlg.Control("comboDateStart"); var comboDateEnd = dlg.Control("comboDateEnd"); var comboDateTimeStart = dlg.Control("comboDateTimeStart"); var comboDateTimeEnd = dlg.Control("comboDateTimeEnd"); var radioAllItemsMatching = dlg.Control("radioAllItemsMatching"); var radioDate = dlg.Control("radioDate"); var radioDateRange = dlg.Control("radioDateRange"); var radioDateTimeRange = dlg.Control("radioDateTimeRange"); var radiosDateSelectors = { "matchingselector" : radioAllItemsMatching, "bydate" : radioDate, "bydaterange" : radioDateRange, "bydatetimerange" : radioDateTimeRange }; if(defaultSelector) radiosDateSelectors[defaultSelector].value = true; for(var i = 0; i < fileQueryResult.dates.length; i++) { var item = fileQueryResult.dates[i]; comboDate.AddItem(item); comboDateStart.AddItem(item); comboDateEnd.AddItem(item); } for(var i = 0; i < fileQueryResult.dateTimes.length; i++) { var item = fileQueryResult.dateTimes[i]; comboDateTimeStart.AddItem(item); comboDateTimeEnd.AddItem(item); } Log(" 0010000 ShowSelectionDetailsDialog Line 315", true); radioAllItemsMatching.title = "All items matching '" + dateSource + "' date selector (" + fileQueryResult.validFileCount + ")"; Log(" 0010000 ShowSelectionDetailsDialog Line 317", true); comboDate.value = comboDateStart.value = comboDateTimeStart.value = 0; comboDateEnd.value = fileQueryResult.dates.length > 1 ? 1 : 0; comboDateTimeEnd.value = fileQueryResult.dateTimes.length > 1 ? 1 : 0; dlg.Show(); while (true) { var msg = dlg.GetMsg(); if (!msg.result) break; //Log("Msg Event = " + msg.event + " by " + msg.control); if (msg.event == "click") { if(msg.control == "buttonOK") { if(radioAllItemsMatching.value) { var selectorFunction = function(date) { //Log("Selector function: Contains datesource"); return dateSelectorFunction(date) != null; } return {selectorFunction : selectorFunction, fileCount : fileQueryResult.validFileCount, cachedDates : fileQueryResult.cachedDates }; } else if(radioDate.value) { var selectorFunction = function(date) { if(date) { //Log("Selector function: Date " + date.Format("D#yyyy.MM.dd") + " == " + fileQueryResult.dates[comboDate.value]); return date.Format("D#yyyy.MM.dd") == fileQueryResult.dates[comboDate.value]; } return false; } return {selectorFunction : selectorFunction, fileCount : fileQueryResult.validFileCount, cachedDates : fileQueryResult.cachedDates }; } else if(radioDateRange.value) { var startDate = fileQueryResult.dates[comboDateStart.value]; var endDate = fileQueryResult.dates[comboDateEnd.value]; if(endDate < startDate) { var tmp = startDate; startDate = endDate; endDate = tmp; } var selectorFunction = function(date) { if(date) { //Log("Selector function: Date range " + startDate + " <= " + date.Format("D#yyyy.MM.dd") + " && " + date.Format("D#yyyy.MM.dd") + " <= " + endDate); var itemDate = date.Format("D#yyyy.MM.dd"); return startDate <= itemDate && itemDate <= endDate; } return false; } return {selectorFunction : selectorFunction, fileCount : fileQueryResult.validFileCount, cachedDates : fileQueryResult.cachedDates }; } else if(radioDateTimeRange.value) { var startDateTime = fileQueryResult.dateTimes[comboDateTimeStart.value]; var endDateTime = fileQueryResult.dateTimes[comboDateTimeEnd.value]; if(endDateTime < startDateTime) { var tmp = startDateTime; startDateTime = endDateTime; endDateTime = tmp; } var selectorFunction = function(date) { if(date) { //Log("Selector function: Date time range " + startDateTime + " <= " + date.Format("D#yyyy.MM.dd T#HH:mm:ss") + " && " + date.Format("D#yyyy.MM.dd T#HH:mm:ss") + " <= " + endDateTime); var itemDate = date.Format("D#yyyy.MM.dd T#HH:mm:ss"); return startDateTime <= itemDate && itemDate <= endDateTime; } return false; } return {selectorFunction : selectorFunction, fileCount : fileQueryResult.validFileCount, cachedDates : fileQueryResult.cachedDates }; } } } else if(msg.event == "selchange") { if(msg.control == "comboDate") { radioDate.value = true; } if(msg.control == "comboDateStart") { radioDateRange.value = true; if(comboDateStart.value >= comboDateEnd.value) if(comboDateEnd.value < fileQueryResult.dates.length - 1)//there are enough items in the list comboDateEnd.SelectItem(comboDateStart.value + 1); } else if(msg.control == "comboDateEnd") { radioDateRange.value = true; if(comboDateStart.value >= comboDateEnd.value) if(comboDateStart.value > 1) comboDateStart.SelectItem(comboDateEnd.value - 1); } else if(msg.control == "comboDateTimeStart") { radioDateTimeRange.value = true; if(comboDateTimeStart.value >= comboDateTimeEnd.value) if(comboDateTimeEnd.value < fileQueryResult.dateTimes.length - 1)//there are enough items in the list comboDateTimeEnd.SelectItem(comboDateTimeStart.value + 1); } else if(msg.control == "comboDateTimeEnd") { radioDateTimeRange.value = true; if(comboDateTimeStart.value >= comboDateTimeEnd.value) if(comboDateTimeStart.value > 1) comboDateTimeStart.SelectItem(comboDateTimeEnd.value - 1); } } } return null; Log(" 0010010 ShowSelectionDetailsDialog Exit", true); } //Create and return a function that selects the desired date according to the params of the command function CreateSourceDateSelector(arg) { var dateSelector = function(item) //default is create { return item.create; }; if(arg) { arg = arg.toLowerCase(); if(arg == "access") dateSelector = function(item) { return item.access; }; else if(arg == "modify") dateSelector = function(item) { return item.modify; }; else if(arg == "doccreateddate") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "doc") return item.metadata.doc.doccreateddate; } return null; }; else if(arg == "docedittime") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "doc") return item.metadata.doc.docedittime; } return null; }; else if(arg == "doclastsaveddate") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "doc") return item.metadata.doc.doclastsaveddate; } return null; }; else if(arg == "datedigitized") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "image") return item.metadata.image.datedigitized; } return null; }; else if(arg == "datetaken") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "image") return item.metadata.image.datetaken; } return null; }; else if(arg == "recordingtime") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "video") return item.metadata.video.recordingtime; } return null; }; else if(arg == "releasedate") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "audio") return item.metadata.audio.releasedate; } return null; }; /* else if(arg == "mp3year") dateSelector = function(item) { if(item.metadata) { if(item.metadata == "audio") return item.metadata.audio.mp3year; //this brings problems as it is a number, not a date } return null; }; */ } return dateSelector; } //Enumerate the dates in a specified tab function QueryFileDates(tab, dateSelector, dateSource, progress, itemType, selectOnlyFromSelectedItems) { var path = tab.path; var minDate = DOpus.Create.Date(); var maxDate = DOpus.Create.Date(); var dates = []; var dateTimes = []; var cachedDates = {}; var items = MapItemType(tab, itemType, selectOnlyFromSelectedItems); if(!items) { Log("No items mappable", true); return; } if(selectOnlyFromSelectedItems && items.count == 0) { var dlg = DOpus.Dlg; dlg.window = tab; dlg.buttons = "Yes|Cancel"; dlg.title = "No items in selection"; dlg.message = "Select.ByDate was started with the \"ONLYFROMSELECTEDITEMS\" option but there are no selected items. Select from all items instead?"; var result = dlg.Show(); if(result == 1) { items = MapItemType(tab, itemType, false); } else return null; } progress.Init(tab, "Querying date information in '" + tab.path + "'"); progress.SetStatus("Querying 0/" + items.count + " items"); progress.SetFiles(items.count); DOpus.Delay(200); progress.Show(); var processedFilesCount = 0; var validFileCount = 0; var fileEnum = new Enumerator(items); while (!fileEnum.atEnd()) { var abortState = progress.GetAbortState(); if (abortState == "a") { return null; } else if (abortState == "p") { DOpus.Delay(500); continue; } var item = fileEnum.item(); var date = dateSelector(item); if(date) { if(maxDate < date) maxDate = date; else if(date < minDate) minDate = date; var datePart = date.Format("D#yyyy.MM.dd") if(!ArrayIncludes(dates, datePart)) dates.push(datePart); var dateTime = date.Format("D#yyyy.MM.dd T#HH:mm:ss"); if(!ArrayIncludes(dateTimes, dateTime)) dateTimes.push(dateTime); cachedDates[item] = date; validFileCount++; } fileEnum.moveNext(); progress.SetStatus("Querying " + ++processedFilesCount + "/" + items.count + " items (" + validFileCount + " items with '" + dateSource + "')"); progress.SetFilesProgress(processedFilesCount); } DOpus.Delay(800);//progress Bug workaround progress.Hide(); dates = dates.sort(); dateTimes = dateTimes.sort(); return { minDate: minDate, maxDate: maxDate, dates: dates, dateTimes: dateTimes, validFileCount: validFileCount, cachedDates : cachedDates }; } //Select files in source function SelectFiles(tab, selectorFunction, cachedDates, fileCount, progress) { var selectedFilesResultVector = DOpus.Create.Vector(); progress.SetStatus("Selecting 0/" + fileCount + " files"); progress.SetFiles(fileCount); DOpus.Delay(200); progress.Show(); var processedFilesCount = 0; for(var file in cachedDates) { var date = cachedDates[file]; if(selectorFunction(date)) { selectedFilesResultVector.push_back(file); } progress.SetStatus("Selecting " + processedFilesCount + "/" + fileCount + " files"); progress.SetFilesProgress(processedFilesCount++); } progress.Hide(); return selectedFilesResultVector; } function ArrayIncludes(array, item) { for(var i = 0; i < array.length; i++) if(array[i] == item) return true; return false; } function Log(msg, e) { DOpus.output(String(msg), e || false); } // //maybe in a next release ==SCRIPT RESOURCES