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)

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

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

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

Вместо/перед добавь вывод в консоль того же самого 'doublecmd -c -t "' .. filepath .. '/' .. filename .. '" &', посмотри, что выводит. Оно выглядит правильно? Если его вот так, как оно выведено, скопипастить в шелл, выполнится как надо?


upd: проверил. Ну конечно. У тебя filepath уже содержит в себе имя файла. Присоединять к нему filename ещё раз не надо. 'doublecmd -c -t "' .. filepath .. '" &'. Будет работать. Но обрати внимание на комментарий выше. Так делать небезопасно.

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 4)

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

-os.execute('doublecmd -c -t "' .. filepath .. '/' .. filename .. '" &')
+os.execute('doublecmd -c -t "' .. filepath .. '" &')

Хотя в filepath путь и так абсолютный, так что просто filename лишнее. А по поводу не надо самого имени файла это я попутал, так как на nemo проверял. В любом случае filename лишний

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
sudo apt get install lua-posix
-- у меня в Debian Sid mpv собран с lua5.2,но пути
-- поиска почему-то для 5.1 по этому подменяю пути
-- убери эти две строчки если всё работает без них
package.path  = package.path:gsub("5%.1","5.2")
package.cpath = package.cpath:gsub("5%.1","5.2")

require 'mp'
local posix = require 'posix'

local function GoToFile()
  local cpwd = mp.get_property_osd("working-directory")
  local path = mp.get_property_osd("path")
  local filepath = string.format("%s/%s",cpwd,path)
  -- форкаем процесс
  local pid = posix.unistd.fork()
  -- если дочка то открываем ФМ
  if pid == 0 then
     posix.unistd.execp('doublecmd',{'-c','-t',filepath})
     exit(0)
  end
end

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

Мне самому надо переписывать программы под lua-posix сам везде дёргаю execute/popen, местами с

function shell_escape(text)
    text = "'" .. text:gsub("'", "'\\''") .. "'" -- escape special symbols
    return text:gsub(" ","'\\ '") -- allow space for local file path
end

Предложенным @shdown

Аналогичное на opennet написано, не помню ссылку. Но лучше через os.execute и popen дёргать то что не имеет произвольных параметров, а если имеет то дёргать через lua-posix или иные механизмы прямого доступа к POSIX API включая свои модули для этого, может и у mpv есть из коробки API для этого, но глядя по диагонали не нашёл.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Что за велосипед ты изобрёл на этот раз?

https://mpv.io/manual/master/#lua-scripting-utils-subprocess-detached(t)

Если использоать эту функцию, то не нужно запускать шелл или экранировать args.

    return text:gsub(" ","'\\ '") -- allow space for local file path

А в чём смысл этого?

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

Если использоать эту функцию, то не нужно запускать шелл или экранировать args.

Ну, вот как сказал по диагонали не заметил нужного

может и у mpv есть из коробки API для этого, но глядя по диагонали не нашёл.

А в чём смысл этого?

Не помню уже, что-то с дальнейшей конкатенацией было связано, удалить забыл. Вместо cmd 'lalala lalala' было cmd 'lalala'\ 'lalala'. Но вот, зачем так делал уже не помню. Вырвал из заметок, а не итогового кода.

Что за велосипед ты изобрёл на этот раз?

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от firkax

если имя файла будет примерно таким "; rm -Rf "/home оно запустит удаление home по этому скрипту

Но ведь имя файла не передаётся в консоль на исполнение, а вызывается файловый менеджер, который не умеет исполнять команды, он может лишь отобразить указанный в параметрах путь. И если этот путь будет выглядеть как команда, он её выполнять не станет. Или я не так понимаю?

Dreamdrawer
() автор топика
Последнее исправление: Dreamdrawer (всего исправлений: 2)
Ответ на: комментарий от 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
()