Skip to content

Commit 81b0f1f

Browse files
committed
contrib/dbmaint - remove database records for missing film rolls and images.
1 parent c3ce8d5 commit 81b0f1f

File tree

1 file changed

+314
-0
lines changed

1 file changed

+314
-0
lines changed

contrib/dbmaint.lua

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
--[[
2+
3+
dbmaint.lua - perform database maintenance
4+
5+
Copyright (C) 2024 Bill Ferguson <wpferguson.com>.
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation; either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
]]
20+
--[[
21+
dbmaint - perform database maintenance
22+
23+
Perform database maintenance to clean up missing images and filmstrips.
24+
25+
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
26+
None
27+
28+
USAGE
29+
* start dbmaint from script_manager
30+
* scan for missing film rolls or missing images
31+
* look at the results and choose to delete or not
32+
33+
BUGS, COMMENTS, SUGGESTIONS
34+
Bill Ferguson <wpferguson.com>
35+
36+
CHANGES
37+
]]
38+
39+
local dt = require "darktable"
40+
local du = require "lib/dtutils"
41+
local df = require "lib/dtutils.file"
42+
local log = require "lib/dtutils.log"
43+
44+
45+
-- - - - - - - - - - - - - - - - - - - - - - - -
46+
-- C O N S T A N T S
47+
-- - - - - - - - - - - - - - - - - - - - - - - -
48+
49+
local MODULE <const> = "dbmaint"
50+
local DEFAULT_LOG_LEVEL <const> = log.error
51+
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
52+
53+
-- - - - - - - - - - - - - - - - - - - - - - - -
54+
-- A P I C H E C K
55+
-- - - - - - - - - - - - - - - - - - - - - - - -
56+
57+
du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need
58+
59+
60+
-- - - - - - - - - - - - - - - - - - - - - - - - - -
61+
-- I 1 8 N
62+
-- - - - - - - - - - - - - - - - - - - - - - - - - -
63+
64+
local gettext = dt.gettext.gettext
65+
66+
dt.gettext.bindtextdomain(MODULE , dt.configuration.config_dir .. "/lua/locale/")
67+
68+
local function _(msgid)
69+
return gettext(MODULE, msgid)
70+
end
71+
72+
73+
-- - - - - - - - - - - - - - - - - - - - - - - - - -
74+
-- S C R I P T M A N A G E R I N T E G R A T I O N
75+
-- - - - - - - - - - - - - - - - - - - - - - - - - -
76+
77+
local script_data = {}
78+
79+
script_data.destroy = nil -- function to destory the script
80+
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
81+
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
82+
script_data.show = nil -- only required for libs since the destroy_method only hides them
83+
84+
script_data.metadata = {
85+
name = "dbmaint",
86+
purpose = _("perform database maintenance"),
87+
author = "Bill Ferguson <wpferguson.com>",
88+
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/dbmaint/"
89+
}
90+
91+
92+
-- - - - - - - - - - - - - - - - - - - - - - - -
93+
-- L O G L E V E L
94+
-- - - - - - - - - - - - - - - - - - - - - - - -
95+
96+
log.log_level(DEFAULT_LOG_LEVEL)
97+
98+
-- - - - - - - - - - - - - - - - - - - - - - - -
99+
-- N A M E S P A C E
100+
-- - - - - - - - - - - - - - - - - - - - - - - -
101+
102+
local dbmaint = {}
103+
104+
-- - - - - - - - - - - - - - - - - - - - - - - -
105+
-- G L O B A L V A R I A B L E S
106+
-- - - - - - - - - - - - - - - - - - - - - - - -
107+
108+
dbmaint.main_widget = nil
109+
110+
-- - - - - - - - - - - - - - - - - - - - - - - -
111+
-- A L I A S E S
112+
-- - - - - - - - - - - - - - - - - - - - - - - -
113+
114+
local namespace = dbmaint
115+
116+
-- - - - - - - - - - - - - - - - - - - - - - - -
117+
-- F U N C T I O N S
118+
-- - - - - - - - - - - - - - - - - - - - - - - -
119+
120+
local function scan_film_rolls()
121+
local missing_films = {}
122+
123+
for _, filmroll in ipairs(dt.films) do
124+
if not df.check_if_file_exists(filmroll.path) then
125+
table.insert(missing_films, filmroll)
126+
end
127+
end
128+
129+
return missing_films
130+
end
131+
132+
local function scan_images(film)
133+
local missing_images = {}
134+
135+
if film then
136+
for i = 1, #film do
137+
local image = film[i]
138+
log.log_msg(log.debug, "checking " .. image.filename)
139+
if not df.check_if_file_exists(image.path .. PS .. image.filename) then
140+
log.log_msg(log.info, image.filename .. " not found")
141+
table.insert(missing_images, image)
142+
end
143+
end
144+
end
145+
146+
return missing_images
147+
end
148+
149+
local function remove_missing_film_rolls(list)
150+
for _, filmroll in ipairs(list) do
151+
filmroll:delete(true)
152+
end
153+
end
154+
155+
-- force the lighttable to reload
156+
157+
local function refresh_lighttable(film)
158+
local rules = dt.gui.libs.collect.filter()
159+
dt.gui.libs.collect.filter(rules)
160+
end
161+
162+
local function remove_missing_images(list)
163+
local film = list[1].film
164+
for _, image in ipairs(list) do
165+
image:delete()
166+
end
167+
refresh_lighttable(film)
168+
end
169+
170+
local function install_module()
171+
if not namespace.module_installed then
172+
dt.register_lib(
173+
MODULE, -- Module name
174+
_("DB maintenance"), -- Visible name
175+
true, -- expandable
176+
true, -- resetable
177+
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers
178+
namespace.main_widget,
179+
nil,-- view_enter
180+
nil -- view_leave
181+
)
182+
namespace.module_installed = true
183+
end
184+
end
185+
186+
-- - - - - - - - - - - - - - - - - - - - - - - -
187+
-- U S E R I N T E R F A C E
188+
-- - - - - - - - - - - - - - - - - - - - - - - -
189+
190+
dbmaint.list_widget = dt.new_widget("text_view"){
191+
editable = false,
192+
reset_callback = function(this)
193+
this.text = ""
194+
end
195+
}
196+
197+
dbmaint.chooser = dt.new_widget("combobox"){
198+
label = "scan for",
199+
selected = 1,
200+
"film rolls", "images",
201+
reset_callback = function(this)
202+
this.selected = 1
203+
end
204+
}
205+
206+
dbmaint.scan_button = dt.new_widget("button"){
207+
label = "scan",
208+
tooltip = "click to scan for missing film rolls/files",
209+
clicked_callback = function(this)
210+
local found = nil
211+
local found_text = ""
212+
if dbmaint.chooser.value == "film rolls" then
213+
found = scan_film_rolls()
214+
if #found > 0 then
215+
for _, film in ipairs(found) do
216+
local dir_name = du.split(film.path, PS)
217+
found_text = found_text .. dir_name[#dir_name] .. "\n"
218+
end
219+
end
220+
else
221+
log.log_msg(log.debug, "checking path " .. dt.collection[1].path .. " for missing files")
222+
found = scan_images(dt.collection[1].film)
223+
if #found > 0 then
224+
for _, image in ipairs(found) do
225+
found_text = found_text .. image.filename .. "\n"
226+
end
227+
end
228+
end
229+
if #found > 0 then
230+
dbmaint.list_widget.text = found_text
231+
dbmaint.found = found
232+
dbmaint.remove_button.sensitive = true
233+
end
234+
end,
235+
reset_callback = function(this)
236+
dbmaint.found = nil
237+
end
238+
}
239+
240+
dbmaint.remove_button = dt.new_widget("button"){
241+
label = "remove",
242+
tooltip = "remove missing film rolls/images",
243+
sensitive = false,
244+
clicked_callback = function(this)
245+
if dbmaint.chooser.value == "film rolls" then
246+
remove_missing_film_rolls(dbmaint.found)
247+
else
248+
remove_missing_images(dbmaint.found)
249+
end
250+
dbmaint.found = nil
251+
dbmaint.list_widget.text = ""
252+
this.sensitive = false
253+
end,
254+
reset_callback = function(this)
255+
this.sensitive = false
256+
end
257+
}
258+
259+
dbmaint.main_widget = dt.new_widget("box"){
260+
orientation = "vertical",
261+
dt.new_widget("section_label"){label = "missing items"},
262+
dbmaint.list_widget,
263+
dt.new_widget("label"){label = ""},
264+
dbmaint.chooser,
265+
dt.new_widget("label"){label = ""},
266+
dbmaint.scan_button,
267+
dbmaint.remove_button
268+
}
269+
270+
-- - - - - - - - - - - - - - - - - - - - - - - -
271+
-- D A R K T A B L E I N T E G R A T I O N
272+
-- - - - - - - - - - - - - - - - - - - - - - - -
273+
274+
local function destroy()
275+
dt.gui.libs[MODULE].visible = false
276+
277+
if namespace.event_registered then
278+
dt.destroy_event(MODULE, "view-changed")
279+
end
280+
281+
return
282+
end
283+
284+
local function restart()
285+
dt.gui.libs[MODULE].visible = true
286+
287+
return
288+
end
289+
290+
script_data.destroy = destroy
291+
script_data.restart = restart
292+
script_data.destroy_method = "hide"
293+
script_data.show = restart
294+
295+
-- - - - - - - - - - - - - - - - - - - - - - - -
296+
-- E V E N T S
297+
-- - - - - - - - - - - - - - - - - - - - - - - -
298+
299+
if dt.gui.current_view().id == "lighttable" then
300+
install_module()
301+
else
302+
if not namespace.event_registered then
303+
dt.register_event(MODULE, "view-changed",
304+
function(event, old_view, new_view)
305+
if new_view.name == "lighttable" and old_view.name == "darkroom" then
306+
install_module()
307+
end
308+
end
309+
)
310+
namespace.event_registered = true
311+
end
312+
end
313+
314+
return script_data

0 commit comments

Comments
 (0)