From c74d29e02013950c81e9db283b406b3763641324 Mon Sep 17 00:00:00 2001 From: GHswitt Date: Wed, 14 Dec 2016 01:08:10 +0100 Subject: [PATCH 001/640] Add new GUI entry in lighttable for renaming tags Rename tag: A new tag is added to all images containing old tag. After that, the old tag is removed from all images (and removed from tags). The GUI entry has two entries: Old tag, New tag and a Go button. --- contrib/rename-tags.lua | 114 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 contrib/rename-tags.lua diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua new file mode 100644 index 00000000..69c6e0a8 --- /dev/null +++ b/contrib/rename-tags.lua @@ -0,0 +1,114 @@ +--[[ +Rename tags + +AUTHOR +Sebastian Witt (se.witt@gmx.net) + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR +is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "rename-tags" + +USAGE +* In lighttable there is a new entry: 'rename tag' +* Enter old tag (this one gets deleted!) +* Enter new tag name + +LICENSE +GPLv2 + +]] + +local darktable = require "darktable" +local debug = require "darktable.debug" + +-- GUI entries +local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" } +local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" } + +-- This function does the renaming +local function rename_tags(widget) + -- If entries are empty, return + if old_tag.text == '' then + darktable.print ("Old tag can't be empty") + return + end + if new_tag.text == '' then + darktable.print ("New tag can't be empty") + return + end + + local Count = 0 + + -- Check if old tag exists + local ot = darktable.tags.find (old_tag.text) + + if not ot then + darktable.print ("Old tag does not exist") + return + end + + -- Show job + local job = darktable.gui.create_job ("Renaming tag", true) + + old_tag.editable = false + new_tag.editable = false + + -- Create if it does not exists + local nt = darktable.tags.create (new_tag.text) + + -- Search images for old tag + dbcount = #darktable.database + for i,image in ipairs(darktable.database) do + -- Update progress bar + job.percent = i / dbcount + + local tags = image:get_tags () + for _,t in ipairs (tags) do + if t.name == old_tag.text then + -- Found it, attach new tag + image:attach_tag (nt) + Count = Count + 1 + end + end + end + + -- Delete old tag, this removes it from all images + darktable.tags.delete (ot) + + job.valid = false + darktable.print ("Renamed tags for " .. Count .. " images") + old_tag.editable = true + new_tag.editable = true +end + +-- GUI +local old_widget = darktable.new_widget ("box") { + orientation = "horizontal", + darktable.new_widget("label") { label = "Old tag" }, + old_tag +} + +local new_widget = darktable.new_widget ("box") { + orientation = "horizontal", + darktable.new_widget("label") { label = "New tag" }, + new_tag +} + +local function rename_reset(widget) + old_tag.text = '' + new_tag.text = '' +end + +local rename_widget = darktable.new_widget ("box") { + orientation = "vertical", + reset_callback = rename_reset, + old_widget, + new_widget, + darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } +} + + +darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rename_widget, nil, nil) + From d0ec941009110fdcd0ebe3ce5e4326e6254d64ab Mon Sep 17 00:00:00 2001 From: supertobi Date: Wed, 11 Oct 2017 09:32:29 +0200 Subject: [PATCH 002/640] check if exiftool exists in autostyle.lua --- contrib/autostyle.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 17f27c31..66eca201 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -28,6 +28,8 @@ USAGE > exiftool -AutoDynamicRange XE021351.RAF Auto Dynamic Range : 200% +ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT +* exiftool LICENSE GPLv2 @@ -41,7 +43,7 @@ local darktable = require "darktable" local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture -- Tested it with darktable 1.6.1 and darktable git from 2014-01-25 -darktable.configuration.check_version(...,{2,0,2},{2,1,0},{3,0,0},{4,0,0}) +darktable.configuration.check_version(...,{2,0,2},{2,1,0},{3,0,0},{4,0,0},{5,0,0}) -- Receive the event triggered function autostyle_apply_one_image_event(event,image) @@ -66,7 +68,11 @@ function autostyle_apply_one_image (image) darktable.print("style name not found in " .. darktable.preferences.read("autostyle","exif_tag","string")) return end - + if not checkIfBinExists("exiftool") then + return + end + + -- First find the style (we have its name) local styles= darktable.styles local style From d74f2eba92f276688b70c7d1ec23d61a1dfc4f31 Mon Sep 17 00:00:00 2001 From: supertobi Date: Wed, 11 Oct 2017 11:29:48 +0200 Subject: [PATCH 003/640] Create printExamples.lua --- examples/printExamples.lua | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/printExamples.lua diff --git a/examples/printExamples.lua b/examples/printExamples.lua new file mode 100644 index 00000000..5ef3695e --- /dev/null +++ b/examples/printExamples.lua @@ -0,0 +1,40 @@ +--[[ + This file is part of darktable, + copyright (c) 2017 Tobias Jakobs + 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 . +]] + +--[[ +Print Examples +prints "hello world when DT starts +USAGE +* require this file from your main lua config file: +]] +local dt = require "darktable" +dt.configuration.check_version(...,{5,0,0}) + +-- Will print a string to the darktable control log (the long +-- overlayed window that appears over the main panel). +dt.print("print") + +-- This function will print its parameter if the Lua logdomain is +-- activated. Start darktable with the "-d lua" command line option +-- to enable the Lua logdomain. +dt.print_error("print error") + +-- This function will print its parameter if the Lua logdomain is +-- activated. Start darktable with the "-d lua" command line option +-- to enable the Lua logdomain. +dt.print_log("print log") + +-- +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua From 024e016df2853c65215d8f517f53b4ce26a49b49 Mon Sep 17 00:00:00 2001 From: GHswitt Date: Mon, 11 Dec 2017 14:27:36 +0100 Subject: [PATCH 004/640] Storage plugin for face_recognition --- contrib/face_recognition.lua | 163 +++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 contrib/face_recognition.lua diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua new file mode 100644 index 00000000..18f851fe --- /dev/null +++ b/contrib/face_recognition.lua @@ -0,0 +1,163 @@ +--[[ + Face recognition for darktable + + Copyright (c) 2017 Sebastian Witt + + 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 . +]] + +--[[ +face_recognition +Add a new storage option to send images to face_recognition. +Images are exported to darktable tmp dir first. +A directory with known faces must exist, the image name are the +tag names which will be used. +Multiple images for one face can exist, add a number to it, the +number will be removed from the tag, for example: +People|IknowYou1.jpg +People|IknowYou2.jpg +People|Another.jpg +People|Youtoo.jpg + +ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT +* https://github.com/ageitgey/face_recognition +* https://github.com/darktable-org/lua-scripts/tree/master/lib + +USAGE +* require this file from your main luarc config file. + +This plugin will add a new storage option and calls face_recognition after export. +]] + +local dt = require "darktable" +local df = require "lib/dtutils.file" +local gettext = dt.gettext + +-- works with darktable API version from 2.0.0 to 5.0.0 +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("face_recognition", dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("face_recognition", msgid) +end + +-- Register preference for known faces path +dt.preferences.register("FaceRecognition", + "knownImagePath", + "directory", -- type + _("Face recognition: Known images"), -- label + _("Path to images with known faces, files named after tag to apply"), -- tooltip + "~/.config/darktable/face_recognition") -- default +-- ...and number of CPU cores to use +dt.preferences.register("FaceRecognition", + "nrCores", + "integer", -- type + _("Face recognition: Nr of CPU cores"), -- label + _("Number of CPU cores to use, 0 for all"), -- tooltip + 0, -- default + 0, -- min + 64) -- max + +local function show_status (storage, image, format, filename, number, total, high_quality, extra_data) + dt.print("Export to Face recognition "..tostring(number).."/"..tostring(total)) +end + +local function face_recognition (storage, image_table, extra_data) --finalize + if not df.check_if_bin_exists("face_recognition") then + dt.print(_("Face recognition not found")) + return + end + + -- list of exported images + local img_list = {} + + for _,v in pairs(image_table) do + table.insert (img_list, v) + end + + -- Get path of exported images + local path = df.get_path (img_list[1]) + dt.print_error ("FR: Unknown path: " .. path) + + -- Path to known images and number of CPU cores to use + local knownPath = dt.preferences.read("FaceRecognition", "knownImagePath", "directory") + local nrCores = dt.preferences.read("FaceRecognition", "nrCores", "integer") + + if nrCores < 1 then + nrCores = -1 + end + + -- Output file + local output = path .. "fr.txt" + + local command = "face_recognition --cpus " .. nrCores .. " " .. knownPath .. " " .. path .. " > " .. output + dt.print_error("FR: " .. command) + dt.print(_("Starting face recognition...")) + + dt.control.execute(command) + + -- Remove exported images + for _,v in ipairs(img_list) do + os.remove (v) + end + + -- Open output file + local f = io.open(output, "rb") + + if not f then + dt.print(_("Face recognition failed")) + else + dt.print(_("Face recognition finished")) + f:close () + end + + -- Read output + local result = {} + for line in io.lines(output) do + local file, tag = string.match (line, "(.*),(.*)$") + tag = string.gsub (tag, "%d*$", "") + dt.print_error ("F:"..file .." T:".. tag) + if result[file] ~= nil then + table.insert (result[file], tag) + else + result[file] = {tag} + end + end + + -- Attach tags + for file,tags in pairs(result) do + -- Find image in table + for img,file2 in pairs(image_table) do + if file == file2 then + for _,t in ipairs (tags) do + dt.print_error ("I:" .. img.id .. " T: ".. t) + -- Create tag if it does not exists + local tag = dt.tags.create (t) + img:attach_tag (tag) + end + end + end + end + + --os.remove (output) + +end + +-- Register +dt.register_storage("module_face_recognition", _("Face recognition"), show_status, face_recognition) + +-- +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua From 8e6552ee9c2a158fa9fcf456a41aa6fc271efc51 Mon Sep 17 00:00:00 2001 From: GHswitt Date: Mon, 11 Dec 2017 17:43:53 +0100 Subject: [PATCH 005/640] Added ignore tag and unknown tag, verbose output --- contrib/face_recognition.lua | 100 ++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 18f851fe..5f885914 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -54,14 +54,21 @@ local function _(msgid) return gettext.dgettext("face_recognition", msgid) end --- Register preference for known faces path +-- Preference: Tag for unknown_person dt.preferences.register("FaceRecognition", - "knownImagePath", - "directory", -- type - _("Face recognition: Known images"), -- label - _("Path to images with known faces, files named after tag to apply"), -- tooltip - "~/.config/darktable/face_recognition") -- default --- ...and number of CPU cores to use + "unknownTag", + "string", -- type + _("Face recognition: Unknown tag"), -- label + _("Tag for faces that are not recognized"), -- tooltip + "unknown_person") +-- Preference: Images with this substring in tags are ignored +dt.preferences.register("FaceRecognition", + "ignoreTags", + "string", -- type + _("Face recognition: Ignore tag"), -- label + _("Images with this substring in tags are ignored, separate multiple strings with ,"), -- tooltip + "") +-- Preference: Number of CPU cores to use dt.preferences.register("FaceRecognition", "nrCores", "integer", -- type @@ -70,41 +77,77 @@ dt.preferences.register("FaceRecognition", 0, -- default 0, -- min 64) -- max +-- Preference: Known faces path +dt.preferences.register("FaceRecognition", + "knownImagePath", + "directory", -- type + _("Face recognition: Known images"), -- label + _("Path to images with known faces, files named after tag to apply"), -- tooltip + "~/.config/darktable/face_recognition") -- default -- default local function show_status (storage, image, format, filename, number, total, high_quality, extra_data) dt.print("Export to Face recognition "..tostring(number).."/"..tostring(total)) end +-- Check if image has ignored tag attached +local function ignoreByTag (image, ignoreTags) + local tags = image:get_tags () + local ignoreImage = false + -- For each image tag + for _,t in ipairs (tags) do + -- Check if it contains a ignore tag + for _,it in ipairs (ignoreTags) do + if string.find (t.name, it, 1, true) then + -- The image has ignored tag attached + ignoreImage = true + dt.print_error ("Face recognition: Ignored tag: " .. it .. " found in " .. image.id .. ":" .. t.name) + end + end + end + + return ignoreImage +end + local function face_recognition (storage, image_table, extra_data) --finalize if not df.check_if_bin_exists("face_recognition") then dt.print(_("Face recognition not found")) return end + -- Get preferences + local knownPath = dt.preferences.read("FaceRecognition", "knownImagePath", "directory") + local nrCores = dt.preferences.read("FaceRecognition", "nrCores", "integer") + local ignoreTagString = dt.preferences.read("FaceRecognition", "ignoreTags", "string") + local unknownTag = dt.preferences.read("FaceRecognition", "unknownTag", "string") + + -- face_recognition uses -1 for all cores, we use 0 in preferences + if nrCores < 1 then + nrCores = -1 + end + + -- Split ignore tags (if any) + ignoreTags = {} + for tag in string.gmatch(ignoreTagString, '([^,]+)') do + table.insert (ignoreTags, tag) + dt.print_error ("Face recognition: Ignore tag: " .. tag) + end + -- list of exported images local img_list = {} - for _,v in pairs(image_table) do + for img,v in pairs(image_table) do table.insert (img_list, v) end -- Get path of exported images local path = df.get_path (img_list[1]) - dt.print_error ("FR: Unknown path: " .. path) - - -- Path to known images and number of CPU cores to use - local knownPath = dt.preferences.read("FaceRecognition", "knownImagePath", "directory") - local nrCores = dt.preferences.read("FaceRecognition", "nrCores", "integer") + dt.print_error ("Face recognition: Path to unknown images: " .. path) - if nrCores < 1 then - nrCores = -1 - end - -- Output file - local output = path .. "fr.txt" + local output = path .. "facerecognition.txt" local command = "face_recognition --cpus " .. nrCores .. " " .. knownPath .. " " .. path .. " > " .. output - dt.print_error("FR: " .. command) + dt.print_error("Face recognition: Running command: " .. command) dt.print(_("Starting face recognition...")) dt.control.execute(command) @@ -129,7 +172,7 @@ local function face_recognition (storage, image_table, extra_data) --finalize for line in io.lines(output) do local file, tag = string.match (line, "(.*),(.*)$") tag = string.gsub (tag, "%d*$", "") - dt.print_error ("F:"..file .." T:".. tag) + dt.print_error ("File:"..file .." Tag:".. tag) if result[file] ~= nil then table.insert (result[file], tag) else @@ -143,10 +186,19 @@ local function face_recognition (storage, image_table, extra_data) --finalize for img,file2 in pairs(image_table) do if file == file2 then for _,t in ipairs (tags) do - dt.print_error ("I:" .. img.id .. " T: ".. t) - -- Create tag if it does not exists - local tag = dt.tags.create (t) - img:attach_tag (tag) + -- Check if image is ignored + if ignoreByTag (img, ignoreTags) then + dt.print_error("Face recognition: Ignoring image with ID " .. img.id) + else + -- Check of unrecognized unknown_person + if t == "unknown_person" then + t = unknownTag + end + dt.print_error ("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 From b47da137c1d9fdce42532ccb8da76b3cb4e7cd3a Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 12 Dec 2017 15:18:40 +0100 Subject: [PATCH 006/640] Create LICENSE --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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. + + This program 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 this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From a6f8070f654cd750674bf448fd1b7bca9e557c8e Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 12 Dec 2017 16:36:38 +0100 Subject: [PATCH 007/640] Delete LICENSE --- LICENSE | 674 -------------------------------------------------------- 1 file changed, 674 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 94a9ed02..00000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program 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. - - This program 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 this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. From 33b6f0d72e56e35f7b00886843816b67eaafe532 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:07:20 +0100 Subject: [PATCH 008/640] added {5,0,0} to the check_version --- contrib/slideshowMusic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index f96383d2..2da53dc2 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -29,7 +29,7 @@ local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext -dt.configuration.check_version(...,{2,0,2},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,2},{3,0,0},{4,0,0},{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") From 63b38c1f53aaaffabe6a9f439de71a9c28b5daf2 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:08:07 +0100 Subject: [PATCH 009/640] added {5,0,0} to the check_version --- contrib/clear_GPS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index bc5fc4e3..2a84a616 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -42,7 +42,7 @@ local gettext = dt.gettext -- not a number local NaN = 0/0 -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain From 6b5f650aac8e0a0b02005ab5e3a1f0ed81facfec Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:08:49 +0100 Subject: [PATCH 010/640] added {5,0,0} to the check_version --- contrib/cr2hdr.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 3d14fb16..051c33d4 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -35,7 +35,7 @@ USAGE local darktable = require "darktable" -- Tested with darktable 2.0.1 -darktable.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +darktable.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) local queue = {} local processed_files = {} From c4ed6c2b97687acee9001861fda08e43462d012d Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:09:42 +0100 Subject: [PATCH 011/640] added {5,0,0} to the check_version --- contrib/fujifilm_ratings.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index e19ef79b..38b3c21b 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -27,7 +27,7 @@ local dt = require "darktable" local df = require "lib/dtutils.file" local gettext = dt.gettext -dt.configuration.check_version(..., {4,0,0}) +dt.configuration.check_version(...,{4,0,0},{5,0,0}) gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") From b4347e5701bc13d873d61a094104cee550e5a7dd Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:10:31 +0100 Subject: [PATCH 012/640] added {5,0,0} to the check_version --- contrib/rate_group.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 253443fd..494f4ad8 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -41,7 +41,7 @@ local dt = require "darktable" -- added version check -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{4,0,0}) local function apply_rating(rating) local images = dt.gui.action_images From befa83bee8ff7414347190e99de1639404d8a000 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:10:56 +0100 Subject: [PATCH 013/640] added {5,0,0} to the check_version --- contrib/rate_group.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 494f4ad8..3a557a8f 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -41,7 +41,7 @@ local dt = require "darktable" -- added version check -dt.configuration.check_version(...,{3,0,0},{4,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) local function apply_rating(rating) local images = dt.gui.action_images From d3692bcc0914148ff2e8068314601695f00d14f0 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:22:43 +0100 Subject: [PATCH 014/640] check_for_updates.lua: added {5,0,0} to the check_version --- official/check_for_updates.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index c2d925fa..221a660f 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -31,7 +31,7 @@ local dt = require "darktable" local https = require "ssl.https" local cjson = require "cjson" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) -- compare two version strings of the form "major.minor.patch" -- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version, From 0191558d26eec18bdfabe0f4ce5ad3fa48ad78d6 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:24:42 +0100 Subject: [PATCH 015/640] Update copy_paste_metadata.lua added {5,0,0} to the check_version --- official/copy_paste_metadata.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index c655b00a..4d1c70bc 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -27,7 +27,7 @@ USAGE local dt = require "darktable" -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) -- set this to "false" if you don't want to overwrite metadata fields -- (title, description, creator, publisher and rights) that are already set From d29e5f49f4052e7f60aab538879d93b522cb0679 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:28:44 +0100 Subject: [PATCH 016/640] Update delete_long_tags.lua added {5,0,0} to the check_version --- official/delete_long_tags.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 8481600e..3e2378b7 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -29,7 +29,7 @@ all tags longer than the given length will be automatically deleted at every res ]] local dt = require "darktable" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) dt.preferences.register("delete_long_tags", "length", "integer", "maximum length of tags to keep", From 4c26465dde0635ffe2c90424d3153c2743d3a548 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:30:08 +0100 Subject: [PATCH 017/640] Update enfuse.lua added {5,0,0} to the check_version --- official/enfuse.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index d6ded05f..961793cd 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -37,7 +37,7 @@ local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("enfuse",dt.configuration.config_dir.."/lua/locale/") From 10c1eff1b67edd6e40f96e4a9d18acc1b0d1f0cc Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:33:40 +0100 Subject: [PATCH 018/640] Update generate_image_txt.lua added {5,0,0} to the check_version --- official/generate_image_txt.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index d127a5d6..8dcd5d1f 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -38,7 +38,7 @@ local dt = require "darktable" require "darktable.debug" require "official/yield" -dt.configuration.check_version(...,{2,1,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,1,0},{3,0,0},{4,0,0},{5,0,0}) dt.preferences.register("generate_image_txt", "enabled", From 2c77712ab4dd330acabe4b65a0ffdad7ee7f3dca Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:34:41 +0100 Subject: [PATCH 019/640] Update image_path_in_ui.lua added {5,0,0} to the check_version --- official/image_path_in_ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 03d9104b..b21a2186 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -29,7 +29,7 @@ This plugin will add a widget at the bottom of the left column in lighttable mod ]] local dt = require "darktable" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"} From d6e53cc00540d0c45cdac8018736b0eaa731c105 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:35:57 +0100 Subject: [PATCH 020/640] Update save_selection.lua added {5,0,0} to the check_version --- official/save_selection.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/save_selection.lua b/official/save_selection.lua index 3c87b45d..fd9f4f8d 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -34,7 +34,7 @@ increase it if you need more temporary selection buffers ]] local dt = require "darktable" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) local buffer_count = 5 From 67d92bd0702d6ff9fba2777bc1f5b8399694b006 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 2 Jan 2018 11:37:10 +0100 Subject: [PATCH 021/640] Update selection_to_pdf.lua added {5,0,0} to the check_version --- official/selection_to_pdf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index c56d4798..f44a8dcf 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -36,7 +36,7 @@ Plugin allows you to choose how many thumbnails you need per row local dt = require "darktable" require "official/yield" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) dt.preferences.register ("selection_to_pdf","Open with","string", From 664496b430ffbed166a26d647bf40e603e520782 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 2 Jan 2018 19:51:14 -0500 Subject: [PATCH 022/640] Updated to api 5.0.0 and tested. include_all.lua changed to load official/yield and ignore the lib and tools directories. --- include_all.lua | 13 ++++++++++--- tools/get_lib_manpages.lua | 2 +- tools/get_libdoc.lua | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include_all.lua b/include_all.lua index cbe3b2b2..c25dd54d 100644 --- a/include_all.lua +++ b/include_all.lua @@ -1,6 +1,7 @@ --[[ 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 @@ -33,14 +34,20 @@ Note that you need to restart DT for your changes to enabled scripts to take eff ]] local dt = require "darktable" local io = require "io" -dt.configuration.check_version(...,{3,0,0}) -local output = io.popen("cd "..dt.configuration.config_dir.."/lua ;find . -name \\*.lua -print") +-- 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 then + 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) diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 23400aa7..cea3bbc6 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -10,7 +10,7 @@ local df = require "lib/dtutils.file" local log = require "lib/dtutils.log" local libname = nil -dt.configuration.check_version(...,{3,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) local keys = {"Name", "Synopsis", "Usage", "Description", "Return_Value", "Limitations", "Example", "See_Also", "Reference", "License", "Copyright"} diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index de6615d6..42b19e46 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -6,7 +6,7 @@ local dt = require "darktable" -dt.configuration.check_version(...,{3,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) local keys = {"Name", "Synopsis", "Usage", "Description", "Return_Value", "Limitations", "Example", "See_Also", "Reference", "License", "Copyright"} From 2d9cdc5a24c869add1f67b02813a3ec6da012bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20V=C3=B6lker?= Date: Wed, 13 Sep 2017 17:16:57 +0200 Subject: [PATCH 023/640] GPX export script which generates a GPX track from all selected images containing geo information --- contrib/gpx_export.lua | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 contrib/gpx_export.lua diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua new file mode 100644 index 00000000..640809f8 --- /dev/null +++ b/contrib/gpx_export.lua @@ -0,0 +1,140 @@ +--[[ + This file is part of darktable, + copyright (c) 2017 Jannis_V + + 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 . +]] + +--[[ +Simple darktable GPX generator script + +This script generates a GPX track from all images having GPS latitude +and longitude information +]] + +local dt = require "darktable" +local df = require "lib/dtutils.file" +local dl = require "lib/dtutils" +local gettext = dt.gettext + +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("gpx_export", msgid) +end + +local path_entry = dt.new_widget("entry") +{ + text = dt.preferences.read("gpx_exporter", "gpxExportPath", "string"), + editable=true, + reset_callback = function(self) + self.text = "~/darktable.gpx" + dt.preferences.write("gpx_exporter", "gpxExportPath", "string", self.text) + end, + tooltip = _("gpx file path"), +} + +local function stop_job(job) + job.valid = false +end + +local function create_gpx_file() + dt.preferences.write("gpx_exporter", "gpxExportPath", "string", path_entry.text) + + path = path_entry.text:gsub("^~", os.getenv("HOME")) -- Expand ~ to home + path = path:gsub("//", "/") + + dt.print(_("exporting gpx file...")) + + job = dt.gui.create_job(_("gpx export"), true, stop_job) + + local gpx_file = "\n" + gpx_file = gpx_file.."\n" + gpx_file = gpx_file.."\t\n" + gpx_file = gpx_file.."\t\t\n"; + + local sel_images = dt.gui.action_images + for key,image in dl.spairs(sel_images, function(t, a, b) return t[b].exif_datetime_taken > t[a].exif_datetime_taken end) do + + if(job.valid) then + job.percent = (key - 1) / #sel_images + + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Just in case + ) then + + if(image.exif_datetime_taken == "") then + dt.print(image.path.."/"..image.filename.._(" does not have date information and won't be processed")) + print(image.path.."/"..image.filename.._(" does not have date information and won't be processed")) -- Also print to terminal + else + date_format = "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)" + my_year, my_month, my_day, my_hour, my_min, my_sec = image.exif_datetime_taken:match(date_format) + + local my_timestamp = os.time({year=my_year, month=my_month, day=my_day, hour=my_hour, min=my_min, sec=my_sec}) + + gpx_file = gpx_file.."\t\t\t\n" + gpx_file = gpx_file.."\t\t\t\t\n" + gpx_file = gpx_file.."\t\t\t\n" + end + end + else + break + end + end + + job.valid = false + + gpx_file = gpx_file.."\t\t\n"; + gpx_file = gpx_file.."\t\n"; + gpx_file = gpx_file.."\n"; + + local file = io.open(path, "w") + if (file == nil) then + dt.print(_("invalid path: ")..path) + else + file:write(gpx_file) + file:close() + dt.print(_("gpx file created: ")..path) + end +end + +dt.register_lib( + "gpx_exporter", + "gpx export", + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + dt.new_widget("box") + { + orientation = "vertical", + dt.new_widget("button") + { + label = _("export"), + tooltip = _("export gpx file"), + clicked_callback = create_gpx_file + }, + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label") + { + label = _("file:"), + }, + path_entry + }, + }, + nil,-- view_enter + nil -- view_leave +) From 92b5507e0efe410fa6dab4205851cdff31fe04c1 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Sun, 7 Jan 2018 00:37:41 -0600 Subject: [PATCH 024/640] Added 'Labels to Tags' script. --- contrib/LabelsToTags.lua | 225 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 contrib/LabelsToTags.lua diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua new file mode 100644 index 00000000..1135a96b --- /dev/null +++ b/contrib/LabelsToTags.lua @@ -0,0 +1,225 @@ +--[[ + LABELS TO TAGS + Allows the mass-application of tags using color labels and ratings + as a guide. + + AUTHOR + August Schwerdfeger (august@schwerdfeger.name) + + INSTALLATION + * Copy this file into $CONFIGDIR/lua/, where CONFIGDIR + is your darktable configuration directory + * Add the following line in the file $CONFIGDIR/luarc: + require "LabelsToTags" + + USAGE + In your 'luarc' file or elsewhere, use the function + 'register_tag_mapping', defined in this module, to specify + one or more tag mappings for use by the module. + Any mappings so registered will be selectable, according + to their given names, in the module's "mapping" combo box. + + A mapping takes the form of a table mapping patterns to + lists of tags. A pattern consists of 6 characters, of which + the first five represent color labels and the last the rating. + Each color label character may be '+', '-', or '*', + indicating that for this pattern to match, the corresponding + color label, respectively, must be on, must be off, or can be + either. Similarly, the rating character may be a numeral + between 0 and 5, "R" for rejected, or "*" for "any value." + + An example call to 'register_tag_mapping' is provided in a + comment at the end of this file. + + When the "Start" button is pressed, the module will + iterate over each selected image and check the state of + that image's color labels and rating against each pattern + defined in the selected mapping. For each pattern that + matches, the corresponding tags will be added to the + image. Any such tag not already existing in the database + will be created. + + LICENSE + LGPLv2+ + +]] +local darktable = require("darktable") +darktable.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) + +local LIB_ID = "LabelsToTags" + +-- Helper functions: BEGIN + +local function keySet(t) + local rv = {} + for k,_ in pairs(t) do + table.insert(rv,k) + end + table.sort(rv) + return(rv) +end + +local function generateLabelHash(img) + local hash = "" + hash = hash .. (img.red and "+" or "-") + hash = hash .. (img.yellow and "+" or "-") + hash = hash .. (img.green and "+" or "-") + hash = hash .. (img.blue and "+" or "-") + hash = hash .. (img.purple and "+" or "-") + hash = hash .. (img.rating == -1 and "R" or tostring(img.rating)) + return(hash) +end + +local function hashMatch(hash,pattern) + if #(hash) ~= #(pattern) then return(false) end + for i = 0,#hash do + if string.sub(hash,i,i) ~= string.sub(pattern,i,i) and + string.sub(pattern,i,i) ~= "*" then + return(false) + end + end + return(true) +end + +-- Helper functions: END + + + + +local initialAvailableMappings = { + ["Colors"] = { ["+*****"] = { "Red" }, + ["*+****"] = { "Yellow" }, + ["**+***"] = { "Green" }, + ["***+**"] = { "Blue" }, + ["****+*"] = { "Purple" } }, + ["Single colors"] = { ["+----*"] = { "Red", "Only red" }, + ["-+---*"] = { "Yellow", "Only yellow" }, + ["--+--*"] = { "Green", "Only green" }, + ["---+-*"] = { "Blue", "Only blue" }, + ["----+*"] = { "Purple", "Only purple" } }, + ["Ratings"] = { ["*****0"] = { "No stars", "Not rejected" }, + ["*****1"] = { "One star", "Not rejected" }, + ["*****2"] = { "Two stars", "Not rejected" }, + ["*****3"] = { "Three stars", "Not rejected" }, + ["*****4"] = { "Four stars", "Not rejected" }, + ["*****5"] = { "Five stars", "Not rejected" }, + ["*****R"] = { "Rejected" } } +} + +local availableMappings = {} + +local function getAvailableMappings() + if availableMappings == nil or next(availableMappings) == nil then + return(initialAvailableMappings) + else + return(availableMappings) + end +end + +local function getComboboxTooltip() + if availableMappings == nil or next(availableMappings) == nil then + return("No registered mappings -- using defaults") + else + return("Select a label-to-tag mapping") + end +end + +local mappingComboBox = darktable.new_widget("combobox"){ + label = "mapping", + value = 1, + tooltip = getComboboxTooltip(), + reset_callback = function(selfC) + if selfC == nil then + return + end + i = 1 + for _,m in pairs(keySet(getAvailableMappings())) do + selfC[i] = m + i = i+1 + end + n = #selfC + for j = i,n do + selfC[i] = nil + end + selfC.value = 1 + selfC.tooltip = getComboboxTooltip() + end, + unpack(keySet(getAvailableMappings())) +} + +local function doTagging(selfC) + local job = darktable.gui.create_job(string.format("labels to tags (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")",#(darktable.gui.action_images)),true) + job.percent = 0.0 + local pctIncrement = 1.0 / #(darktable.gui.action_images) + + local availableMappings = getAvailableMappings() + local memoizedTags = {} + for _,img in ipairs(darktable.gui.action_images) do + local tagsToApply = {} + local hash = generateLabelHash(img) + for k,v in pairs(availableMappings[mappingComboBox.value]) do + if hashMatch(hash,k) then + for _,tag in ipairs(v) do + tagsToApply[tag] = true + end + end + end + for k,_ in pairs(tagsToApply) do + if memoizedTags[k] == nil then + memoizedTags[k] = darktable.tags.create(k) + end + darktable.tags.attach(memoizedTags[k],img) + end + job.percent = job.percent + pctIncrement + end + job.valid = false +end + +local my_widget = darktable.new_widget("box") { + orientation = "vertical", + mappingComboBox, + darktable.new_widget("button") { + label = "start", + tooltip = "Tag all selected images", + clicked_callback = doTagging + } +} + +local PATTERN_PATTERN = "^[+*-][+*-][+*-][+*-][+*-][0-5R*]$" + +darktable.register_tag_mapping = function(name, mapping) + if availableMappings[name] ~= nil then + darktable.print_error("Tag mapping '" .. name .. "' already registered") + return + end + for pattern,tags in pairs(mapping) do + if string.match(pattern,PATTERN_PATTERN) == nil then + darktable.print_error("In tag mapping '" .. name .. "': Pattern '" .. pattern .. "' invalid") + return + end + for _,tag in ipairs(tags) do + if type(tag) ~= "string" then + darktable.print_error("In tag mapping '" .. name .. "': All tag mappings must be lists of strings") + return + end + end + end + availableMappings[name] = mapping + mappingComboBox.reset_callback(mappingComboBox) +end + +--[[ +darktable.register_tag_mapping("Example", + { ["+----*"] = { "Red", "Only red" }, + ["-+---*"] = { "Yellow", "Only yellow" }, + ["--+--*"] = { "Green", "Only green" }, + ["---+-*"] = { "Blue", "Only blue" }, + ["****+*"] = { "Purple" }, + ["----+*"] = { "Only purple" }, + ["*****1"] = { "One star" }, + ["*****R"] = { "Rejected" } }) +]] + +darktable.register_lib(LIB_ID,"labels to tags",true,true,{ + [darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20}, + },my_widget,nil,nil) From b406b36cda216a1927e14f9d89bfeb9ea5a78a4c Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 17:31:19 +0100 Subject: [PATCH 025/640] Added all Slovak and Czech accents --- contrib/kml_export.lua | 101 +++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index ab1f8c06..1ab8f783 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -82,57 +82,108 @@ end -- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/ function string.stripAccents( str ) local tableAccents = {} + -- A tableAccents["à"] = "a" - tableAccents["á"] = "a" - tableAccents["â"] = "a" - tableAccents["ã"] = "a" - tableAccents["ä"] = "a" - tableAccents["ç"] = "c" - tableAccents["è"] = "e" - tableAccents["é"] = "e" - tableAccents["ê"] = "e" - tableAccents["ë"] = "e" - tableAccents["ì"] = "i" - tableAccents["í"] = "i" - tableAccents["î"] = "i" - tableAccents["ï"] = "i" - tableAccents["ñ"] = "n" - tableAccents["ò"] = "o" - tableAccents["ó"] = "o" - tableAccents["ô"] = "o" - tableAccents["õ"] = "o" - tableAccents["ö"] = "o" - tableAccents["ù"] = "u" - tableAccents["ú"] = "u" - tableAccents["û"] = "u" - tableAccents["ü"] = "u" - tableAccents["ý"] = "y" - tableAccents["ÿ"] = "y" tableAccents["À"] = "A" + tableAccents["á"] = "a" tableAccents["Á"] = "A" + tableAccents["â"] = "a" tableAccents["Â"] = "A" + tableAccents["ã"] = "a" tableAccents["Ã"] = "A" + tableAccents["ä"] = "a" tableAccents["Ä"] = "A" + -- B + -- C + tableAccents["ç"] = "c" tableAccents["Ç"] = "C" + tableAccents["č"] = "c" + tableAccents["Č"] = "C" + -- D + tableAccents["ď"] = "d" + tableAccents["Ď"] = "d" + -- E + tableAccents["è"] = "e" tableAccents["È"] = "E" + tableAccents["é"] = "e" tableAccents["É"] = "E" + tableAccents["ê"] = "e" tableAccents["Ê"] = "E" + tableAccents["ë"] = "e" tableAccents["Ë"] = "E" + tableAccents["ě"] = "e" + tableAccents["Ě"] = "E" + -- F + -- G + -- H + -- I + tableAccents["ì"] = "i" tableAccents["Ì"] = "I" + tableAccents["í"] = "i" tableAccents["Í"] = "I" + tableAccents["î"] = "i" tableAccents["Î"] = "I" + tableAccents["ï"] = "i" tableAccents["Ï"] = "I" + -- J + -- K + -- L + tableAccents["ĺ"] = "l" + tableAccents["Ĺ"] = "L" + tableAccents["ľ"] = "l" + tableAccents["Ľ"] = "L" + -- M + -- N + tableAccents["ñ"] = "n" tableAccents["Ñ"] = "N" + tableAccents["ň"] = "n" + tableAccents["Ň"] = "N" + -- O + tableAccents["ò"] = "o" tableAccents["Ò"] = "O" + tableAccents["ó"] = "o" tableAccents["Ó"] = "O" + tableAccents["ô"] = "o" tableAccents["Ô"] = "O" + tableAccents["õ"] = "o" tableAccents["Õ"] = "O" + tableAccents["ö"] = "o" tableAccents["Ö"] = "O" + -- P + -- Q + -- R + tableAccents["ŕ"] = "r" + tableAccents["Ŕ"] = "R" + tableAccents["ř"] = "r" + tableAccents["Ř"] = "R" + -- S + tableAccents["š"] = "s" + tableAccents["Š"] = "S" + -- T + tableAccents["ť"] = "t" + tableAccents["Ť"] = "T" + -- U + tableAccents["ù"] = "u" tableAccents["Ù"] = "U" + tableAccents["ú"] = "u" tableAccents["Ú"] = "U" + tableAccents["û"] = "u" tableAccents["Û"] = "U" + tableAccents["ü"] = "u" tableAccents["Ü"] = "U" + tableAccents["ů"] = "u" + tableAccents["Ů"] = "U" + -- V + -- W + -- X + -- Y + tableAccents["ý"] = "y" tableAccents["Ý"] = "Y" + tableAccents["ÿ"] = "y" + tableAccents["Ÿ"] = "Y" + -- Z + tableAccents["ž"] = "z" + tableAccents["Ž"] = "Z" local normalizedString = "" From d2977183582f6738eb01edd9a8bb7f57601c228b Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 17:40:50 +0100 Subject: [PATCH 026/640] Path is now sorted by exif_datetime_taken --- contrib/kml_export.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 1ab8f783..f2e56667 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -357,7 +357,7 @@ local function create_kml_file(storage, image_table, extra_data) kml_file = kml_file.." \n" kml_file = kml_file.." \n" - for image,exported_image in spairs(image_table, function(t,a,b) return t[b] < t[a] end) do + for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then From e9d0f706edc96cd31d493f8edfda4015fc58441c Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 17:41:26 +0100 Subject: [PATCH 027/640] Correct handling of duplicates --- contrib/kml_export.lua | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index f2e56667..b2404454 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -213,6 +213,20 @@ function string.escapeXmlCharacters( str ) return str end +-- Add duplicate index to filename +-- image.filename does not have index, exported_image has index +function addDuplicateIndex( index, filename ) + if index > 0 then + filename = filename.."_" + if index < 10 then + filename = filename.."0" + end + filename = filename..index + end + + return filename +end + local function create_kml_file(storage, image_table, extra_data) if not df.check_if_bin_exists("mkdir") then dt.print_error(_("mkdir not found")) @@ -297,6 +311,8 @@ local function create_kml_file(storage, image_table, extra_data) for image,exported_image in pairs(image_table) do -- Extract filename, e.g DSC9784.ARW -> DSC9784 filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG extension = string.match(exported_image,"%.%w*$") @@ -309,7 +325,7 @@ local function create_kml_file(storage, image_table, extra_data) if (image.title and image.title ~= "") then image_title = string.escapeXmlCharacters(image.title) else - image_title = image.filename + image_title = filename..extension end -- Characters should not be escaped in CDATA, but we are using HTML fragment, so we must escape them image_description = string.escapeXmlCharacters(image.description) @@ -396,7 +412,8 @@ local function create_kml_file(storage, image_table, extra_data) (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images end From 0c1de20a1ac5c284da9f025fc88434cec80fa203 Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 17:56:02 +0100 Subject: [PATCH 028/640] Code formatting --- contrib/kml_export.lua | 190 +++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 94 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index b2404454..58e0a15a 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -1,7 +1,7 @@ --[[ This file is part of darktable, - Copyright 2016 by Tobias Jakobs. - Copyright 2016 by Erik Augustin. + Copyright 2018 by Tobias Jakobs. + Copyright 2018 by Erik Augustin. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -81,7 +81,7 @@ end -- Strip accents from a string -- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/ function string.stripAccents( str ) - local tableAccents = {} + local tableAccents = {} -- A tableAccents["à"] = "a" tableAccents["À"] = "A" @@ -185,18 +185,17 @@ function string.stripAccents( str ) tableAccents["ž"] = "z" tableAccents["Ž"] = "Z" - local normalizedString = "" + local normalizedString = "" - for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do - if tableAccents[strChar] ~= nil then - normalizedString = normalizedString..tableAccents[strChar] - else - normalizedString = normalizedString..strChar + for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do + if tableAccents[strChar] ~= nil then + normalizedString = normalizedString..tableAccents[strChar] + else + normalizedString = normalizedString..strChar + end end - end - - return normalizedString + return normalizedString end -- Escape XML characters @@ -245,7 +244,7 @@ local function create_kml_file(storage, image_table, extra_data) return end - dt.print_error("Will try to export KML file now") + dt.print_log("Will try to export KML file now") local imageFoldername if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then @@ -265,7 +264,6 @@ local function create_kml_file(storage, image_table, extra_data) dt.control.execute(mkdirCommand) end - -- Create the thumbnails for image,exported_image in pairs(image_table) do if ((image.longitude and image.latitude) and @@ -275,11 +273,11 @@ local function create_kml_file(storage, image_table, extra_data) filename = string.upper(string.gsub(filename,"%.%w*", "")) -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg - -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to - -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the - -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It - -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other - -- profiles that might be present in the input and aren't needed in the thumbnail. + -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to + -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the + -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It + -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other + -- profiles that might be present in the input and aren't needed in the thumbnail. local convertToThumbCommand = "convert -size 96x96 "..exported_image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg" dt.control.execute(convertToThumbCommand) @@ -309,14 +307,14 @@ local function create_kml_file(storage, image_table, extra_data) kml_file = kml_file.." Exported from darktable\n" for image,exported_image in pairs(image_table) do - -- Extract filename, e.g DSC9784.ARW -> DSC9784 - filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - -- Handle duplicates - filename = addDuplicateIndex( image.duplicate_index, filename ) - -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG - extension = string.match(exported_image,"%.%w*$") - - if ((image.longitude and image.latitude) and + -- Extract filename, e.g DSC9784.ARW -> DSC9784 + filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) + -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG + extension = string.match(exported_image,"%.%w*$") + + if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then kml_file = kml_file.." \n" @@ -357,37 +355,39 @@ local function create_kml_file(storage, image_table, extra_data) end end --- Connects all images with an path + -- Connects all images with an path if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then - kml_file = kml_file.." \n" - kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice - --kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local altitude = 0; - if (image.elevation) then - altitude = image.elevation; - end - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" - end - end - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice + --kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local altitude = 0; + if (image.elevation) then + altitude = image.elevation; + end + + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" + end + end + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" end kml_file = kml_file.."\n" @@ -399,77 +399,79 @@ local function create_kml_file(storage, image_table, extra_data) dt.print("KML file created in "..exportDirectory) --- Compress the files to create a KMZ file + -- Compress the files to create a KMZ file if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") local createKMZCommand = "zip --test --move --junk-paths " createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - -- Handle duplicates - filename = addDuplicateIndex( image.duplicate_index, filename ) - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails - createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images - end + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) + + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails + createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images + end end - dt.control.execute(createKMZCommand) + dt.control.execute(createKMZCommand) end --- Open the file with the standard programm + -- Open the file with the standard programm if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then - local kmlFileOpenCommand + local kmlFileOpenCommand if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" else kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" - end + end dt.control.execute(kmlFileOpenCommand) end - end -- Preferences dt.preferences.register("kml_export", - "OpenKmlFile", - "bool", - _("KML export: Open KML/KMZ file after export"), - _("Opens the KML file after the export with the standard program for KML files"), - false ) + "OpenKmlFile", + "bool", + _("KML export: Open KML/KMZ file after export"), + _("Opens the KML file after the export with the standard program for KML files"), + false ) local handle = io.popen("xdg-user-dir DESKTOP") local result = handle:read() if (result == nil) then - result = "" + result = "" end handle:close() + dt.preferences.register("kml_export", - "ExportDirectory", - "directory", - _("KML export: Export directory"), - _("A directory that will be used to export the KML/KMZ files"), - result ) + "ExportDirectory", + "directory", + _("KML export: Export directory"), + _("A directory that will be used to export the KML/KMZ files"), + result ) dt.preferences.register("kml_export", - "CreatePath", - "bool", - _("KML export: Connect images with path"), - _("connect all images with a path"), - false ) + "CreatePath", + "bool", + _("KML export: Connect images with path"), + _("connect all images with a path"), + false ) + dt.preferences.register("kml_export", - "CreateKMZ", - "bool", - _("KML export: Create KMZ file"), - _("Compress all imeges to one KMZ file"), - true ) + "CreateKMZ", + "bool", + _("KML export: Create KMZ file"), + _("Compress all imeges to one KMZ file"), + true ) -- Register dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) From f86b16735b3d4aa3d1a283dc0028f795832af994 Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 22:54:22 +0100 Subject: [PATCH 029/640] Formatted code to follow project settings --- contrib/kml_export.lua | 739 +++++++++++++++++++++-------------------- 1 file changed, 371 insertions(+), 368 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 58e0a15a..070a02fa 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -1,20 +1,20 @@ --[[ - This file is part of darktable, - Copyright 2018 by Tobias Jakobs. - Copyright 2018 by Erik Augustin. - - This program 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. - - This program 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 this program. If not, see . + This file is part of darktable, + Copyright 2018 by Tobias Jakobs. + Copyright 2018 by Erik Augustin. + + This program 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. + + This program 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 this program. If not, see . ]] --[[ darktable KML export script @@ -47,155 +47,155 @@ dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("kml_export", msgid) + return gettext.dgettext("kml_export", msgid) end -- Sort a table local function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua - -- collect the keys - local keys = {} - for _key in pairs(_table) do keys[#keys + 1] = _key end - - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(_table, a, b) end) - else - table.sort(keys) - end - - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keys[i], _table[keys[i]] - end + -- collect the keys + local keys = {} + for _key in pairs(_table) do keys[#keys + 1] = _key end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(_table, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], _table[keys[i]] end + end end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) + dt.print(string.format(_("Export Image %i/%i"), number, total)) end -- Strip accents from a string -- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/ function string.stripAccents( str ) - local tableAccents = {} - -- A - tableAccents["à"] = "a" - tableAccents["À"] = "A" - tableAccents["á"] = "a" - tableAccents["Á"] = "A" - tableAccents["â"] = "a" - tableAccents["Â"] = "A" - tableAccents["ã"] = "a" - tableAccents["Ã"] = "A" - tableAccents["ä"] = "a" - tableAccents["Ä"] = "A" - -- B - -- C - tableAccents["ç"] = "c" - tableAccents["Ç"] = "C" - tableAccents["č"] = "c" - tableAccents["Č"] = "C" - -- D - tableAccents["ď"] = "d" - tableAccents["Ď"] = "d" - -- E - tableAccents["è"] = "e" - tableAccents["È"] = "E" - tableAccents["é"] = "e" - tableAccents["É"] = "E" - tableAccents["ê"] = "e" - tableAccents["Ê"] = "E" - tableAccents["ë"] = "e" - tableAccents["Ë"] = "E" - tableAccents["ě"] = "e" - tableAccents["Ě"] = "E" - -- F - -- G - -- H - -- I - tableAccents["ì"] = "i" - tableAccents["Ì"] = "I" - tableAccents["í"] = "i" - tableAccents["Í"] = "I" - tableAccents["î"] = "i" - tableAccents["Î"] = "I" - tableAccents["ï"] = "i" - tableAccents["Ï"] = "I" - -- J - -- K - -- L - tableAccents["ĺ"] = "l" - tableAccents["Ĺ"] = "L" - tableAccents["ľ"] = "l" - tableAccents["Ľ"] = "L" - -- M - -- N - tableAccents["ñ"] = "n" - tableAccents["Ñ"] = "N" - tableAccents["ň"] = "n" - tableAccents["Ň"] = "N" - -- O - tableAccents["ò"] = "o" - tableAccents["Ò"] = "O" - tableAccents["ó"] = "o" - tableAccents["Ó"] = "O" - tableAccents["ô"] = "o" - tableAccents["Ô"] = "O" - tableAccents["õ"] = "o" - tableAccents["Õ"] = "O" - tableAccents["ö"] = "o" - tableAccents["Ö"] = "O" - -- P - -- Q - -- R - tableAccents["ŕ"] = "r" - tableAccents["Ŕ"] = "R" - tableAccents["ř"] = "r" - tableAccents["Ř"] = "R" - -- S - tableAccents["š"] = "s" - tableAccents["Š"] = "S" - -- T - tableAccents["ť"] = "t" - tableAccents["Ť"] = "T" - -- U - tableAccents["ù"] = "u" - tableAccents["Ù"] = "U" - tableAccents["ú"] = "u" - tableAccents["Ú"] = "U" - tableAccents["û"] = "u" - tableAccents["Û"] = "U" - tableAccents["ü"] = "u" - tableAccents["Ü"] = "U" - tableAccents["ů"] = "u" - tableAccents["Ů"] = "U" - -- V - -- W - -- X - -- Y - tableAccents["ý"] = "y" - tableAccents["Ý"] = "Y" - tableAccents["ÿ"] = "y" - tableAccents["Ÿ"] = "Y" - -- Z - tableAccents["ž"] = "z" - tableAccents["Ž"] = "Z" - - local normalizedString = "" - - for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do - if tableAccents[strChar] ~= nil then - normalizedString = normalizedString..tableAccents[strChar] - else - normalizedString = normalizedString..strChar - end + local tableAccents = {} + -- A + tableAccents["à"] = "a" + tableAccents["À"] = "A" + tableAccents["á"] = "a" + tableAccents["Á"] = "A" + tableAccents["â"] = "a" + tableAccents["Â"] = "A" + tableAccents["ã"] = "a" + tableAccents["Ã"] = "A" + tableAccents["ä"] = "a" + tableAccents["Ä"] = "A" + -- B + -- C + tableAccents["ç"] = "c" + tableAccents["Ç"] = "C" + tableAccents["č"] = "c" + tableAccents["Č"] = "C" + -- D + tableAccents["ď"] = "d" + tableAccents["Ď"] = "d" + -- E + tableAccents["è"] = "e" + tableAccents["È"] = "E" + tableAccents["é"] = "e" + tableAccents["É"] = "E" + tableAccents["ê"] = "e" + tableAccents["Ê"] = "E" + tableAccents["ë"] = "e" + tableAccents["Ë"] = "E" + tableAccents["ě"] = "e" + tableAccents["Ě"] = "E" + -- F + -- G + -- H + -- I + tableAccents["ì"] = "i" + tableAccents["Ì"] = "I" + tableAccents["í"] = "i" + tableAccents["Í"] = "I" + tableAccents["î"] = "i" + tableAccents["Î"] = "I" + tableAccents["ï"] = "i" + tableAccents["Ï"] = "I" + -- J + -- K + -- L + tableAccents["ĺ"] = "l" + tableAccents["Ĺ"] = "L" + tableAccents["ľ"] = "l" + tableAccents["Ľ"] = "L" + -- M + -- N + tableAccents["ñ"] = "n" + tableAccents["Ñ"] = "N" + tableAccents["ň"] = "n" + tableAccents["Ň"] = "N" + -- O + tableAccents["ò"] = "o" + tableAccents["Ò"] = "O" + tableAccents["ó"] = "o" + tableAccents["Ó"] = "O" + tableAccents["ô"] = "o" + tableAccents["Ô"] = "O" + tableAccents["õ"] = "o" + tableAccents["Õ"] = "O" + tableAccents["ö"] = "o" + tableAccents["Ö"] = "O" + -- P + -- Q + -- R + tableAccents["ŕ"] = "r" + tableAccents["Ŕ"] = "R" + tableAccents["ř"] = "r" + tableAccents["Ř"] = "R" + -- S + tableAccents["š"] = "s" + tableAccents["Š"] = "S" + -- T + tableAccents["ť"] = "t" + tableAccents["Ť"] = "T" + -- U + tableAccents["ù"] = "u" + tableAccents["Ù"] = "U" + tableAccents["ú"] = "u" + tableAccents["Ú"] = "U" + tableAccents["û"] = "u" + tableAccents["Û"] = "U" + tableAccents["ü"] = "u" + tableAccents["Ü"] = "U" + tableAccents["ů"] = "u" + tableAccents["Ů"] = "U" + -- V + -- W + -- X + -- Y + tableAccents["ý"] = "y" + tableAccents["Ý"] = "Y" + tableAccents["ÿ"] = "y" + tableAccents["Ÿ"] = "Y" + -- Z + tableAccents["ž"] = "z" + tableAccents["Ž"] = "Z" + + local normalizedString = "" + + for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do + if tableAccents[strChar] ~= nil then + normalizedString = normalizedString..tableAccents[strChar] + else + normalizedString = normalizedString..strChar end + end - return normalizedString + return normalizedString end -- Escape XML characters @@ -203,275 +203,278 @@ end -- https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents function string.escapeXmlCharacters( str ) - str = string.gsub(str,"&", "&") - str = string.gsub(str,"\"", """) - str = string.gsub(str,"'", "'") - str = string.gsub(str,"<", "<") - str = string.gsub(str,">", ">") + str = string.gsub(str,"&", "&") + str = string.gsub(str,"\"", """) + str = string.gsub(str,"'", "'") + str = string.gsub(str,"<", "<") + str = string.gsub(str,">", ">") - return str + return str end -- Add duplicate index to filename -- image.filename does not have index, exported_image has index function addDuplicateIndex( index, filename ) - if index > 0 then - filename = filename.."_" - if index < 10 then - filename = filename.."0" - end - filename = filename..index + if index > 0 then + filename = filename.."_" + if index < 10 then + filename = filename.."0" end + filename = filename..index + end - return filename + return filename end local function create_kml_file(storage, image_table, extra_data) - if not df.check_if_bin_exists("mkdir") then - dt.print_error(_("mkdir not found")) - return - end - if not df.check_if_bin_exists("convert") then - dt.print_error(_("convert not found")) - return - end - if not df.check_if_bin_exists("xdg-open") then - dt.print_error(_("xdg-open not found")) - return - end - if not df.check_if_bin_exists("xdg-user-dir") then - dt.print_error(_("xdg-user-dir not found")) - return + if not df.check_if_bin_exists("mkdir") then + dt.print_error(_("mkdir not found")) + return + end + if not df.check_if_bin_exists("convert") then + dt.print_error(_("convert not found")) + return + end + if not df.check_if_bin_exists("xdg-open") then + dt.print_error(_("xdg-open not found")) + return + end + if not df.check_if_bin_exists("xdg-user-dir") then + dt.print_error(_("xdg-user-dir not found")) + return + end + + dt.print_error("Will try to export KML file now") + + local imageFoldername + if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then + if not df.check_if_bin_exists("zip") then + dt.print_error(_("zip not found")) + return end - dt.print_log("Will try to export KML file now") + exportDirectory = dt.configuration.tmp_dir + imageFoldername = "" + else + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") + + -- Creates dir if not exsists + imageFoldername = "files/" + local mkdirCommand = "mkdir -p "..exportDirectory.."/"..imageFoldername + dt.control.execute(mkdirCommand) + end + + -- Create the thumbnails + for image,exported_image in pairs(image_table) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$") + filename = string.upper(string.gsub(filename,"%.%w*", "")) + + -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg + -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to + -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the + -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It + -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other + -- profiles that might be present in the input and aren't needed in the thumbnail. + + local convertToThumbCommand = "convert -size 96x96 "..exported_image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg" + dt.control.execute(convertToThumbCommand) + else + -- Remove exported image if it has no GPS data + os.remove(exported_image) + end - local imageFoldername - if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - if not df.check_if_bin_exists("zip") then - dt.print_error(_("zip not found")) - return + local pattern = "[/]?([^/]+)$" + filmName = string.match(image.film.path, pattern) + + -- Strip accents from the filename, because GoogleEarth can't open them + -- https://github.com/darktable-org/lua-scripts/issues/54 + filmName = string.stripAccents(filmName) + end + + exportKMLFilename = filmName..".kml" + exportKMZFilename = filmName..".kmz" + + -- Create the KML file + local kml_file = "\n" + kml_file = kml_file.."\n" + kml_file = kml_file.."\n" + + --image_table = dt.gui.selection(); + kml_file = kml_file..""..filmName.."\n" + kml_file = kml_file.." Exported from darktable\n" + + for image,exported_image in pairs(image_table) do + -- Extract filename, e.g DSC9784.ARW -> DSC9784 + filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) + -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG + extension = string.match(exported_image,"%.%w*$") + + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + kml_file = kml_file.." \n" + + local image_title, image_description + if (image.title and image.title ~= "") then + image_title = string.escapeXmlCharacters(image.title) + else + image_title = filename..extension + end + -- Characters should not be escaped in CDATA, but we are using HTML fragment, so we must escape them + image_description = string.escapeXmlCharacters(image.description) + + kml_file = kml_file.." "..image_title.."\n" + kml_file = kml_file.." "..image_description.."\n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." 1\n" + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n" + kml_file = kml_file.." \n" + kml_file = kml_file.." "..string.gsub(image.exif_datetime_taken," ", "T").."Z".."\n" + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + end + end + + -- Connects all images with an path + if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then + kml_file = kml_file.." \n" + kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice + --kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local altitude = 0; + if (image.elevation) then + altitude = image.elevation; end - exportDirectory = dt.configuration.tmp_dir - imageFoldername = "" - else - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - - -- Creates dir if not exsists - imageFoldername = "files/" - local mkdirCommand = "mkdir -p "..exportDirectory.."/"..imageFoldername - dt.control.execute(mkdirCommand) + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" + end end - -- Create the thumbnails - for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$") - filename = string.upper(string.gsub(filename,"%.%w*", "")) - - -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg - -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to - -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the - -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It - -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other - -- profiles that might be present in the input and aren't needed in the thumbnail. - - local convertToThumbCommand = "convert -size 96x96 "..exported_image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg" - dt.control.execute(convertToThumbCommand) - else - -- Remove exported image if it has no GPS data - os.remove(exported_image) - end + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" - local pattern = "[/]?([^/]+)$" - filmName = string.match(image.film.path, pattern) + kml_file = kml_file.." \n" + end - -- Strip accents from the filename, because GoogleEarth can't open them - -- https://github.com/darktable-org/lua-scripts/issues/54 - filmName = string.stripAccents(filmName) - end + kml_file = kml_file.."\n" + kml_file = kml_file.."" + + local file = io.open(exportDirectory.."/"..exportKMLFilename, "w") + file:write(kml_file) + file:close() - exportKMLFilename = filmName..".kml" - exportKMZFilename = filmName..".kmz" + dt.print("KML file created in "..exportDirectory) - -- Create the KML file - local kml_file = "\n" - kml_file = kml_file.."\n" - kml_file = kml_file.."\n" + -- Compress the files to create a KMZ file + if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - --image_table = dt.gui.selection(); - kml_file = kml_file..""..filmName.."\n" - kml_file = kml_file.." Exported from darktable\n" + local createKMZCommand = "zip --test --move --junk-paths " + createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file for image,exported_image in pairs(image_table) do - -- Extract filename, e.g DSC9784.ARW -> DSC9784 - filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) -- Handle duplicates filename = addDuplicateIndex( image.duplicate_index, filename ) - -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG - extension = string.match(exported_image,"%.%w*$") - - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - kml_file = kml_file.." \n" - - local image_title, image_description - if (image.title and image.title ~= "") then - image_title = string.escapeXmlCharacters(image.title) - else - image_title = filename..extension - end - -- Characters should not be escaped in CDATA, but we are using HTML fragment, so we must escape them - image_description = string.escapeXmlCharacters(image.description) - - kml_file = kml_file.." "..image_title.."\n" - kml_file = kml_file.." "..image_description.."\n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." 1\n" - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n" - kml_file = kml_file.." \n" - kml_file = kml_file.." "..string.gsub(image.exif_datetime_taken," ", "T").."Z".."\n" - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - end - end - -- Connects all images with an path - if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then - kml_file = kml_file.." \n" - kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice - --kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local altitude = 0; - if (image.elevation) then - altitude = image.elevation; - end - - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" - end - end - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails + createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images + end end - kml_file = kml_file.."\n" - kml_file = kml_file.."" - - local file = io.open(exportDirectory.."/"..exportKMLFilename, "w") - file:write(kml_file) - file:close() + dt.control.execute(createKMZCommand) + end - dt.print("KML file created in "..exportDirectory) + -- Open the file with the standard programm + if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then + local kmlFileOpenCommand - -- Compress the files to create a KMZ file if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - - local createKMZCommand = "zip --test --move --junk-paths " - createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file - - for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - -- Handle duplicates - filename = addDuplicateIndex( image.duplicate_index, filename ) - - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails - createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images - end - end - - dt.control.execute(createKMZCommand) - end - - -- Open the file with the standard programm - if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then - local kmlFileOpenCommand - - if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" - else - kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" - end - dt.control.execute(kmlFileOpenCommand) + kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" + else + kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" end + dt.control.execute(kmlFileOpenCommand) + end end -- Preferences dt.preferences.register("kml_export", - "OpenKmlFile", - "bool", - _("KML export: Open KML/KMZ file after export"), - _("Opens the KML file after the export with the standard program for KML files"), - false ) + "OpenKmlFile", + "bool", + _("KML export: Open KML/KMZ file after export"), + _("Opens the KML file after the export with the standard program for KML files"), + false ) local handle = io.popen("xdg-user-dir DESKTOP") local result = handle:read() if (result == nil) then - result = "" + result = "" end handle:close() dt.preferences.register("kml_export", - "ExportDirectory", - "directory", - _("KML export: Export directory"), - _("A directory that will be used to export the KML/KMZ files"), - result ) + "ExportDirectory", + "directory", + _("KML export: Export directory"), + _("A directory that will be used to export the KML/KMZ files"), + result ) dt.preferences.register("kml_export", - "CreatePath", - "bool", - _("KML export: Connect images with path"), - _("connect all images with a path"), - false ) + "CreatePath", + "bool", + _("KML export: Connect images with path"), + _("connect all images with a path"), + false ) dt.preferences.register("kml_export", - "CreateKMZ", - "bool", - _("KML export: Create KMZ file"), - _("Compress all imeges to one KMZ file"), - true ) + "CreateKMZ", + "bool", + _("KML export: Create KMZ file"), + _("Compress all imeges to one KMZ file"), + true ) -- Register dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua; From 493dcc7ef7131b2b75111011a4e0060edf4f9c77 Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Wed, 17 Jan 2018 10:41:55 +0100 Subject: [PATCH 030/640] Don't delete tags while iterating --- official/delete_long_tags.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 3e2378b7..5a2da73c 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2014 Tobias Ellinghaus + copyright (c) 2014--2018 Tobias Ellinghaus darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ ]] --[[ DELETE LONG TAGS -A simple script that will automatically delete all tag longer than a set length +A simple script that will automatically delete all tags longer than a set length USAGE * require this script from your main lua file @@ -38,10 +38,18 @@ dt.preferences.register("delete_long_tags", "length", "integer", local max_length = dt.preferences.read("delete_long_tags", "length", "integer") +-- deleting while iterating the tags list seems to break the iterator! +local long_tags = {} + for _,t in ipairs(dt.tags) do local len = #t.name if len > max_length then print("deleting tag `"..t.name.."' (length: "..len..")") - t:delete() + table.insert(long_tags, t.name) end end + +for _,name in pairs(long_tags) do + tag = dt.tags.find(name) + tag:delete() +end From 95077f639b0345f35f8fb810190202b86c55e88b Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Wed, 17 Jan 2018 10:42:44 +0100 Subject: [PATCH 031/640] New script to delete unused tags on startup --- official/delete_unused_tags.lua | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 official/delete_unused_tags.lua diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua new file mode 100644 index 00000000..337f5f64 --- /dev/null +++ b/official/delete_unused_tags.lua @@ -0,0 +1,46 @@ +--[[ + This file is part of darktable, + copyright (c) 2018 Tobias Ellinghaus + + 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 . +]] +--[[ +DELETE UNUSED TAGS +A simple script that will automatically delete all tags that are not attached to any images + +USAGE +* require this script from your main lua file +* restart darktable + +all tags that are not used will be automatically deleted at every restart +]] + +local dt = require "darktable" + +dt.configuration.check_version(...,{5,0,0}) + +-- deleting while iterating the tags list seems to break the iterator! +local unused_tags = {} + +for _, t in ipairs(dt.tags) do + if #t == 0 then + table.insert(unused_tags, t.name) + end +end + +for _,name in pairs(unused_tags) do + print("deleting tag `" .. name .. "'") + tag = dt.tags.find(name) + tag:delete() +end From 54572de8d9dfb4b618ee39ebde358b09b9714878 Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Tue, 23 Jan 2018 11:28:45 +0100 Subject: [PATCH 032/640] Fix LabelsToTags for Lua 5.3 Fixes #106 --- contrib/LabelsToTags.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 1135a96b..431760e5 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -43,9 +43,13 @@ LGPLv2+ ]] + local darktable = require("darktable") darktable.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +-- Lua 5.3 no longer has "unpack" but "table.unpack" +unpack = unpack or table.unpack + local LIB_ID = "LabelsToTags" -- Helper functions: BEGIN @@ -151,7 +155,7 @@ local function doTagging(selfC) local job = darktable.gui.create_job(string.format("labels to tags (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")",#(darktable.gui.action_images)),true) job.percent = 0.0 local pctIncrement = 1.0 / #(darktable.gui.action_images) - + local availableMappings = getAvailableMappings() local memoizedTags = {} for _,img in ipairs(darktable.gui.action_images) do From 5d57347730a1278f89bfabba2c7acec96e2e208b Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Thu, 22 Feb 2018 16:01:54 -0800 Subject: [PATCH 033/640] fixed a couple dtutils_file functions for windows platform --- lib/dtutils/file.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 617234b5..bc215e3c 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -51,7 +51,13 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local result = os.execute("which " .. bin) + local cmd + if package.config:sub(1,1) == '/' then + cmd = 'which ' + else + cmd = 'where ' + end + local result = os.execute(cmd .. bin) if not result then result = false end @@ -194,10 +200,13 @@ dtutils_file.libdoc.functions["check_if_file_exists"] = { } function dtutils_file.check_if_file_exists(filepath) - local result = os.execute("test -e " .. filepath) - if not result then - result = false + local file = io.open(filepath, "r") + local result = false + if file then + result = true + file:close() end + return result end @@ -384,7 +393,7 @@ function dtutils_file.create_unique_filename(filepath) while dtutils_file.check_if_file_exists(filepath) do filepath = dtutils_file.filename_increment(filepath) -- limit to 99 more exports of the original export - if string.match(dtfileutils.get_basename(filepath), "_(d-)$") == "99" then + if string.match(dtutils_file.get_basename(filepath), "_(d-)$") == "99" then break end end From 4ad9e77a7e0a0c86a9837e1212c7fd6ecdfe4787 Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Thu, 22 Feb 2018 16:07:28 -0800 Subject: [PATCH 034/640] improved a few aspects of the hugin script: * handle stiching all from hugin_executor without the gui * automatically create the panorama file name based on first selected file plus _pano * automatically detects if output file exists, if so use an unique name * delete temporarily exported file --- contrib/hugin.lua | 51 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index d69a8ad7..9008b157 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -71,38 +71,59 @@ local function create_panorama(storage, image_table, extra_data) --finalize -- list of exported images local img_list + local img_set = {} -- reset and create image list img_list = "" - - for _,v in pairs(image_table) do + for k,v in pairs(image_table) do img_list = img_list ..v.. " " + table.insert(img_set, k) end - dt.print(_("Will try to stitch now")) + -- use first file as basename + table.sort(img_set, function(a,b) return a.filename Date: Fri, 23 Feb 2018 18:14:24 -0800 Subject: [PATCH 035/640] platform dependent implementation of check_if_bin_exists and check_if_file_exists --- lib/dtutils/file.lua | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index bc215e3c..22cd5e56 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -51,16 +51,17 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local cmd - if package.config:sub(1,1) == '/' then - cmd = 'which ' + local result + if (dt.configuration.running_os == 'linux') then + result = os.execute("which "..bin) else - cmd = 'where ' + result = dtutils_file.check_if_file_exists(bin) end - local result = os.execute(cmd .. bin) + if not result then result = false end + return result end @@ -200,11 +201,26 @@ dtutils_file.libdoc.functions["check_if_file_exists"] = { } function dtutils_file.check_if_file_exists(filepath) - local file = io.open(filepath, "r") - local result = false - if file then - result = true - file:close() + local result + if (dt.configuration.running_os == 'windows') then + filepath = string.gsub(filepath, '[\\/]+', '\\') + result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)') + if not result then + result = false + end + elseif (dt.configuration.running_os == "linux") then + result = os.execute('test -e ' .. filepath) + if not result then + result = false + end + else + local file = io.open(filepath, "r") + if file then + result = true + file:close() + else + result = false + end end return result @@ -400,4 +416,4 @@ function dtutils_file.create_unique_filename(filepath) return filepath end -return dtutils_file +return dtutils_file \ No newline at end of file From fe942100a40691d3b2250b5125b9984e3231dca5 Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Fri, 23 Feb 2018 10:07:45 -0800 Subject: [PATCH 036/640] hugin plugin improvements * added preference requiring user to specify the paths for hugin, hugin_executor and pto_gen needed for this plguin * added preference to allow user to choose to launch hugin in GUI mode * minor fix to the way files are handled; due to some versions of hugin_executor not writing out to the path specified in --prefix, assume we are working in the tmp directory and then move the file afterwards --- contrib/hugin.lua | 111 ++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 42 deletions(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 9008b157..477e5060 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -28,7 +28,9 @@ ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT * hugin USAGE -* require this file from your main luarc config file. +* require this file from your main luarc config file +* set the hugin tool paths in preferences +* if hugin gui mode is used, save the final result in the tmp directory with the first file name and _pano as suffix for the image to be automatically imported to DT afterwards This plugin will add a new storage option and calls hugin after export. ]] @@ -37,6 +39,7 @@ local dt = require "darktable" local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext +local namespace = 'module_hugin' -- works with darktable API version from 2.0.0 to 5.0.0 dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) @@ -45,28 +48,33 @@ dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("hugin", msgid) + return gettext.dgettext("hugin", msgid) end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print("Export to Hugin "..tostring(number).."/"..tostring(total)) + dt.print("exporting to Hugin: "..tostring(number).."/"..tostring(total)) end local function create_panorama(storage, image_table, extra_data) --finalize - if not df.check_if_bin_exists("hugin") then - dt.print_error(_("hugin not found")) - return - end - -- Since Hugin 2015.0.0 hugin provides a command line tool to start the assistant -- http://wiki.panotools.org/Hugin_executor -- We need pto_gen to create pto file for hugin_executor -- http://hugin.sourceforge.net/docs/manual/Pto_gen.html - local hugin_executor = false - if (df.check_if_bin_exists("hugin_executor") and df.check_if_bin_exists("pto_gen")) then - hugin_executor = true + local hugin = '"'..dt.preferences.read(namespace, "hugin", "file")..'"' + local hugin_executor = '"'..dt.preferences.read(namespace, "hugin_executor", "file")..'"' + local pto_gen = '"'..dt.preferences.read(namespace, "pto_gen", "file")..'"' + local user_prefer_gui = dt.preferences.read(namespace, "hugin_prefer_gui", "bool") + + local cmd_line_available = false + if df.check_if_bin_exists(hugin_executor) and df.check_if_bin_exists(pto_gen) then + cmd_line_available = true + end + + local gui_available = false + if df.check_if_bin_exists(hugin) then + gui_available = true end -- list of exported images @@ -76,58 +84,77 @@ local function create_panorama(storage, image_table, extra_data) --finalize -- reset and create image list img_list = "" for k,v in pairs(image_table) do - img_list = img_list ..v.. " " - table.insert(img_set, k) + img_list = img_list..v..' ' + table.insert(img_set, k) end - -- use first file as basename + -- use first file as basename for output file table.sort(img_set, function(a,b) return a.filename Date: Fri, 2 Mar 2018 14:07:29 -0500 Subject: [PATCH 037/640] Added windows and macOS external executable compatibility. Added functions set_executable_path_preference(), get_executable_path_preference(), and executable_path_widget() to lib/dtutils/file.lua to get, set and retrieve the location of executables on windows and macOS systems. Modified check_if_bin_exists to use the path preferences so executables can be found on windows and macOS systems as well as linux. Modified contrib/gimp.lua to use the new functions, thus making it usable on windows and macOS too. --- contrib/gimp.lua | 177 ++++++++----------------------------------- lib/dtutils/file.lua | 133 +++++++++++++++++++++++++++++--- 2 files changed, 153 insertions(+), 157 deletions(-) diff --git a/contrib/gimp.lua b/contrib/gimp.lua index f8472c75..c0fba7ec 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -67,109 +67,38 @@ local dt = require "darktable" local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext +local gimp_widget = nil -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/") -local function split_filepath(str) - local result = {} - -- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little - result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$") - return result -end - -local function get_path(str) - local parts = split_filepath(str) - return parts["path"] -end - -local function get_filename(str) - local parts = split_filepath(str) - return parts["filename"] -end - -local function get_basename(str) - local parts = split_filepath(str) - return parts["basename"] -end - -local function get_filetype(str) - local parts = split_filepath(str) - return parts["filetype"] -end - local function _(msgid) return gettext.dgettext("gimp", msgid) end --- Thanks Tobias Jakobs for the idea and the correction -function checkIfFileExists(filepath) - local file = io.open(filepath,"r") - local ret - if file ~= nil then - io.close(file) - dt.print_error("true checkIfFileExists: "..filepath) - ret = true - else - dt.print_error(filepath.." not found") - ret = false - end - return ret -end - -local function filename_increment(filepath) - - -- break up the filepath into parts - local path = get_path(filepath) - local basename = get_basename(filepath) - local filetype = get_filetype(filepath) - - -- check to see if we've incremented before - local increment = string.match(basename, "_(%d-)$") - - if increment then - -- we do 2 digit increments so make sure we didn't grab part of the filename - if string.len(increment) > 2 then - -- we got the filename so set the increment to 01 - increment = "01" - else - increment = string.format("%02d", tonumber(increment) + 1) - basename = string.gsub(basename, "_(%d-)$", "") - end - else - increment = "01" - end - local incremented_filepath = path .. basename .. "_" .. increment .. "." .. filetype - - dt.print_error("original file was " .. filepath) - dt.print_error("incremented file is " .. incremented_filepath) - - return incremented_filepath -end - -local function groupIfNotMember(img, new_img) +local function group_if_not_member(img, new_img) local image_table = img:get_group_members() local is_member = false for _,image in ipairs(image_table) do - dt.print_error(image.filename .. " is a member") + dt.print_log(image.filename .. " is a member") if image.filename == new_img.filename then is_member = true - dt.print_error("Already in group") + dt.print_log("Already in group") end end if not is_member then - dt.print_error("group leader is "..img.group_leader.filename) + dt.print_log("group leader is "..img.group_leader.filename) new_img:group_with(img.group_leader) - dt.print_error("Added to group") + dt.print_log("Added to group") end end local function sanitize_filename(filepath) - local path = get_path(filepath) - local basename = get_basename(filepath) - local filetype = get_filetype(filepath) + local path = df.get_path(filepath) + local basename = df.get_basename(filepath) + local filetype = df.get_filetype(filepath) local sanitized = string.gsub(basename, " ", "\\ ") @@ -181,60 +110,11 @@ local function show_status(storage, image, format, filename, dt.print(string.format(_("Export Image %i/%i"), number, total)) end -local function fileCopy(fromFile, toFile) - local result = nil - -- if cp exists, use it - if df.check_if_bin_exists("cp") then - result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") - end - -- if cp was not present, or if cp failed, then a pure lua solution - if not result then - local fileIn, err = io.open(fromFile, 'rb') - if fileIn then - local fileOut, errr = io.open(toFile, 'w') - if fileOut then - local content = fileIn:read(4096) - while content do - fileOut:write(content) - content = fileIn:read(4096) - end - result = true - fileIn:close() - fileOut:close() - else - dt.print_error("fileCopy Error: " .. errr) - end - else - dt.print_error("fileCopy Error: " .. err) - end - end - return result -end +local function gimp_edit(storage, image_table, extra_data) --finalize -local function fileMove(fromFile, toFile) - local success = os.rename(fromFile, toFile) - if not success then - -- an error occurred, so let's try using the operating system function - if df.check_if_bin_exists("mv") then - success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") - end - -- if the mv didn't exist or succeed, then... - if not success then - -- pure lua solution - success = fileCopy(fromFile, toFile) - if success then - os.remove(fromFile) - else - dt.print_error("fileMove Error: Unable to move " .. fromFile .. " to " .. toFile .. ". Leaving " .. fromFile .. " in place.") - dt.print(string.format(_("Unable to move edited file into collection. Leaving it as %s"), fromFile)) - end - end - end - return success -- nil on error, some value if success -end + local gimp_executable = df.check_if_bin_exists("gimp") -local function gimp_edit(storage, image_table, extra_data) --finalize - if not df.check_if_bin_exists("gimp") then + if not gimp_executable then dt.print_error(_("GIMP not found")) return end @@ -253,9 +133,9 @@ local function gimp_edit(storage, image_table, extra_data) --finalize dt.print(_("Launching GIMP...")) local gimpStartCommand - gimpStartCommand = "gimp "..img_list + gimpStartCommand = gimp_executable .. " " .. img_list - dt.print_error(gimpStartCommand) + dt.print_log(gimpStartCommand) dt.control.execute( gimpStartCommand) @@ -266,28 +146,28 @@ local function gimp_edit(storage, image_table, extra_data) --finalize for image,exported_image in pairs(image_table) do - local myimage_name = image.path .. "/" .. get_filename(exported_image) + local myimage_name = image.path .. "/" .. df.get_filename(exported_image) - while checkIfFileExists(myimage_name) do - myimage_name = filename_increment(myimage_name) + while df.check_if_file_exists(myimage_name) do + myimage_name = df.filename_increment(myimage_name) -- limit to 99 more exports of the original export - if string.match(get_basename(myimage_name), "_(d-)$") == "99" then + if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then break end end - dt.print_error("moving " .. exported_image .. " to " .. myimage_name) - local result = fileMove(exported_image, myimage_name) + dt.print_log("moving " .. exported_image .. " to " .. myimage_name) + local result = df.file_move(exported_image, myimage_name) if result then - dt.print_error("importing file") + dt.print_log("importing file") local myimage = dt.database.import(myimage_name) - groupIfNotMember(image, myimage) + group_if_not_member(image, myimage) for _,tag in pairs(dt.tags.get_tags(image)) do if not (string.sub(tag.name,1,9) == "darktable") then - dt.print_error("attaching tag") + dt.print_log("attaching tag") dt.tags.attach(tag,myimage) end end @@ -297,6 +177,13 @@ local function gimp_edit(storage, image_table, extra_data) --finalize end -- Register -dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit) + +local executables = {"gimp"} + +if dt.configuration.running_os ~= "linux" then + gimp_widget = df.executable_path_widget(executables) +end + +dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) -- diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 22cd5e56..696cdbc6 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -23,7 +23,7 @@ dtutils_file.libdoc = { local gettext = dt.gettext -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/") @@ -34,14 +34,18 @@ end dtutils_file.libdoc.functions["check_if_bin_exists"] = { Name = [[check_if_bin_exists]], - Synopsis = [[check if an executable is in the path]], + Synopsis = [[check if an executable exists]], Usage = [[local df = require "lib/dtutils.file" local result = df.check_if_bin_exists(bin) bin - string - the binary to check for]], - Description = [[check_if_bin_exists checks to see if the specified binary executable is - in the path.]], - Return_Value = [[result - boolean - true if the executable was found, false if not]], + Description = [[check_if_bin_exists checks to see if the specified binary exists. + check_if_bin_exists first checks to see if a preference for the binary has been + registered and uses that if found. The presence of the file is verified, then + quoted and returned. If no preference is specified and the operating system is + linux then the which command is used to check for a binary in the path. If found + that path is returned. If no binary is found, false is returned.]], + Return_Value = [[result - string - the path of the binary, false if not found]], Limitations = [[]], Example = [[]], See_Also = [[]], @@ -51,17 +55,27 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local result - if (dt.configuration.running_os == 'linux') then - result = os.execute("which "..bin) + local result = false + local path = nil + + if string.match(bin, "/") or string.match(bin, "\\") then + path = bin else - result = dtutils_file.check_if_file_exists(bin) + path = dtutils_file.get_executable_path_preference(bin) end - if not result then - result = false + if string.len(path) > 0 then + if dtutils_file.check_if_file_exists(path) then + result = "\"" .. path .. "\"" + end + elseif dt.configuration.running_os == "linux" then + local p = io.popen("which " .. bin) + local output = p:read("*a") + p:close() + if string.len(output) > 0 then + result = output:sub(1,-2) + end end - return result end @@ -416,4 +430,99 @@ function dtutils_file.create_unique_filename(filepath) return filepath end + +dtutils_file.libdoc.functions["set_executable_path_preference"] = { + Name = [[set_executable_path_preference]], + Synopsis = [[set a preference for the path to an executable]], + Usage = [[local df = require "lib/dtutils.file" + + df.set_executable_path_preference(executable, path) + executable - string - the name of the executable to set the path for + path - string - the path to the binary]], + Description = [[set_executable_path_preference takes an executable name and path to the + executable and registers the preference for later use.]], + Return_Value = [[]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.set_executable_path_preference(executable, path) + dt.preferences.write("executable_paths", executable, "string", path) +end + + +dtutils_file.libdoc.functions["get_executable_path_preference"] = { + Name = [[get_executable_path_preference]], + Synopsis = [[return the path to an executable from a preference]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.get_executable_path_preference(executable) + executable - string - the name of the executable to get the path for]], + Description = [[get_executable_path_preference returns the path preference to + the requested executable.]], + Return_Value = [[result - string - path to the executable]], + Limitations = [[executable should be the basename of the executable without extensions]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.get_executable_path_preference(executable) + return dt.preferences.read("executable_paths", executable, "string") +end + + +dtutils_file.libdoc.functions["executable_path_widget"] = { + Name = [[executable_path_widget]], + Synopsis = [[create a widget to get executable path preferences]], + Usage = [[local df = require "lib/dtutils.file" + + local widget = df.executable_path_widget(executables) + executables - table - a table of strings that are executable names]], + Description = [[executable_path_widget takes a table of executable names + and builds a set of file selector widgets to get the path to the executable. + The resulting widgets are wrapped in a box widget and returned.]], + Return_Value = [[widget - widget - a widget containing a file selector widget for + each executable.]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.executable_path_widget(executables) + local box_widgets = {} + table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"}) + for _, executable in pairs(executables) do + table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"}) + local path = dtutils_file.get_executable_path_preference(executable) + if not path then + path = "" + end + table.insert(box_widgets, dt.new_widget("file_chooser_button"){ + title = "select " .. executable .. " executable", + value = path, + is_directory = false, + changed_callback = function(self) + if dtutils_file.check_if_bin_exists(self.value) then + dtutils_file.set_executable_path_preference(executable, self.value) + end + end} + ) + end + local box = dt.new_widget("box"){ + orientation = "vertical", + table.unpack(box_widgets) + } + return box +end + return dtutils_file \ No newline at end of file From c073ecf0dd10f05b26b904e2d56d22e8fa845126 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 3 Mar 2018 20:22:47 -0500 Subject: [PATCH 038/640] Added check_os to lib/dtutils.lua so that scripts can check compatibility with the current operating system --- lib/dtutils.lua | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 02888a8e..abe51d64 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -32,7 +32,7 @@ local dt = require "darktable" local log = require "lib/dtutils.log" -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) dtutils.libdoc.functions["split"] = { Name = [[split]], @@ -215,4 +215,37 @@ function dtutils.spairs(_table, order) -- Code copied from http://stackoverflow. end end +dtutils.libdoc.functions["check_os"] = { + Name = [[check_os]], + Synopsis = [[check that the operating system is supported]], + Usage = [[local du = require "lib/dtutils" + + local result = du.check_os(operating_systems) + operating_systems - a table of operating system names such as {"windows","linux","macos","unix"}]], + Description = [[check_os checks a supplied table of operating systems against the operating system the + script is running on and returns true if the OS is in the list, otherwise false]], + Return_Value = [[result - boolean - true if the operating system is supported, false if not.]], + Limitations = [[]], + Example = [[local du = require "lib/dtutils" + if du.check_os({"windows"}) then + -- run the script + else + dt.print("Script