فهرست منبع

Upload files to ''

initial version, needs helper script
Markus Spring 8 ماه پیش
والد
کامیت
ef60671012
1فایلهای تغییر یافته به همراه358 افزوده شده و 0 حذف شده
  1. 358 0
      mail2blog.lua

+ 358 - 0
mail2blog.lua

@@ -0,0 +1,358 @@
+--[[ 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 = 2000
+local image_max_y = 2000
+
+-- 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 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
+
+---------------------------------------------------------------
+-- helper functions to access darktable feature via user interface
+-- use event handling helper functions to wait for pixel pipe
+-- processing to complete
+
+local function numberToString(number, nilReplacement, nanReplacement)
+  -- convert given number to string
+  -- return 'not a number' and 'nil' as '0/0'
+  -- log output equals to dt.gui.action command and parameters
+  if (number ~= number) then
+    return nanReplacement or '0/0'
+  end
+
+  if (number == nil) then
+    return nilReplacement or '0/0'
+  end
+
+  -- some digits with dot
+  local result = string.format('%.4f', number)
+  result = string.gsub(result, ',', '.')
+
+  return result
+end
+
+-- convert values to boolean, consider not a number and nil
+local function GuiActionValueToBoolean(value)
+  -- NaN
+  if (value ~= value) then
+    return false
+  end
+
+  -- nil
+  if (value == nil) then
+    return false
+  end
+
+  return value ~= 0
+end
+
+function ThreadSleep(milliseconds)
+  -- local timeout = StepTimeout:Value()
+  local timeout = 500
+  local factor = milliseconds / timeout
+  LogInfo('    '..string.format(_("wait for %d ms. (config = %s ms * %s)"), milliseconds, timeout, factor))
+  dt.control.sleep(milliseconds)
+end
+
+-- perform the specified effect on the path and element of an action
+-- see https://docs.darktable.org/lua/stable/lua.api.manual/darktable/gui/action/
+local function GuiActionInternal(path, instance, element, effect, speed, waitForPipeline)
+  LogInfo('dt.gui.action(' ..
+     quote(path) ..
+     ',' .. instance .. ',' .. quote(element) .. ',' .. quote(effect) .. ',' .. numberToString(speed) .. ')')
+
+  local result
+
+  -- if (waitForPipeline) then
+  --   WaitForPixelPipe:Do(function()
+  --     result = dt.gui.action(path, instance, element, effect, speed)
+  --   end)
+  -- else
+  result = dt.gui.action(path, instance, element, effect, speed)
+    -- wait a bit...
+  -- ThreadSleep(StepTimeout:Value() / 2)
+  ThreadSleep(500 / 2)
+  return result
+end
+
+-- wait for 'pixelpipe-processing-complete'
+local function GuiAction(path, instance, element, effect, speed)
+  return GuiActionInternal(path, instance, element, effect, speed, true)
+end
+
+local function randomString(length)
+    if not length or length <= 0 then return '' end
+    math.randomseed(os.clock()//5)
+    return randomString(length - 1) .. charset[math.random(1, #charset)]
+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 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' )
+            -- run mailscript
+            local spring2lifescript = get_executable("spring2lifescript", "spring2life script")
+            run_cmd = spring2lifescript .. " " .. tmp_exported
+               .. ' ' .. select_publication_target.value
+               .. ' ' .. df.sanitize_filename(i.filename) .. ' &'
+            LogInfo(run_cmd)
+            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")
+            --- dt.styles.delete(tmpstyle)
+         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