| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- --[[ Export image for blog, duplicate and set it LOCKED ]]
- local script_path = debug.getinfo(1, "S").source:sub(2):match("(.*/)")
- package.path = script_path .. "?.lua;" .. package.path
- local config = require("config")
- email_1 = config.email_1
- email_2 = config.email_2
- email_3 = config.email_3
- local image_max_x = 2500
- local image_max_y = 2500
- -- local jpg_quality_str = '92'
- -- module name
- local MODULE_NAME = "mail2blog"
- local df = require "lib/dtutils.file"
- local dt = require "darktable"
- local du = require "lib/dtutils"
- local log = require 'lib/dtutils.log'
- local dtsys = require "lib/dtutils.system"
- local cjson = require "cjson"
- local function quote(text)
- return '"' .. text .. '"'
- end
- local charset = {} do -- [0-9a-zA-Z]
- for c = 48, 57 do table.insert(charset, string.char(c)) end
- for c = 65, 90 do table.insert(charset, string.char(c)) end
- for c = 97, 122 do table.insert(charset, string.char(c)) end
- end
- -- - - - - - - - - - - - - - - - - - - - - - - -
- -- V E R S I O N C H E C K
- -- - - - - - - - - - - - - - - - - - - - - - - -
- du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.0
- -- script_manager integration to allow a script to be removed
- -- without restarting darktable
- local function destroy()
- -- nothing to destroy
- end
- -- - - - - - - - - - - - - - - - - - - - - - - -
- -- C O N S T A N T S
- -- - - - - - - - - - - - - - - - - - - - - - - -
- local PS = dt.configuration.running_os == "windows" and "\\" or "/"
- -- - - - - - - - - - - - - - - - - - - - - - - -
- -- T R A N S L A T I O N S
- -- - - - - - - - - - - - - - - - - - - - - - - -
- local gettext = dt.gettext
- gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
- local function _(msgid)
- return gettext.dgettext(MODULE_NAME, msgid)
- end
- -- - - - - - - - - - - - - - - - - - - - - - - -
- -- M A I N
- -- - - - - - - - - - - - - - - - - - - - - - - -
- -- alias dt.control.sleep to sleep
- local sleep = dt.control.sleep
- ---------------------------------------------------------------
- -- some helper methods to log information messages
- log.log_level(log.info) -- log.info or log.warn or log.debug
- local LogCurrentStep = ''
- local LogMajorNr = 0
- local LogMajorMax = 0
- local LogSummaryMessages = {}
- local function GetLogInfoText(text)
- return '[' .. LogMajorNr .. '/' .. LogMajorMax .. '] ' .. LogCurrentStep .. ': ' .. text
- end
- local function LogInfo(text)
- log.msg(log.info, GetLogInfoText(text))
- end
- local function LogScreen(text)
- log.msg(log.screen, text)
- end
- local function LogSummaryClear()
- for k, v in pairs(LogSummaryMessages) do
- LogSummaryMessages[k] = nil
- end
- end
- local function LogSummaryMessage(text)
- table.insert(LogSummaryMessages, GetLogInfoText(text))
- end
- -- ----------------------------------------------------
- local function set_published_tag ( email, image )
- if email == 'postie_markus_spring.info@markus-spring.de' then
- local tagnr = dt.tags.find('photography|published|blog')
- dt.tags.attach(tagnr,image)
- elseif email == 'postie_vhs_fotogruppe_reichenhall@markus-spring.de' then
- local tagnr = dt.tags.find('photography|published|vhs-fotogruppe')
- dt.tags.attach(tagnr,image)
- -- else
- -- local tagnr = dt.tags.find('photography|published|instagram')
- -- dt.tags.attach(tagnr,image)
- end
- local tagnr = dt.tags.find('LOCKED')
- dt.tags.attach(tagnr,image)
- end
- local function getPureFilename(path)
- return string.match(path, "([^/\\]+)$")
- end
- local function set_metadata_note ( tmp_exported, image )
- if image then
- local current_notes = image.notes or "" -- Retrieve existing notes or set as empty
- if current_notes ~= "" then
- current_notes = current_notes .. "; "
- end
- image.notes = current_notes .. 'published as ' .. getPureFilename(tmp_exported)
- end
- end
- local function set_rating_min_2 ( image )
- if image.rating < 2 then
- image.rating = 2
- end
- end
- local function get_executable( binaryname, binarystring )
- local binary = dt.preferences.read(MODULE_NAME, binaryname, "string")
- if binary == "" then
- dt.print(_( binarystring .. " executable not configured"))
- return
- end
- binary = df.sanitize_filename(binary)
- return binary
- end
- local function run_exiftool ( file, tmp_exported, flags )
- local exiftoolbinary = get_executable("exiftoolbinary", "exiftool")
- run_cmd = exiftoolbinary..' -TagsFromFile '..file..' '..flags..' '..tmp_exported
- -- LogInfo(string.format("Running %s", run_cmd))
- local job = dt.gui.create_job(string.format("Running %s", run_cmd), true, stop_job)
- resp = dtsys.external_command(run_cmd)
- job.valid = false
- end
- local function isempty(s)
- return s == nil or s == ''
- end
- local function remove_unneeded_exif_values ( jpeg_file )
- local tags_to_remove = {
- "ModifyDate", "DateTimeOriginal", "CreateDate", "DateCreated",
- "TimeCreated", "GPSTimeStamp", "GPSDateStamp", "GPSDateTime",
- "IFD0:*", "IFD1:*"
- }
-
- local args = {"-overwrite_original"}
- for _, tag in ipairs(tags_to_remove) do
- table.insert(args, "-" .. tag .. "=")
- end
- -- table.insert(args, "-FileModifyDate<FileModifyDate")
- table.insert(args, jpeg_file)
-
- local exiftoolbinary = get_executable("exiftoolbinary", "exiftool")
- run_cmd = exiftoolbinary..' '.. table.concat(args, " ")
- -- dt.print_log(string.format("Running %s", run_cmd))
- local job = dt.gui.create_job(string.format("Running %s", run_cmd), true, stop_job)
- resp = dtsys.external_command(run_cmd)
- job.valid = false
- return nil
- end
- -- Function to replace German umlauts and sanitize the filename
- local function create_safe_filename(title)
- local replacements = {
- ["ä"] = "ae", ["ö"] = "oe", ["ü"] = "ue",
- ["Ä"] = "Ae", ["Ö"] = "Oe", ["Ü"] = "Ue",
- ["ß"] = "ss"
- }
- title = title:gsub("[%z\1-\127\194-\244][\128-\191]*", function(char)
- return replacements[char] or char
- end)
- title = title:gsub("[^%w%-]", "_")
- title = title:gsub("_+", "_")
- title = title:gsub("^_+", ""):gsub("_+$", "")
- if title == "" then
- title = "untitled"
- end
- title = title:sub(1, 255)
- return title
- end
- -- ----------------------------------------------------
- dt.print_log(MODULE_NAME .. ' loaded')
- -- save the configuration
- local current_view = dt.gui.current_view()
- local select_publication_target = dt.new_widget("combobox")
- {
- label = "target",
- tooltip = "Select blog for image publication",
- changed_callback = function(w) dt.preferences.write(MODULE_NAME, "target", "string", w.selected) end,
- email_1, email_2, email_3
- }
- local function process_image(image_path)
- local exiftoolbinary = get_executable("exiftoolbinary", "exiftool")
- -- Get metadata using exiftool
- local metadata_cmd = exiftoolbinary .. " -j -n -XMP:HierarchicalSubject -Composite:GPSPosition -XMP:Title " .. image_path
- dt.print_log(metadata_cmd)
- local handle = io.popen(metadata_cmd)
- local json_data = handle:read("*a")
- handle:close()
- print(json_data)
-
- -- Parse JSON data using cjson
- local metadata = cjson.decode(json_data)[1]
- local first_item = metadata
- local h_subject = first_item.HierarchicalSubject or ""
- local gps_position = first_item.GPSPosition or ""
- local title = first_item.Title or ""
- -- find ^where|
- local function find_where_value(tbl)
- for _, value in pairs(tbl) do
- if type(value) == "string" and string.find(value, "^where|") then
- return value
- end
- end
- return nil -- Not found
- end
- where = find_where_value(h_subject)
- local platz = ""
- local ort = ""
- local platz_ort_table = {where:match(".*|(.-)|([^|]+)$")}
- for i, v in ipairs(platz_ort_table) do
- if i == 1 then
- platz = v
- elseif i == 2 then
- ort = v
- end
- end
- -- Process HierarchicalSubject
- local h_subject_list = {}
- for _, v in pairs(h_subject) do
- if not ( tostring(v):find("^darktable") or
- tostring(v):find("^photography|published") or
- tostring(v):find("^where|") or
- tostring(v):find("^LOCKED") ) then
- table.insert(h_subject_list, v)
- end
- end
- local lat, lon = gps_position:match("(-?[%d%.]+) (-?[%d%.]+)")
- local caption = string.format(
- "#img1 %s, %s (<a target='_blank' href='https://www.openstreetmap.org/?mlat=%s&mlon=%s#map=18/%s/%s'>OSM</a>)#",
- platz or "", ort or "", lat or "", lon or "", lat or "", lon or ""
- )
- -- Generate tags, extract the last part of each string and format it
- local function subject_tags(t)
- local result = {}
- for _, str in ipairs(t) do
- -- Find the last part of the string after the last '|'
- local lastPart = str:match(".*|([^|]+)$")
- -- Add it to the result table, wrapped in brackets
- table.insert(result, "[" .. lastPart .. "]")
- end
- -- Concatenate all elements into a single string
- return table.concat(result, " ")
- end
- tags = subject_tags(h_subject_list)
- title = tags .. " " .. title
- return filtered_subject, title, caption
- end
- local publication_button = dt.new_widget("button")
- {
- label = "Publish!",
- clicked_callback = function ()
- for i_, i in ipairs(dt.gui.action_images) do
- if isempty(i.title) then
- local job = dt.gui.create_job("FEHLER: Das Bild " .. i.filename .. " hat keinen Titel.", true, stop_job)
- os.execute("sleep " .. 3)
- job.valid = false
- else
- set_rating_min_2( i )
- -- create duplicate
- local newimg = i.duplicate_with_history(i)
- local jpeg_exporter = dt.new_format("jpeg")
- jpeg_exporter.max_height = image_max_y
- jpeg_exporter.max_width = image_max_x
- -- local tmp_exported = os.tmpname()..".jpg"
- local tempname = os.tmpname()
- os.remove(tempname)
- os.execute("mkdir " .. tempname)
- local tmp_exported = tempname .. '/' .. create_safe_filename(i.title) .. '.jpg'
- local job = dt.gui.create_job(string.format(_("Converting raw file '%s' to jpeg..."), i.filename), true, stop_job)
- jpeg_exporter:write_image(i, tmp_exported, false)
- -- copy exif data from original file
- run_exiftool( df.sanitize_filename(i.path..PS..i.filename), tmp_exported, '-exif:all --subifd:all --Orientation -overwrite_original' )
- -- copy exif data from xmp file
- run_exiftool( df.sanitize_filename(i.sidecar) , tmp_exported, '-xmp:all -exif:all --subifd:all -overwrite_original' )
- local h_subject, title, caption = process_image(tmp_exported)
- remove_unneeded_exif_values(tmp_exported)
-
- run_cmd = "thunderbird -compose \"to=".. select_publication_target.value ..",subject='" .. title .."',body='" .. caption .. "',attachment='file://" .. tmp_exported .."'\""
- job = false
- local job = dt.gui.create_job("Running " .. run_cmd, true, stop_job)
- os.execute(run_cmd)
- set_published_tag ( select_publication_target.value, i )
- job = false
- set_metadata_note ( tmp_exported, i )
- LogScreen("Done")
- end
- end
- end
- }
- local lib_widgets = {}
- table.insert(lib_widgets, select_publication_target)
- table.insert(lib_widgets, publication_button)
- -- ... and tell dt about it all
- dt.register_lib(
- MODULE_NAME, -- plugin name
- MODULE_NAME, -- name
- true, -- expandable
- false, -- resetable
- {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
- dt.new_widget("box") -- widget
- {
- orientation = "vertical",
- -- sensitive = enfuse_installed,
- table.unpack(lib_widgets)
- },
- nil,-- view_enter
- nil -- view_leave
- )
- -- end
- -- -- register the new preferences -----------------------------------------------
- dt.preferences.register(MODULE_NAME, "exiftoolbinary", "file",
- _(MODULE_NAME .. ": executable for exiftool"),
- _("select executable for exiftool command line version") , "")
- dt.preferences.register(MODULE_NAME, "spring2lifescript", "file",
- _(MODULE_NAME .. ": executable for mail2spring2life script"),
- _("select executable for mail2spring2life script") , "")
- -- ----------------------------------------------------------------------------------
- -- set the destroy routine so that script_manager can call it when
- -- it's time to destroy the script and then return the data to
- -- script_manager
- local script_data = {}
- script_data.destroy = destroy
- return script_data
|