diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua new file mode 100644 index 0000000..2a1bd24 --- /dev/null +++ b/contrib/AutoGrouper.lua @@ -0,0 +1,155 @@ +--[[AutoGrouper plugin for darktable + + copyright (c) 2019 Kevin Ertel + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this Plugin +This plugin adds the module "Auto Group" to darktable's lighttable view + +----REQUIRED SOFTWARE---- +None + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Set a gap amount in second which will be used to determine when images should no +longer be added to a group. If an image is more then the specified amount of time +from the last image in the group it will not be added. Images without timestamps +in exif data will be ignored. + +There are two buttons. One allows the grouping to be performed only on the currently +selected images, the other button performs grouping on the entire active collection +]] + +local dt = require "darktable" +local mod = 'autogroup' +local gettext = dt.gettext +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/") +local function _(msgid) + return gettext.dgettext("AutoGrouper", msgid) +end + +local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) + if test >= low and test <= high then + return true + else + return false + end +end + +local function CompTime(first, second) + first_time = first.exif_datetime_taken + if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end + first_time = tonumber(string.gsub(first_time, '[^0-9]*','')) + second_time = second.exif_datetime_taken + if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end + second_time = tonumber(string.gsub(second_time, '[^0-9]*','')) + return first_time < second_time +end + +local function SeperateTime(str) + local cleaned = string.gsub(str, '[^%d]',':') + cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss + local year = string.sub(cleaned,1,4) + local month = string.sub(cleaned,6,7) + local day = string.sub(cleaned,9,10) + local hour = string.sub(cleaned,12,13) + local min = string.sub(cleaned,15,16) + local sec = string.sub(cleaned,18,19) + return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} +end + +local function GetTimeDiff(curr_image, prev_image) + local curr_time = SeperateTime(curr_image.exif_datetime_taken) + local prev_time = SeperateTime(prev_image.exif_datetime_taken) + return os.time(curr_time)-os.time(prev_time) +end + +local function main(on_collection) + local images = {} + if on_collection then + local col_images = dt.collection + for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection + table.insert(images,i,image) + end + else + images = dt.gui.selection() + end + dt.preferences.write(mod, 'active_gap', 'integer', GUI.gap.value) + if #images < 2 then return end + table.sort(images, function(first, second) return CompTime(first,second) end) --sort images into + + for i, image in ipairs(images) do + if i == 1 then + prev_image = image + elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then + local curr_image = image + if GetTimeDiff(curr_image, prev_image) < GUI.gap.value then + images[i]:group_with(images[i-1]) + end + prev_image = curr_image + end + end +end + +-- GUI -- +GUI = { + gap = {}, + selected = {}, + collection = {} +} +temp = dt.preferences.read(mod, 'active_gap', 'integer') +if not InRange(temp, 1, 3600) then temp = 3 end +GUI.gap = dt.new_widget('slider'){ + label = _('group gap [sec.]'), + tooltip = _('minimum gap, in seconds, between groups'), + soft_min = 1, + soft_max = 30, + hard_min = 1, + hard_max = 3600, + step = 1, + digits = 0, + value = temp, + reset_callback = function(self) + self.value = 3 + end +} +GUI.selected = dt.new_widget("button"){ + label = _('auto group: selected'), + tooltip =_('auto group selected images'), + clicked_callback = function() main(false) end +} +GUI.collection = dt.new_widget("button"){ + label = _('auto group: collection'), + tooltip =_('auto group the entire collection'), + clicked_callback = function() main(true) end +} +dt.register_lib( + "AutoGroup_Lib", -- Module name + _("Auto Group"), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers + dt.new_widget("box"){ + orientation = "vertical", + GUI.gap, + GUI.selected, + GUI.collection + } +)