diff --git a/.lib/record-core.lua b/.lib/record-core.lua index 5b14284..e0c99ed 100644 --- a/.lib/record-core.lua +++ b/.lib/record-core.lua @@ -22,129 +22,148 @@ function check_api_version() end end -function show_error(errorMsg) +function show_error(error_msg) local error_dialog = Dialog("Error") error_dialog - :label { text = errorMsg } + :label { text = error_msg } :newrow() :button { text = "Close", onclick = function() error_dialog:close() end } error_dialog:show() end --- Core functions -local function initialize_snapshot(self, sprite) - self.auto_snap_enabled = false - self.auto_snap_delay = 1 - self.auto_snap_increment = 0 - self.context = nil - - -- Instance of Aseprite Sprite object - -- https://github.com/aseprite/api/blob/master/api/sprite.md#sprite - self.sprite = nil - if sprite then - self.sprite = sprite - self.context = get_recording_context(sprite) +local function get_active_frame_number() + local frame = app.activeFrame + if frame == nil then + return 1 + else + return frame end end -local function get_snapshot_recording_index(self) - local path = self.context.index_file +RecordingContext = {} + +function RecordingContext:get_recording_index() + local path = self.index_file if not app.fs.isFile(path) then return 0 end local file = io.open(path, "r") + assert(file) local contents = file:read() io.close(file) return tonumber(contents) end -local function increment_snapshot_recording_index(self) - local index = get_snapshot_recording_index(self) + 1 - local path = self.context.index_file +function RecordingContext:set_recording_index(index) + local path = self.index_file local file = io.open(path, "w") + assert(file) file:write("" .. index) io.close(file) end -local function get_active_frame_number() - local frame = app.activeFrame - if frame == nil then - return 1 - else - return frame - end -end - -function get_recording_context(sprite) +function RecordingContext.new(sprite) local self = {} + setmetatable(self, { __index = RecordingContext }) self.sprite_file_name = app.fs.fileTitle(sprite.filename) self.sprite_file_path = app.fs.filePath(sprite.filename) + self:_init_directory() + self.index_file = app.fs.joinPath(self.record_directory_path, "_index.txt") + self:_promote_v2_to_v3() + return self +end - -- 2.x Target Directory Backwards Compatibility - self.record_directory_name_legacy = self.sprite_file_name .. "_record" - local is_legacy_recording = false - if app.fs.isDirectory(app.fs.joinPath(self.sprite_file_path, self.record_directory_name_legacy)) then - is_legacy_recording = true - self.record_directory_name = self.record_directory_name_legacy +function RecordingContext:_init_directory() + local dir_name_legacy = self.sprite_file_name .. "_record" + local dir_path_legacy = app.fs.joinPath(self.sprite_file_path, dir_name_legacy) + if app.fs.isDirectory(dir_path_legacy) then + -- For 2.x Target Directory Backwards Compatibility + self._is_legacy_recording = true + self.record_directory_name = dir_name_legacy else + self._is_legacy_recording = false self.record_directory_name = self.sprite_file_name .. "__record" end self.record_directory_path = app.fs.joinPath(self.sprite_file_path, self.record_directory_name) - self.index_file = app.fs.joinPath(self.record_directory_path, "_index.txt") +end +function RecordingContext:_promote_v2_to_v3() + if not self._is_legacy_recording then + return -- Is not v2.x + end + if app.fs.isFile(self.index_file) then + return -- Is v2.x, but already has promoted structure + end -- 2.x Add Missing Index File for Forward Compatibility - if is_legacy_recording and not app.fs.isFile(self.index_file) then - local is_index_set = false - local current_index = 0 - while not is_index_set do - if not app.fs.isFile(get_contextual_recording_image_path(self, current_index)) then - is_index_set = true - local file = io.open(self.index_file, "w") - file:write("" .. current_index) - io.close(file) - else - current_index = current_index + 1 - end + local is_index_set = false + local current_index = 0 + while not is_index_set do + if not app.fs.isFile(self:get_recording_image_path(current_index)) then + is_index_set = true + self.context:set_recording_index(current_index) + else + current_index = current_index + 1 end end - - return self end -function get_contextual_recording_image_path(self, index) +function RecordingContext:get_recording_image_path(index) return app.fs.joinPath(self.record_directory_path, self.sprite_file_name .. "_" .. index .. ".png") end -function get_recording_image_path_at_index(self, index) - return get_contextual_recording_image_path(self.context, index) +Snapshot = {} + +function Snapshot:_initialize(sprite) + self.auto_snap_enabled = false + self.auto_snap_delay = 1 + self.auto_snap_increment = 0 + self.context = nil + + -- Instance of Aseprite Sprite object + -- https://github.com/aseprite/api/blob/master/api/sprite.md#sprite + self.sprite = nil + if sprite then + self.sprite = sprite + self.context = RecordingContext.new(sprite) + end +end + +function Snapshot:_increment_recording_index() + local index = self.context:get_recording_index(self) + 1 + self.context:set_recording_index(index) +end + +function Snapshot:get_recording_image_path(index) + return self.context:get_recording_image_path(index) end -function get_snapshot() +function Snapshot.new() local self = {} - initialize_snapshot(self, nil) + setmetatable(self, { __index = Snapshot }) + self:_initialize(nil) return self end -function is_snapshot_active(self) - if not is_snapshot_valid(self) then +function Snapshot:is_active() + if not self:is_valid() then return false end return self.auto_snap_enabled end -function is_snapshot_valid(self) +function Snapshot:is_valid() if self.sprite then return true end return false end -function reset_snapshot(self) - initialize_snapshot(self, nil) +function Snapshot:reset() + self:_initialize(nil) end -function auto_save_snapshot(self) +function Snapshot:auto_save() if not self.auto_snap_enabled then return end @@ -157,31 +176,65 @@ function auto_save_snapshot(self) return end self.auto_snap_increment = 0 - save_snapshot(self) + self:save() end -function save_snapshot(self) - local path = get_recording_image_path_at_index(self, get_snapshot_recording_index(self)) +function Snapshot:_get_current_image() local image = Image(self.sprite) image:drawSprite(self.sprite, get_active_frame_number()) + return image +end + +function Snapshot:_get_saved_image_content(index) + if index < 0 then + return nil + end + local path = self:get_recording_image_path(index) + if not app.fs.isFile(path) then + return nil + end + local file = io.open(path, "rb") + assert(file) + local content = file:read("a") + io.close(file) + return content +end + +function Snapshot:save() + local image = self:_get_current_image() + local index = self.context:get_recording_index() + local path = self:get_recording_image_path(index) image:saveAs(path) - increment_snapshot_recording_index(self) + + local image_changed = true + local prev_content = self:_get_saved_image_content(index - 1) + if prev_content ~= nil then + local curr_content = self:_get_saved_image_content(index) + assert(curr_content ~= nil) + if prev_content == curr_content then + image_changed = false + end + end + + if image_changed then + self:_increment_recording_index() + end end -function set_snapshot_sprite(self, sprite) +function Snapshot:set_sprite(sprite) if not app.fs.isFile(sprite.filename) then return show_error(error_messages.save_required) end if (not self.sprite or self.sprite ~= sprite) then - initialize_snapshot(self, sprite) + self:_initialize(sprite) end end -function update_snapshot_sprite(self) +function Snapshot:update_sprite() local sprite = app.activeSprite if not sprite then return show_error(error_messages.no_active_sprite) end - set_snapshot_sprite(self, sprite) + self:set_sprite(sprite) end diff --git a/Automatic Snapshot.lua b/Automatic Snapshot.lua index 7d09a36..12d75eb 100644 --- a/Automatic Snapshot.lua +++ b/Automatic Snapshot.lua @@ -7,15 +7,15 @@ dofile(".lib/record-core.lua") -local snapshot = get_snapshot() +local snapshot = Snapshot.new() local function take_auto_snapshot() - auto_save_snapshot(snapshot) + snapshot:auto_save() end local function disable_auto_snapshot(dialog) snapshot.auto_snap_enabled = false - if not is_snapshot_valid(snapshot) then + if not snapshot:is_valid() then return end @@ -32,9 +32,9 @@ local function disable_auto_snapshot(dialog) end local function enable_auto_snapshot(dialog) - update_snapshot_sprite(snapshot) + snapshot:update_sprite() - snapshot.auto_snap_enabled = is_snapshot_valid(snapshot) + snapshot.auto_snap_enabled = snapshot:is_valid() if not snapshot.auto_snap_enabled then return end @@ -60,7 +60,7 @@ if check_api_version() then local main_dialog = Dialog { title = "Record - Auto Snapshot", onclose = function() - reset_snapshot(snapshot) + snapshot:reset() end } @@ -89,7 +89,7 @@ if check_api_version() then id = "toggle", text = "Start", onclick = function() - if is_snapshot_active(snapshot) then + if snapshot:is_active() then disable_auto_snapshot(main_dialog) else enable_auto_snapshot(main_dialog) diff --git a/Command Palette.lua b/Command Palette.lua index 5930504..a5dedcb 100644 --- a/Command Palette.lua +++ b/Command Palette.lua @@ -7,24 +7,23 @@ dofile(".lib/record-core.lua") -local snapshot = get_snapshot() +local snapshot = Snapshot.new() local function take_snapshot() - update_snapshot_sprite(snapshot) - if not is_snapshot_valid(snapshot) then + snapshot:update_sprite() + if not snapshot:is_valid() then return end - - save_snapshot(snapshot) + snapshot:save() end local function open_time_lapse() - update_snapshot_sprite(snapshot) - if not is_snapshot_valid(snapshot) then + snapshot:update_sprite() + if not snapshot:is_valid() then return end - local path = get_recording_image_path_at_index(snapshot, 0) + local path = snapshot:get_recording_image_path(0) if app.fs.isFile(path) then app.command.OpenFile { filename = path } else diff --git a/Open Time Lapse.lua b/Open Time Lapse.lua index 31a7422..001fe14 100644 --- a/Open Time Lapse.lua +++ b/Open Time Lapse.lua @@ -10,8 +10,8 @@ dofile(".lib/record-core.lua") if check_api_version() then local sprite = app.activeSprite if sprite and app.fs.isFile(sprite.filename) then - local context = get_recording_context(sprite) - local path = get_contextual_recording_image_path(context, 0) + local context = RecordingContext.new(sprite) + local path = context:get_recording_image_path(0) if app.fs.isFile(path) then app.command.OpenFile { filename = path } else diff --git a/Take Snapshot.lua b/Take Snapshot.lua index 7574971..5d82883 100644 --- a/Take Snapshot.lua +++ b/Take Snapshot.lua @@ -10,9 +10,9 @@ dofile(".lib/record-core.lua") if check_api_version() then local sprite = app.activeSprite if sprite and app.fs.isFile(sprite.filename) then - local snapshot = get_snapshot() - set_snapshot_sprite(snapshot, sprite) - save_snapshot(snapshot) + local snapshot = Snapshot.new() + snapshot:set_sprite(sprite) + snapshot:save() else return show_error(error_messages.save_required) end