Skip to content

Commit 95968c3

Browse files
authored
Add AutoGrouper
Adds AutoGrouper script which allows the user to select multiple images (or an entire collection) and automatically group them based on timestamp. The separation between groups is user defined via a slider.
1 parent cc4e719 commit 95968c3

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

contrib/AutoGrouper.lua

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
--[[AutoGrouper plugin for darktable
2+
3+
copyright (c) 2019 Kevin Ertel
4+
5+
darktable is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
darktable is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with darktable. If not, see <http://www.gnu.org/licenses/>.
17+
]]
18+
19+
--[[About this Plugin
20+
This plugin adds the module "Auto Group" to darktable's lighttable view
21+
22+
----REQUIRED SOFTWARE----
23+
None
24+
25+
----USAGE----
26+
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
27+
1) Copy this file in to your "lua/contrib" folder where all other scripts reside.
28+
2) Require this file in your luarc file, as with any other dt plug-in
29+
30+
Set a gap amount in second which will be used to determine when images should no
31+
longer be added to a group. If an image is more then the specified amount of time
32+
from the last image in the group it will not be added. Images without timestamps
33+
in exif data will be ignored.
34+
35+
There are two buttons. One allows the grouping to be performed only on the currently
36+
selected images, the other button performs grouping on the entire active collection
37+
]]
38+
39+
local dt = require "darktable"
40+
local mod = 'autogroup'
41+
local gettext = dt.gettext
42+
-- Tell gettext where to find the .mo file translating messages for a particular domain
43+
gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/")
44+
local function _(msgid)
45+
return gettext.dgettext("AutoGrouper", msgid)
46+
end
47+
48+
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
49+
if test >= low and test <= high then
50+
return true
51+
else
52+
return false
53+
end
54+
end
55+
56+
local function CompTime(first, second)
57+
first_time = first.exif_datetime_taken
58+
if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end
59+
first_time = tonumber(string.gsub(first_time, '[^0-9]*',''))
60+
second_time = second.exif_datetime_taken
61+
if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end
62+
second_time = tonumber(string.gsub(second_time, '[^0-9]*',''))
63+
return first_time < second_time
64+
end
65+
66+
local function SeperateTime(str)
67+
local cleaned = string.gsub(str, '[^%d]',':')
68+
cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss
69+
local year = string.sub(cleaned,1,4)
70+
local month = string.sub(cleaned,6,7)
71+
local day = string.sub(cleaned,9,10)
72+
local hour = string.sub(cleaned,12,13)
73+
local min = string.sub(cleaned,15,16)
74+
local sec = string.sub(cleaned,18,19)
75+
return {year = year, month = month, day = day, hour = hour, min = min, sec = sec}
76+
end
77+
78+
local function GetTimeDiff(curr_image, prev_image)
79+
local curr_time = SeperateTime(curr_image.exif_datetime_taken)
80+
local prev_time = SeperateTime(prev_image.exif_datetime_taken)
81+
return os.time(curr_time)-os.time(prev_time)
82+
end
83+
84+
local function main(on_collection)
85+
local images = {}
86+
if on_collection then
87+
local col_images = dt.collection
88+
for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection
89+
table.insert(images,i,image)
90+
end
91+
else
92+
images = dt.gui.selection()
93+
end
94+
dt.preferences.write(mod, 'active_gap', 'integer', GUI.gap.value)
95+
if #images < 2 then return end
96+
table.sort(images, function(first, second) return CompTime(first,second) end) --sort images into
97+
98+
for i, image in ipairs(images) do
99+
if i == 1 then
100+
prev_image = image
101+
elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then
102+
local curr_image = image
103+
if GetTimeDiff(curr_image, prev_image) < GUI.gap.value then
104+
images[i]:group_with(images[i-1])
105+
end
106+
prev_image = curr_image
107+
end
108+
end
109+
end
110+
111+
-- GUI --
112+
GUI = {
113+
gap = {},
114+
selected = {},
115+
collection = {}
116+
}
117+
temp = dt.preferences.read(mod, 'active_gap', 'integer')
118+
if not InRange(temp, 1, 3600) then temp = 3 end
119+
GUI.gap = dt.new_widget('slider'){
120+
label = _('group gap [sec.]'),
121+
tooltip = _('minimum gap, in seconds, between groups'),
122+
soft_min = 1,
123+
soft_max = 30,
124+
hard_min = 1,
125+
hard_max = 3600,
126+
step = 1,
127+
digits = 0,
128+
value = temp,
129+
reset_callback = function(self)
130+
self.value = 3
131+
end
132+
}
133+
GUI.selected = dt.new_widget("button"){
134+
label = _('auto group: selected'),
135+
tooltip =_('auto group selected images'),
136+
clicked_callback = function() main(false) end
137+
}
138+
GUI.collection = dt.new_widget("button"){
139+
label = _('auto group: collection'),
140+
tooltip =_('auto group the entire collection'),
141+
clicked_callback = function() main(true) end
142+
}
143+
dt.register_lib(
144+
"AutoGroup_Lib", -- Module name
145+
_("Auto Group"), -- name
146+
true, -- expandable
147+
true, -- resetable
148+
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers
149+
dt.new_widget("box"){
150+
orientation = "vertical",
151+
GUI.gap,
152+
GUI.selected,
153+
GUI.collection
154+
}
155+
)

0 commit comments

Comments
 (0)