On 2017-01-30 12:28, Tobias Ellinghaus wrote:
Am Montag, 30. Januar 2017, 12:04:03 CET schrieb René Seindal:
Hi

Ho do I make a long running Lua extension not block the darktable GUI?

It depends on what your code does and from where it is called. Some things
have to run in the gui thread and can't be unblocked, others can.

When you export files the export runs in the background somehow.

Exports are an example of what gets run in its own thread. So maybe show some
sample code.

The code takes the currently selected image in darktable, looks them up in a shotwell sqlite3 database using luasql and updates ratings and tags in darktable.

It is not something that can be handed off to a sub-process since it updates darktable.

I have put in a progress bar (background job) but the progress bar doesn't update and the cancel button doesn't work, because I can't find a way to hand off control to the gui to update, while looping through the images, looking stuff up in the other sqlite3 database.

The script is attached.

--
René Seindal - [email protected]

____________________________________________________________________________
darktable user mailing list
to unsubscribe send a mail to [email protected]
#!/usr/bin/lua

local dt = require "darktable"

dt.configuration.check_version(...,{4,0,0})

dt.preferences.register(
   "sync-shotwell-tags-and-rating",
   "database",
   "file",
   "location of shotwell database photo.db",
   "enter the location of your shotwell database here",
   "~/.shotwell/data/photo.db")


local function printf(fmt, ...) dt.print_error(string.format(fmt, ...)) end
local function sprintf(fmt, ...) return string.format(fmt, ...) end

local function shotwell_tag_to_dt(tag)
   return (string.gsub((string.gsub(tag, '/', '', 1)), '/', '|'))
end
   
local function shotwell_lookup(conn, file)
   local sql = sprintf('select id,rating from PhotoTable where filename = "%s"', conn:escape(file))

   -- printf('sql = %s', sql)
   local cur = assert(conn:execute(sql))

   local row = cur:fetch({}, "a")
   if not row then return end
   
   -- printf("id: %d, rating %d, filename: %s", row.id, row.rating, file)

   local id = row.id
   local rating = row.rating

   cur:close()

   -- get tags for photo 

   local sql = sprintf('select id,name from TagTable where photo_id_list like "%%thumb%016x,%%" order by name desc', id)
   -- printf('sql = %s', sql)
   local cur = assert(conn:execute(sql))

   local tags = {}
   local lasttag;
   
   local row = cur:fetch({}, "a")
   while row do
      -- printf("id: %d, name %s, last %s", row.id, row.name, lasttag)

      if not (lasttag and string.find(lasttag, row.name, 0, true) == 1) then
	 -- printf('match last %s cur %s dt %s', lasttag, row.name, shotwell_tag_to_dt(row.name))
	 table.insert(tags, shotwell_tag_to_dt(row.name))
	 lasttag = row.name
      end
      
      row = cur:fetch(row, "a")
   end
   
   cur:close()

   return rating, tags
end

local function shotwell_sync_images(images)
   local db = dt.preferences.read("sync-shotwell-tags-and-rating", "database", "string")
   -- printf('database file %s', db)
   if not db then dt.print("shotwell database location not defined") return end
   db = string.gsub(db, '^~', os.getenv('HOME'), 1)

   local driver = require 'luasql.sqlite3'
   local env = assert(driver.sqlite3())
   local conn, err = env:connect(db, "READONLY")
   if not conn then dt.print("can't open shotwell database " .. db) env:close() return end

   local cancelled = false
   local progress = dt.gui.create_job('Sync from shotwell', true, function() cancelled = true; end)
   local total = #images

   progress.percent = 0;
   for count, image in ipairs(images)  do
      local file = image.path .. '/' .. image.filename
      -- printf('file %s', file)
      local rating, tags = shotwell_lookup(conn, file)
      if rating then
	 -- printf('\trating %d', rating)
	 image.rating = rating
	 
	 for _, tag in pairs(tags) do
	    -- printf('\ttag %s', tag)
	    image:attach_tag(dt.tags.create(tag))
	 end
      else
	 dt.print(sprintf('file %s not found in shotwell database', file))
      end

      progress.percent = total / count
      if cancelled then break end

      -- dt.control.sleep(1)
      -- coroutine.yield('WAIT_MS', 1)
   end

   progress.valid = false

   conn:close()
   env:close()
end


dt.register_event(
   "shortcut",
  function(event, shortcut) shotwell_sync_images(dt.gui.action_images) end,
  "sync rating and tags from shotwell"
)

dt.gui.libs.image.register_action(
  "sync shotwell",
  function(event, images) shotwell_sync_images(images) end,
  "sync rating and tags from shotwell"
)

Reply via email to