diff --git a/README.md b/README.md index 7577026..8acac4b 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ The following third-party projects are listed for information only. Think of thi * [johnnyrun/darktable_lua_gimp](https://github.com/johnnyrun/darktable_lua_gimp) – GIMP export * [arru/darktable-scripts](https://github.com/arru/darktable-scripts) * [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts) +* [s5k6/dtscripts](https://github.com/s5k6/dtscripts) ## Download and Install diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 2936800..4575542 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -88,7 +88,7 @@ local function _(msgid) end -- maximum number of external programs, can be increased to necessity -local MAX_EDITORS = 10 +local MAX_EDITORS = 9 -- number of valid entries in the list of external programs local n_entries @@ -98,7 +98,6 @@ local n_entries local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"} --- last used editor initialization if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0) dt.preferences.write(MODULE_NAME, "initialized", "bool", true) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 45229b6..fe1e9f6 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -69,14 +69,8 @@ end -- preferences if not dt.preferences.read(MODULE, "initialized", "bool") then - dt.preferences.write(MODULE, "unknown_tag", "string", "unknown_person") - dt.preferences.write(MODULE, "ignore_tags", "string", "") - dt.preferences.write(MODULE, "tolerance", "float", 0.6) - dt.preferences.write(MODULE, "num_cores", "integer", 0) - dt.preferences.write(MODULE, "known_image_path", "directory", dt.configuration.config_dir .. "/face_recognition") - dt.preferences.write(MODULE, "export_format", "integer", 1) - dt.preferences.write(MODULE, "max_width", "integer", 1000) - dt.preferences.write(MODULE, "max_height", "integer", 1000) + reset_preferences() + save_preferences() dt.preferences.write(MODULE, "initialized", "bool", true) end @@ -154,13 +148,29 @@ end local function save_preferences() dt.preferences.write(MODULE, "unknown_tag", "string", fc.unknown_tag.text) + dt.preferences.write(MODULE, "no_persons_found_tag", "string", fc.no_persons_found_tag.text) dt.preferences.write(MODULE, "ignore_tags", "string", fc.ignore_tags.text) - dt.preferences.write(MODULE, "max_width", "integer", tonumber(fc.width.text)) - dt.preferences.write(MODULE, "max_height", "integer", tonumber(fc.height.text)) - dt.preferences.write(MODULE, "num_cores", "integer", fc.num_cores.value) + dt.preferences.write(MODULE, "known_image_path", "directory", fc.known_image_path.value) local val = fc.tolerance.value val = string.gsub(tostring(val), ",", ".") dt.preferences.write(MODULE, "tolerance", "float", tonumber(val)) + dt.preferences.write(MODULE, "num_cores", "integer", fc.num_cores.value) + dt.preferences.write(MODULE, "export_format", "integer", fc.export_format.selected) + dt.preferences.write(MODULE, "max_width", "integer", tonumber(fc.width.text)) + dt.preferences.write(MODULE, "max_height", "integer", tonumber(fc.height.text)) +end + +local function reset_preferences() + fc.unknown_tag.text = "unknown_person" + fc.no_persons_found_tag.text = "no_persons_found" + fc.ignore_tags.text = "" + fc.known_image_path.value = dt.configuration.config_dir .. "/face_recognition" + fc.tolerance.value = 0.6 + fc.num_cores.value = -1 + fc.export_format.selected = 1 + fc.width.text = 1000 + fc.height.text = 1000 + save_preferences() end -- Check if image has ignored tag attached @@ -205,6 +215,7 @@ local function face_recognition () local nrCores = dt.preferences.read(MODULE, "num_cores", "integer") local ignoreTagString = dt.preferences.read(MODULE, "ignore_tags", "string") local unknownTag = dt.preferences.read(MODULE, "unknown_tag", "string") + local nonpersonsfoundTag = dt.preferences.read(MODULE, "no_persons_found_tag", "string") -- face_recognition uses -1 for all cores, we use 0 in preferences if nrCores < 1 then @@ -259,13 +270,15 @@ local function face_recognition () dt.print(_("processing results...")) local result = {} for line in io.lines(OUTPUT) do - local file, tag = string.match (line, "(.*),(.*)$") - tag = string.gsub (tag, "%d*$", "") - dt.print_log ("File:"..file .." Tag:".. tag) - if result[file] ~= nil then - table.insert (result[file], tag) - else - result[file] = {tag} + if not string.match(line, "^WARNING:") then + local file, tag = string.match (line, "(.*),(.*)$") + tag = string.gsub (tag, "%d*$", "") + dt.print_log ("File:"..file .." Tag:".. tag) + if result[file] ~= nil then + table.insert (result[file], tag) + else + result[file] = {tag} + end end end @@ -283,10 +296,16 @@ local function face_recognition () if t == "unknown_person" then t = unknownTag end - dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) - -- Create tag if it does not exists - local tag = dt.tags.create (t) - img:attach_tag (tag) + -- Check of unrecognized no_persons_found + if t == "no_persons_found" then + t = nonpersonsfoundTag + end + if t ~= "" and t ~= nil then + dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) + -- Create tag if it does not exists + local tag = dt.tags.create (t) + img:attach_tag (tag) + end end end end @@ -314,6 +333,12 @@ fc.unknown_tag = dt.new_widget("entry"){ editable = true, } +fc.no_persons_found_tag = dt.new_widget("entry"){ + text = dt.preferences.read(MODULE, "no_persons_found_tag", "string"), + tooltip = _("tag to be used when no persons are found"), + editable = true, +} + fc.ignore_tags = dt.new_widget("entry"){ text = dt.preferences.read(MODULE, "ignore_tags", "string"), tooltip = _("tags of images to ignore"), @@ -386,7 +411,9 @@ fc.execute = dt.new_widget("button"){ local widgets = { dt.new_widget("label"){ label = _("unknown person tag")}, fc.unknown_tag, - dt.new_widget("label"){ label = _("togs of images to ignore")}, + dt.new_widget("label"){ label = _("no persons found tag")}, + fc.no_persons_found_tag, + dt.new_widget("label"){ label = _("tags of images to ignore")}, fc.ignore_tags, dt.new_widget("label"){ label = _("face data directory")}, fc.known_image_path, @@ -413,7 +440,10 @@ table.insert(widgets, fc.execute) fc.widget = dt.new_widget("box"){ orientation = vertical, - table.unpack(widgets) + reset_callback = function(this) + reset_preferences() + end, + table.unpack(widgets), } --fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") @@ -425,7 +455,7 @@ dt.register_lib( "face_recognition", -- Module name _("face recognition"), -- Visible name true, -- expandable - false, -- resetable + true, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers fc.widget, nil,-- view_enter diff --git a/include_all.lua b/include_all.lua deleted file mode 100644 index c25dd54..0000000 --- a/include_all.lua +++ /dev/null @@ -1,61 +0,0 @@ ---[[ - This file is part of darktable, - copyright (c) 2014 Jérémy Rosen - copyright (c) 2018 Bill Ferguson - - 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 . -]] ---[[ -INCLUDE ALL -Automatically include all scripts in the script repository - -This is intended for debugging purpose - - -USAGE -* require this file from your main lua config file: -* go to configuration => preferences -* Enable the scripts you want to use -* restart darktable - -Note that you need to restart DT for your changes to enabled scripts to take effect - -]] -local dt = require "darktable" -local io = require "io" - --- must be loaded for scripts using darktable.control_execute to work -require "official/yield" - -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) - --- find all scripts, but skip the lib and tools directories -local output = io.popen("cd "..dt.configuration.config_dir.."/lua ;find . -name lib -prune -o -name tools -prune -o -name \\*.lua -print") - -local my_name={...} -my_name = my_name[1] -for line in output:lines() do - local req_name = line:sub(3,-5) - if req_name ~= my_name and not string.match(req_name, "yield") then - dt.preferences.register(my_name,req_name,"bool","enable "..req_name, - "Should the script "..req_name.." be enabled at next startup",false) - - if dt.preferences.read(my_name,req_name,"bool") then - require(req_name) - end - end -end - --- --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 89af3a7..f58f38c 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -174,6 +174,59 @@ function dtutils_string.urlencode(str) end +dtutils_string.libdoc.functions["is_not_sanitized"] = { + Name = [[is_not_sanitized]], + Synopsis = [[Check if a string has been sanitized]], + Usage = [[local ds = require "lib/dtutils.string" + local result = ds.is_not_sanitized(str) + str - string - the string that needs to be made safe]], + Description = [[is_not_sanitized checks a string to see if it + has been made safe use passing as an argument in a system command.]], + Return_Value = [[result - boolean - true if the string is not sanitized otherwise false]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +local function _is_not_sanitized_posix(str) + -- A sanitized string must be quoted. + if not string.match(str, "^'.*'$") then + return true + -- A quoted string containing no quote characters within is sanitized. + elseif string.match(str, "^'[^']*'$") then + return false + end + + -- Any quote characters within a sanitized string must be properly + -- escaped. + local quotesStripped = string.sub(str, 2, -2) + local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "") + if string.find(escapedQuotesRemoved, "'") then + return true + else + return false + end +end + +local function _is_not_sanitized_windows(str) + if not string.match(str, "^\".*\"$") then + return true + else + return false + end +end + +function dtutils_string.is_not_sanitized(str) + if dt.configuration.running_os == "windows" then + return _is_not_sanitized_windows(str) + else + return _is_not_sanitized_posix(str) + end +end + dtutils_string.libdoc.functions["sanitize"] = { Name = [[sanitize]], Synopsis = [[surround a string in quotes making it safe to pass as an argument]], @@ -192,41 +245,27 @@ dtutils_string.libdoc.functions["sanitize"] = { Copyright = [[]], } -function dtutils_string.sanitize(str) - local result = "" - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - - if dtutils_string.is_not_sanitized(str) then - result = os_quote .. str .. os_quote +local function _sanitize_posix(str) + if _is_not_sanitized_posix(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str end - - return result end -dtutils_string.libdoc.functions["is_not_sanitized"] = { - Name = [[is_not_sanitized]], - Synopsis = [[Check if a string has been sanitized]], - Usage = [[local ds = require "lib/dtutils.string" - local result = ds.is_not_sanitized(str) - str - string - the string that needs to be made safe]], - Description = [[is_not_sanitized checks a string to see if it - has been made safe use passing as an argument in a system command.]], - Return_Value = [[result - boolean - true if the string is not sanitized otherwise false]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_string.is_not_sanitized(str) - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - - if string.match(str, os_quote .. ".*" .. os_quote) then - return false +local function _sanitize_windows(str) + if _is_not_sanitized_windows(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" else - return true + return str + end +end + +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return _sanitize_windows(str) + else + return _sanitize_posix(str) end end