LINUX.ORG.RU

MPV. Отправить команду другой программе

 ,


0

1

Пытаюсь сделать скрипт, который отправит команду файловому менеджеру — открыть расположение файла, который воспроизводится в данный момент.

require 'mp'

local function GoToFile()
  local filename = string.format("%s", mp.get_property_osd("filename"))
  local filepath = string.format("%s/%s", mp.get_property_osd("working-directory"), mp.get_property_osd("path"))
  os.execute('doublecmd -c -t "' .. filepath .. '/' .. filename .. '" &')
end

-- Key-Bindings
mp.add_key_binding("Ctrl+o", "GoToFile", GoToFile)

вроде всё верно, но скрипт не работает :(

Ошибки не показывает.

Как сделать, чтобы работало?

Ответ на: комментарий от Dreamdrawer

Или я не так понимаю?

Не так.

os.execute для выполнения команды передает ее в shell а не запускает бинарник напрямую.

А это значит, что можно в строке творить все, что угодно. И ; из имени файла будет интерпритироваться как разделитель команд.

Нужно имя файла эскейпить, или найти функцию lua, которая не запускает shell.

Belkrr
()
Ответ на: комментарий от Belkrr

Собственно если б он запускал бинарник напрямую - ситуация была бы хоть и лучше но не до конца. Ведь команды перед запуском всё равно надо распарсить, и если в имени файла кавычки (которые в приведённом коде не экранируются) - парсер либо распарсит всё это неправильно, либо обнаружит синтаксическую ошибку. То есть сломается, хоть вроде и без вредительства.

firkax ★★★★★
()
Ответ на: комментарий от Belkrr

Так, хорошо, а что можете сказать об этом скрипте? Насколько могу судить, там как раз заэскейпили имена. Можно ли рассматривать этот скрипт как безопасный в этом отношении?

Вот как это выглядит:

-- DEBUGGING
--
-- Debug messages will be printed to stdout with mpv command line option
-- `--msg-level='locatefile=debug'`

local msg = require('mp.msg')
local mputils = require('mp.utils')

-- for ubuntu
url_browser_linux_cmd = "xdg-open \"$url\""
file_browser_linux_cmd = "dbus-send --print-reply --dest=org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1.ShowItems array:string:\"file:$path\" string:\"\""
-- for macos
url_browser_macos_cmd = "open \"$url\""
-- file_browser_macos_cmd = "osascript -e 'tell application \"Finder\"' -e 'set frontmost to true' -e 'reveal (POSIX file \"$path\")' -e 'end tell'"
file_browser_macos_cmd = "open -a Finder -R \"$path\""
-- for windows
url_browser_windows_cmd = "explorer \"$url\""
file_browser_windows_cmd = "С:\\Tools\\doublecmd\\doublecmd.exe -c -t \"$path\""

--// check if it's a url/stream
function is_url(path)
  if path ~= nil and string.sub(path,1,4) == "http" then
    return true
  else
    return false
  end
end

--// check if macos
function is_macos()
  local homedir = os.getenv("HOME")
  if homedir ~= nil and string.sub(homedir,1,6) == "/Users" then
    return true
  else
    return false
  end
end

--// check if windows
function is_windows()
  local windir = os.getenv("windir")
  if windir~=nil then
    return true
  else
    return false
  end
end

--// create temporary script
function create_temp_file(content)
  local tmp_filename = os.tmpname()
  local tmp_file = io.open(tmp_filename, "wb")
  tmp_file:write(content)
  io.close(tmp_file)
  return tmp_filename
end

--// path separator stuffs
 function path_sep()
  if is_windows() then
    return "\\"
  else
    return "/"
  end
end
function split_by_separator(filepath)
  local t = {}
  local part_pattern = string.format("([^%s]+)", path_sep())
  for str in filepath:gmatch(part_pattern) do
    table.insert(t, str)
  end
  return t
end
function path_root()
  if path_sep() == "/" then
    return "/"
  else
    return ""
  end
end

--// Extract file dir from url
function normalize(relative_path, base_dir)
  base_dir = base_dir or mputils.getcwd()
  local full_path = mputils.join_path(base_dir, relative_path)

  local parts = split_by_separator(full_path)
  local idx = 1
  repeat
    if parts[idx] == ".." then
      table.remove(parts, idx)
      table.remove(parts, idx - 1)
      idx = idx - 2
    elseif parts[idx] == "." then
      table.remove(parts, idx)
      idx = idx - 1
    end
    idx = idx + 1
  until idx > #parts

  return path_root() .. table.concat(parts, path_sep())
end

--// handle "locate-current-file" function triggered by a key in "input.conf"
function locate_current_file()
  local path = mp.get_property("path")
  if path ~= nil then
    local cmd = ""
    if is_url(path) then
      msg.debug("Url detected '" .. path .. "', your OS web browser will be launched.")
      if is_windows() then
        msg.debug("Windows detected.")
        cmd = url_browser_windows_cmd
      elseif is_macos() then
        msg.debug("macOS detected.")
        cmd = url_browser_macos_cmd
      else
        msg.debug("Linux detected.")
        cmd = url_browser_linux_cmd
      end
      cmd = cmd:gsub("$url", path)
    else
      msg.debug("File detected '" .. path .. "', your OS file browser will be launched.")
      if is_windows() then
        msg.debug("Windows detected.")
        cmd = file_browser_windows_cmd
        path = path:gsub("/", "\\")
      elseif is_macos() then
        msg.debug("macOS detected.")
        cmd = file_browser_macos_cmd
      else
        msg.debug("Linux detected.")
        cmd = file_browser_linux_cmd
      end
      path = normalize(path)
      cmd = cmd:gsub("$path", path)
    end
    msg.debug("Command to be executed: '" .. cmd .. "'")
    mp.osd_message('Browse \n' .. path)
    os.execute(cmd)
  else
    msg.debug("'path' property was empty, no media has been loaded.")
  end
end

mp.add_key_binding(nil, "locate-current-file", locate_current_file)

Я тут далеко не всё понимаю, но адаптировать под Double Commander у меня получилось. Работает.

Dreamdrawer
() автор топика
Последнее исправление: Dreamdrawer (всего исправлений: 1)
Ответ на: комментарий от Dreamdrawer

Насколько могу судить, там как раз заэскейпили имена.

Нет. В скрипте много кода, но это определение урлов и обработка относительных путей.

Нашел в доке mpv команду для запуска внешних программ без промежуточного вызова shell.

Замени os.execute(cmd) на mp.commandv("run", "doublecmd", "-c" "-t", path)

Ну и минимальный работающий вариант почти аналогичен твоему изначальному:

function locate_current_file()
  local path = mp.get_property("path")
  if path:sub(1, 1) ~= "/" then
    path = mp.get_property("working-directory") .. path
  end
  mp.commandv("run", "doublecmd", "-c" "-t", path)
end

mp.add_key_binding("Ctrl+o", "locate-current-file", locate_current_file)
Belkrr
()