From c00fbfaa7137e8b611e13424e951f3ff303e46d2 Mon Sep 17 00:00:00 2001 From: tomasklaen Date: Wed, 4 Sep 2024 11:58:00 +0200 Subject: [PATCH] refactor: normalized interfacing with ziggy --- src/uosc/lib/menus.lua | 90 +++++++++++++++--------------------------- src/uosc/lib/utils.lua | 79 ++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 70 deletions(-) diff --git a/src/uosc/lib/menus.lua b/src/uosc/lib/menus.lua index e27a3651..876e80c3 100644 --- a/src/uosc/lib/menus.lua +++ b/src/uosc/lib/menus.lua @@ -895,49 +895,40 @@ function open_subtitle_downloader() end end - local handle_select, handle_search - - -- Ensures response is valid, and returns its payload, or handles error reporting, - -- and returns `nil`, indicating the consumer should abort response handling. - local function ensure_response_data(success, result, error, check) - local data - if success and result and result.status == 0 then - data = utils.parse_json(result.stdout) - if not data or not check(data) then - data = (data and data.error == true) and data or { - error = true, - message = t('invalid response json (see console for details)'), - message_verbose = 'invalid response json: ' .. utils.to_string(result.stdout), - } - end - else - data = { - error = true, - message = error or t('process exited with code %s (see console for details)', result.status), - message_verbose = result.stdout .. result.stderr, - } - end - - if data.error then - local message, message_verbose = data.message or t('unknown error'), data.message_verbose or data.message - if message_verbose then msg.error(message_verbose) end + local handle_download, handle_search + + -- Checks if there an error, or data is invalid. If true, reports the error, + -- updates menu to inform about it, and returns true. + ---@param error string|nil + ---@param data any + ---@param check_is_valid? fun(data: any):boolean + ---@return boolean abort Whether the further response handling should be aborted. + local function should_abort(error, data, check_is_valid) + if error or not data or (not check_is_valid or not check_is_valid(data)) then menu:update_items({ { - title = message, - hint = t('error'), + title = t('Something went wrong.'), + align = 'center', + muted = true, + italic = true, + selectable = false, + }, + { + title = t('See console for details.'), + align = 'center', muted = true, italic = true, selectable = false, }, }) - return + msg.error(error or ('Invalid response: ' .. (utils.format_json(data) or tostring(data)))) + return true end - - return data + return false end ---@param data {kind: 'file', id: number}|{kind: 'page', query: string, page: number} - handle_select = function(data) + handle_download = function(data) if data.kind == 'page' then handle_search(data.query, data.page) return @@ -953,25 +944,14 @@ function open_subtitle_downloader() end end) - local args = itable_join({config.ziggy_path, 'download-subtitles'}, credentials, { + local args = itable_join({'download-subtitles'}, credentials, { '--file-id', tostring(data.id), '--destination', destination_directory, }) - mp.command_native_async({ - name = 'subprocess', - capture_stderr = true, - capture_stdout = true, - playback_only = false, - args = args, - }, function(success, result, error) + call_ziggy_async(args, function(error, data) if not menu:is_alive() then return end - - local data = ensure_response_data(success, result, error, function(data) - return type(data.file) == 'string' - end) - - if not data then return end + if should_abort(error, data, function(data) return type(data.file) == 'string' end) then return end load_track('sub', data.file) @@ -1008,7 +988,7 @@ function open_subtitle_downloader() menu:update_items({{icon = 'spinner', align = 'center', selectable = false, muted = true}}) - local args = itable_join({config.ziggy_path, 'search-subtitles'}, credentials) + local args = itable_join({'search-subtitles'}, credentials) local languages = itable_filter(get_languages(), function(lang) return lang:match('.json$') == nil end) args[#args + 1] = '--languages' @@ -1027,20 +1007,14 @@ function open_subtitle_downloader() args[#args + 1] = query end - mp.command_native_async({ - name = 'subprocess', - capture_stderr = true, - capture_stdout = true, - playback_only = false, - args = args, - }, function(success, result, error) + call_ziggy_async(args, function(error, data) if not menu:is_alive() then return end - local data = ensure_response_data(success, result, error, function(data) + local function check_is_valid(data) return type(data.data) == 'table' and data.page and data.total_pages - end) + end - if not data then return end + if should_abort(error, data, check_is_valid) then return end local subs = itable_filter(data.data, function(sub) return sub and sub.attributes and sub.attributes.release and type(sub.attributes.files) == 'table' and @@ -1131,7 +1105,7 @@ function open_subtitle_downloader() end end) elseif not event.action then - handle_select(event.value) + handle_download(event.value) end elseif event.type == 'search' then handle_search(event.query) diff --git a/src/uosc/lib/utils.lua b/src/uosc/lib/utils.lua index b5c84687..bbfd8552 100644 --- a/src/uosc/lib/utils.lua +++ b/src/uosc/lib/utils.lua @@ -814,30 +814,85 @@ function load_track(type, path) end end ----@return string|nil -function get_clipboard() +---@param args (string|number)[] +---@return string|nil error +---@return table data +function call_ziggy(args) local result = mp.command_native({ name = 'subprocess', capture_stderr = true, capture_stdout = true, playback_only = false, - args = {config.ziggy_path, 'get-clipboard'}, + args = itable_join({config.ziggy_path}, args), }) - local function print_error(message) - msg.error('Getting clipboard data failed. Error: ' .. message) + if result.status ~= 0 then + return 'Calling ziggy failed. Exit code ' .. result.status .. ': ' .. result.stdout .. result.stderr, {} + end + + local data = utils.parse_json(result.stdout) + if not data then + return 'Ziggy response error. Couldn\'t parse json: ' .. result.stdout, {} + elseif data.error then + return 'Ziggy error: ' .. data.message, {} + else + return nil, data end +end - if result.status == 0 then - local data = utils.parse_json(result.stdout) - if data and data.payload then - return data.payload +---@param args (string|number)[] +---@param callback fun(error: string|nil, data: table) +---@return fun() abort Function to abort the request. +function call_ziggy_async(args, callback) + local abort_signal = mp.command_native_async({ + name = 'subprocess', + capture_stderr = true, + capture_stdout = true, + playback_only = false, + args = itable_join({config.ziggy_path}, args), + }, function(success, result, error) + if not success or not result or result.status ~= 0 then + local exit_code = (result and result.status or 'unknown') + local message = error or (result and result.stdout .. result.stderr) or '' + callback('Calling ziggy failed. Exit code: ' .. exit_code .. ' Error: ' .. message, {}) + return + end + + local json = result and type(result.stdout) == 'string' and result.stdout or '' + local data = utils.parse_json(json) + if not data then + callback('Ziggy response error. Couldn\'t parse json: ' .. json, {}) + elseif data.error then + callback('Ziggy error: ' .. data.message, {}) else - print_error(data and (data.error and data.message or 'unknown error') or 'couldn\'t parse json') + return callback(nil, data) end - else - print_error('exit code ' .. result.status .. ': ' .. result.stdout .. result.stderr) + end) + + return function() + mp.abort_async_command(abort_signal) + end +end + +---@return string|nil +function get_clipboard() + local err, data = call_ziggy({'get-clipboard'}) + if err then + mp.commandv('show-text', 'Get clipboard error. See console for details.') + msg.error(err) + end + return data and data.payload +end + +---@param payload any +---@return string|nil payload String that was copied to clipboard. +function set_clipboard(payload) + local err, data = call_ziggy({'set-clipboard', tostring(payload)}) + if err then + mp.commandv('show-text', 'Set clipboard error. See console for details.') + msg.error(err) end + return data and data.payload end --[[ RENDERING ]]