From f105a1cf1d250328649957eb963405a3d27af39a Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Thu, 29 Jul 2021 02:01:08 +0200 Subject: [PATCH 01/10] Add a command `fileopen` to open files using external programs --- stig/commands/base/file.py | 120 +++++++++++++++++++++++++++++++++++++ stig/commands/cli/file.py | 6 ++ stig/commands/tui/file.py | 7 +++ 3 files changed, 133 insertions(+) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 1ea2211b..2dfce34c 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -11,11 +11,14 @@ import asyncio +from subprocess import Popen, DEVNULL + from . import _mixin as mixin from .. import CmdError, CommandMeta from ... import objects from ...completion import candidates from ._common import make_COLUMNS_doc, make_SCRIPTING_doc, make_X_FILTER_spec +from natsort import humansorted from ...logging import make_logger # isort:skip log = make_logger(__name__) @@ -166,3 +169,120 @@ def completion_candidates_posargs(cls, args): elif args.curarg_index == 3: torrent_filter = args[2] return candidates.file_filter(args.curarg, torrent_filter) + +class FOpenCmdbase(metaclass=CommandMeta): + name = 'fileopen' + aliases = ('fopen',) + provides = set() + category = 'file' + description = 'Open files using an external command' + examples = ('fileopen "that torrent" *.mkv', + 'fileopen "that torrent" *.mkv mpv' + 'fileopen "that torrent" *.mkv mpv --fullscreen',) + argspecs = ( + make_X_FILTER_spec('TORRENT', or_focused=True, nargs='?'), + make_X_FILTER_spec('FILE', or_focused=True, nargs='?'), + {"names": ('COMMAND',), + 'description': "Command to use to open files. Default: xdg-open", + 'nargs': '?' + }, + {"names": ('OPTS',), + 'description': "Options for the external command.", + 'nargs': 'REMAINDER' + }, + ) + async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): + default_command = 'xdg-open' + if COMMAND is None: + command = default_command + else: + command = COMMAND + opts = [] + if not OPTS is None: + opts = OPTS + utilize_tui = not bool(TORRENT_FILTER) + try: + tfilter = self.select_torrents(TORRENT_FILTER, + allow_no_filter=False, + discover_torrent=True) + + # If the user specified a filter instead of selecting via the TUI, + # ignore focused/marked files. + log.debug('%sdiscovering file(s)', '' if utilize_tui else 'Not ') + ffilter = self.select_files(FILE_FILTER, + allow_no_filter=True, + discover_file=utilize_tui) + except ValueError as e: + raise CmdError(e) + + if not utilize_tui: + self.info('Opening %s from torrents %s with %s %s' % + ('all files' if ffilter is None else ffilter, tfilter, + command, opts)) + quiet = False + else: + # We're operating on focused or marked files and changes are + # indiciated by the updated file list, so no info messages + # necessary. + quiet = True + + self.info('Opening %s from torrents %s with %s %s' % + ('all files' if ffilter is None else ffilter, tfilter, + command, opts)) + files = await self.make_file_list(tfilter, ffilter) + if command == default_command: + for f in files: + Popen([default_command, f], stdout=DEVNULL, stderr=DEVNULL) + else: + Popen([command] + opts + files, stdout=DEVNULL, stderr=DEVNULL) + + return None + + async def make_file_list(self, tfilter, ffilter): + response = await self.make_request( + objects.srvapi.torrent.torrents(tfilter, keys=('name', 'files')), + quiet=True) + torrents = response.torrents + + if len(torrents) < 1: + raise CmdError() + + filelist = [] + for torrent in humansorted(torrents, key=lambda t: t['name']): + files, filtered_count = self._flatten_tree(torrent['files'], ffilter) + filelist.extend(files) + + if filelist: + return filelist + else: + if str(tfilter) != 'all': + raise CmdError('No matching files in %s torrents: %s' % (tfilter, ffilter)) + else: + raise CmdError('No matching files: %s' % (ffilter)) + def _flatten_tree(self, files, ffilter=None): + flist = [] + filtered_count = 0 + def _match(ffilter, value): + if ffilter is None: + return True + try: + return ffilter.match(value) + except AttributeError: + pass + try: + return value['id'] in ffilter + except (KeyError, TypeError): + pass + return False + for key,value in humansorted(files.items(), key=lambda pair: pair[0]): + if value.nodetype == 'leaf': + if _match(ffilter, value) and value['size-downloaded'] == value['size-total']: + flist.append(value['path-absolute']) + else: + filtered_count += 1 + + elif value.nodetype == 'parent': + sub_flist, sub_filtered_count = self._flatten_tree(value, ffilter) + flist.extend(sub_flist) + + return flist, filtered_count diff --git a/stig/commands/cli/file.py b/stig/commands/cli/file.py index 66c85c19..fbbf9f1a 100644 --- a/stig/commands/cli/file.py +++ b/stig/commands/cli/file.py @@ -26,6 +26,7 @@ class ListFilesCmd(base.ListFilesCmdbase, mixin.only_supported_columns): provides = {'cli'} + async def make_file_list(self, tfilter, ffilter, columns): response = await self.make_request( objects.srvapi.torrent.torrents(tfilter, keys=('name', 'files')), @@ -91,3 +92,8 @@ def indent(node): class PriorityCmd(base.PriorityCmdbase, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'cli'} + +class FOpenCmd(base.FOpenCmdbase, + mixin.make_request, mixin.select_torrents, + mixin.select_files): + provides = {'cli'} diff --git a/stig/commands/tui/file.py b/stig/commands/tui/file.py index b593cf53..600e9ba3 100644 --- a/stig/commands/tui/file.py +++ b/stig/commands/tui/file.py @@ -30,3 +30,10 @@ def make_file_list(self, tfilter, ffilter, columns): class PriorityCmd(base.PriorityCmdbase, mixin.polling_frenzy, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} +class FOpenCmd(base.FOpenCmdbase, + mixin.polling_frenzy, mixin.make_request, + mixin.select_torrents, mixin.select_files): + provides = {'tui'} + # Ugly hack to make the command behave as expected in the tui + async def run(self, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): + await base.FOpenCmdbase.run(self, TORRENT_FILTER=COMMAND, FILE_FILTER=FILE_FILTER, COMMAND=TORRENT_FILTER, OPTS=OPTS) From 4c2d214953fcac448eb9d4ed8986d9f60c5b414e Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 9 Aug 2021 16:08:57 +0100 Subject: [PATCH 02/10] remove unneeded dependency --- stig/commands/tui/file.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stig/commands/tui/file.py b/stig/commands/tui/file.py index 600e9ba3..e1b4b011 100644 --- a/stig/commands/tui/file.py +++ b/stig/commands/tui/file.py @@ -30,9 +30,7 @@ def make_file_list(self, tfilter, ffilter, columns): class PriorityCmd(base.PriorityCmdbase, mixin.polling_frenzy, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} -class FOpenCmd(base.FOpenCmdbase, - mixin.polling_frenzy, mixin.make_request, - mixin.select_torrents, mixin.select_files): +class FOpenCmd(base.FOpenCmdbase, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} # Ugly hack to make the command behave as expected in the tui async def run(self, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): From de767d3ae2d2f30ff04dadf695bf2551c91ecdb3 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 9 Aug 2021 16:09:17 +0100 Subject: [PATCH 03/10] Improve explanation of fopen tui command --- stig/commands/tui/file.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stig/commands/tui/file.py b/stig/commands/tui/file.py index e1b4b011..05d63ba9 100644 --- a/stig/commands/tui/file.py +++ b/stig/commands/tui/file.py @@ -32,6 +32,8 @@ class PriorityCmd(base.PriorityCmdbase, provides = {'tui'} class FOpenCmd(base.FOpenCmdbase, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} - # Ugly hack to make the command behave as expected in the tui + # When files are selected in the tui, the two first arguments, the torrent + # and the file(s) need to be filled in. That is, `fopen mpv` should mean + # `fopen torrent file mpv` async def run(self, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): await base.FOpenCmdbase.run(self, TORRENT_FILTER=COMMAND, FILE_FILTER=FILE_FILTER, COMMAND=TORRENT_FILTER, OPTS=OPTS) From c170d8adba096b9aee4dfeb954a80219c8502a00 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 9 Aug 2021 16:42:37 +0100 Subject: [PATCH 04/10] fopen: capture and log stdout and stderr --- stig/commands/base/file.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 2dfce34c..cb406df7 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -12,6 +12,7 @@ import asyncio from subprocess import Popen, DEVNULL +from subprocess import run as subprocessrun from . import _mixin as mixin from .. import CmdError, CommandMeta @@ -230,12 +231,24 @@ async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): ('all files' if ffilter is None else ffilter, tfilter, command, opts)) files = await self.make_file_list(tfilter, ffilter) - if command == default_command: - for f in files: - Popen([default_command, f], stdout=DEVNULL, stderr=DEVNULL) + stdoutbuffer = DEVNULL + stderrbuffer = DEVNULL + # TODO separate options for stdout/stderr + try: + if command == default_command: + for f in files: + result = subprocessrun([default_command, f], capture_output = True, text = True) + else: + result = subprocessrun([command] + opts + files, capture_output = True, text = True) + except FileNotFoundError as e: + self.error("Command not found: %s" % command) else: - Popen([command] + opts + files, stdout=DEVNULL, stderr=DEVNULL) - + stdout = result.stdout.rstrip('\r\n') + stderr = result.stderr.rstrip('\r\n') + if len(stdout): + self.info(stdout) + if len(stderr): + self.error(stderr) return None async def make_file_list(self, tfilter, ffilter): From c7e103998cf9c8ef074a774100c93c9540c593e6 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 9 Aug 2021 16:42:57 +0100 Subject: [PATCH 05/10] fopen: cleaner log message --- stig/commands/base/file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index cb406df7..9c9120d8 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -229,7 +229,7 @@ async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): self.info('Opening %s from torrents %s with %s %s' % ('all files' if ffilter is None else ffilter, tfilter, - command, opts)) + command, " ".join(opts))) files = await self.make_file_list(tfilter, ffilter) stdoutbuffer = DEVNULL stderrbuffer = DEVNULL From 389ee3699fc7c48ab2a3684c028cd0043cf3e488 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Tue, 2 Nov 2021 11:48:32 +0000 Subject: [PATCH 06/10] fopen: respect links --- stig/commands/base/file.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 9c9120d8..74fcbb42 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -264,7 +264,10 @@ async def make_file_list(self, tfilter, ffilter): for torrent in humansorted(torrents, key=lambda t: t['name']): files, filtered_count = self._flatten_tree(torrent['files'], ffilter) filelist.extend(files) - + filelist = map( + lambda f: objects.pathtranslator.to_local( str(f) ), + filelist + ) if filelist: return filelist else: From fffd35a8ee9931867e21020660fb37104dc2503b Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 11 Apr 2022 05:15:51 +0200 Subject: [PATCH 07/10] fopen: refactor to use subprocess.Popen instead of subprocess.run subprocess.run blocks. This means that the child process must exit before the user can contine to interact with stig. Using subprocess.Popen instead fixes this. Using pipes and asyncio, stdout and stderr from the child process will appear asynchronously in the log. --- stig/commands/base/file.py | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 74fcbb42..42b7a088 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -11,8 +11,9 @@ import asyncio -from subprocess import Popen, DEVNULL -from subprocess import run as subprocessrun +from subprocess import Popen, DEVNULL, PIPE +from threading import Thread +from time import sleep from . import _mixin as mixin from .. import CmdError, CommandMeta @@ -171,6 +172,7 @@ def completion_candidates_posargs(cls, args): torrent_filter = args[2] return candidates.file_filter(args.curarg, torrent_filter) + class FOpenCmdbase(metaclass=CommandMeta): name = 'fileopen' aliases = ('fopen',) @@ -231,24 +233,45 @@ async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): ('all files' if ffilter is None else ffilter, tfilter, command, " ".join(opts))) files = await self.make_file_list(tfilter, ffilter) - stdoutbuffer = DEVNULL - stderrbuffer = DEVNULL + + def pipelog(pipe, logger): + s = pipe.readline() + for l in s.split("\n"): + if len(l): + logger(l) + def closepipes(proc): + loop = asyncio.get_running_loop() + if proc.poll() is None: + loop.call_later(0.1, lambda: closepipes(proc)) + return + loop.remove_reader(proc.stdout) + loop.remove_reader(proc.stderr) + + # TODO separate options for stdout/stderr + stdoutlogger = lambda s: self.info(command + ": " + s) + stderrlogger = lambda s: self.error(command + ": " + s) + loop = asyncio.get_running_loop() try: if command == default_command: for f in files: - result = subprocessrun([default_command, f], capture_output = True, text = True) + result = Popen([default_command, f], + stdout = PIPE, + stderr = PIPE, + text = True) + loop.add_reader(result.stdout, pipelog, result.stdout, stdoutlogger) + loop.add_reader(result.stderr, pipelog, result.stderr, stderrlogger) + loop.call_soon(lambda: closepipes(result)) else: - result = subprocessrun([command] + opts + files, capture_output = True, text = True) + result = Popen([command] + opts + list(files), + stdout = PIPE, + stderr = PIPE, + text = True) + loop.add_reader(result.stdout, pipelog, result.stdout, stdoutlogger) + loop.add_reader(result.stderr, pipelog, result.stderr, stderrlogger) + loop.call_soon(lambda: closepipes(result)) except FileNotFoundError as e: self.error("Command not found: %s" % command) - else: - stdout = result.stdout.rstrip('\r\n') - stderr = result.stderr.rstrip('\r\n') - if len(stdout): - self.info(stdout) - if len(stderr): - self.error(stderr) return None async def make_file_list(self, tfilter, ffilter): From de4e2ddecd67f88cdc87ae83e196e654f2cc9123 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 11 Apr 2022 05:49:06 +0200 Subject: [PATCH 08/10] fopen: remove unnecessary code --- stig/commands/base/file.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 42b7a088..aa324dbb 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -222,12 +222,6 @@ async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): self.info('Opening %s from torrents %s with %s %s' % ('all files' if ffilter is None else ffilter, tfilter, command, opts)) - quiet = False - else: - # We're operating on focused or marked files and changes are - # indiciated by the updated file list, so no info messages - # necessary. - quiet = True self.info('Opening %s from torrents %s with %s %s' % ('all files' if ffilter is None else ffilter, tfilter, From 882fde43ae458ec1801e99ca411aca50a014bf0d Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Mon, 11 Apr 2022 05:49:36 +0200 Subject: [PATCH 09/10] fopen: add flag -q to suppress stdout from external command pass twice to also suppress stderr --- stig/commands/base/file.py | 17 +++++++++++------ stig/commands/tui/file.py | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index aa324dbb..519ee7c1 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -12,8 +12,6 @@ import asyncio from subprocess import Popen, DEVNULL, PIPE -from threading import Thread -from time import sleep from . import _mixin as mixin from .. import CmdError, CommandMeta @@ -183,18 +181,21 @@ class FOpenCmdbase(metaclass=CommandMeta): 'fileopen "that torrent" *.mkv mpv' 'fileopen "that torrent" *.mkv mpv --fullscreen',) argspecs = ( + {'names': ('--quiet', '-q'), + 'description': 'Suppress stdout from the external command. Pass twice to also suppress stderr', + 'action': 'count', 'default': 0}, make_X_FILTER_spec('TORRENT', or_focused=True, nargs='?'), make_X_FILTER_spec('FILE', or_focused=True, nargs='?'), - {"names": ('COMMAND',), - 'description': "Command to use to open files. Default: xdg-open", + {'names': ('COMMAND',), + 'description': 'Command to use to open files. Default: xdg-open', 'nargs': '?' }, - {"names": ('OPTS',), + {'names': ('OPTS',), 'description': "Options for the external command.", 'nargs': 'REMAINDER' }, ) - async def run(self, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): + async def run(self, quiet, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): default_command = 'xdg-open' if COMMAND is None: command = default_command @@ -244,7 +245,11 @@ def closepipes(proc): # TODO separate options for stdout/stderr stdoutlogger = lambda s: self.info(command + ": " + s) + if quiet >= 1: + stdoutlogger = lambda s: None stderrlogger = lambda s: self.error(command + ": " + s) + if quiet >= 2: + stderrlogger = lambda s: None loop = asyncio.get_running_loop() try: if command == default_command: diff --git a/stig/commands/tui/file.py b/stig/commands/tui/file.py index 05d63ba9..9db43885 100644 --- a/stig/commands/tui/file.py +++ b/stig/commands/tui/file.py @@ -35,5 +35,5 @@ class FOpenCmd(base.FOpenCmdbase, mixin.make_request, mixin.select_torrents, mix # When files are selected in the tui, the two first arguments, the torrent # and the file(s) need to be filled in. That is, `fopen mpv` should mean # `fopen torrent file mpv` - async def run(self, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): - await base.FOpenCmdbase.run(self, TORRENT_FILTER=COMMAND, FILE_FILTER=FILE_FILTER, COMMAND=TORRENT_FILTER, OPTS=OPTS) + async def run(self, quiet, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): + await base.FOpenCmdbase.run(self, quiet, TORRENT_FILTER=COMMAND, FILE_FILTER=FILE_FILTER, COMMAND=TORRENT_FILTER, OPTS=OPTS) From f4485dfbfcf9cd1bbbc511af8ab070deb3a31f83 Mon Sep 17 00:00:00 2001 From: Robin Ekman Date: Thu, 21 Apr 2022 13:32:49 +0200 Subject: [PATCH 10/10] fopen: linting --- stig/commands/base/file.py | 36 ++++++++++++++++++++---------------- stig/commands/cli/file.py | 2 +- stig/commands/tui/file.py | 2 ++ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/stig/commands/base/file.py b/stig/commands/base/file.py index 519ee7c1..7ef532e1 100644 --- a/stig/commands/base/file.py +++ b/stig/commands/base/file.py @@ -11,7 +11,7 @@ import asyncio -from subprocess import Popen, DEVNULL, PIPE +from subprocess import Popen, PIPE from . import _mixin as mixin from .. import CmdError, CommandMeta @@ -189,12 +189,13 @@ class FOpenCmdbase(metaclass=CommandMeta): {'names': ('COMMAND',), 'description': 'Command to use to open files. Default: xdg-open', 'nargs': '?' - }, + }, {'names': ('OPTS',), 'description': "Options for the external command.", 'nargs': 'REMAINDER' - }, + }, ) + async def run(self, quiet, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): default_command = 'xdg-open' if COMMAND is None: @@ -202,7 +203,7 @@ async def run(self, quiet, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): else: command = COMMAND opts = [] - if not OPTS is None: + if OPTS is not None: opts = OPTS utilize_tui = not bool(TORRENT_FILTER) try: @@ -231,9 +232,10 @@ async def run(self, quiet, TORRENT_FILTER, FILE_FILTER, COMMAND, OPTS): def pipelog(pipe, logger): s = pipe.readline() - for l in s.split("\n"): - if len(l): - logger(l) + for ln in s.split("\n"): + if len(ln): + logger(ln) + def closepipes(proc): loop = asyncio.get_running_loop() if proc.poll() is None: @@ -255,21 +257,21 @@ def closepipes(proc): if command == default_command: for f in files: result = Popen([default_command, f], - stdout = PIPE, - stderr = PIPE, - text = True) + stdout=PIPE, + stderr=PIPE, + text=True) loop.add_reader(result.stdout, pipelog, result.stdout, stdoutlogger) loop.add_reader(result.stderr, pipelog, result.stderr, stderrlogger) loop.call_soon(lambda: closepipes(result)) else: result = Popen([command] + opts + list(files), - stdout = PIPE, - stderr = PIPE, - text = True) + stdout=PIPE, + stderr=PIPE, + text=True) loop.add_reader(result.stdout, pipelog, result.stdout, stdoutlogger) loop.add_reader(result.stderr, pipelog, result.stderr, stderrlogger) loop.call_soon(lambda: closepipes(result)) - except FileNotFoundError as e: + except FileNotFoundError: self.error("Command not found: %s" % command) return None @@ -287,7 +289,7 @@ async def make_file_list(self, tfilter, ffilter): files, filtered_count = self._flatten_tree(torrent['files'], ffilter) filelist.extend(files) filelist = map( - lambda f: objects.pathtranslator.to_local( str(f) ), + lambda f: objects.pathtranslator.to_local(str(f)), filelist ) if filelist: @@ -297,14 +299,16 @@ async def make_file_list(self, tfilter, ffilter): raise CmdError('No matching files in %s torrents: %s' % (tfilter, ffilter)) else: raise CmdError('No matching files: %s' % (ffilter)) + def _flatten_tree(self, files, ffilter=None): flist = [] filtered_count = 0 + def _match(ffilter, value): if ffilter is None: return True try: - return ffilter.match(value) + return ffilter.match(value) except AttributeError: pass try: diff --git a/stig/commands/cli/file.py b/stig/commands/cli/file.py index fbbf9f1a..594a58ce 100644 --- a/stig/commands/cli/file.py +++ b/stig/commands/cli/file.py @@ -94,6 +94,6 @@ class PriorityCmd(base.PriorityCmdbase, provides = {'cli'} class FOpenCmd(base.FOpenCmdbase, - mixin.make_request, mixin.select_torrents, + mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'cli'} diff --git a/stig/commands/tui/file.py b/stig/commands/tui/file.py index 9db43885..5916bdf6 100644 --- a/stig/commands/tui/file.py +++ b/stig/commands/tui/file.py @@ -30,10 +30,12 @@ def make_file_list(self, tfilter, ffilter, columns): class PriorityCmd(base.PriorityCmdbase, mixin.polling_frenzy, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} + class FOpenCmd(base.FOpenCmdbase, mixin.make_request, mixin.select_torrents, mixin.select_files): provides = {'tui'} # When files are selected in the tui, the two first arguments, the torrent # and the file(s) need to be filled in. That is, `fopen mpv` should mean # `fopen torrent file mpv` + async def run(self, quiet, COMMAND, TORRENT_FILTER, FILE_FILTER, OPTS): await base.FOpenCmdbase.run(self, quiet, TORRENT_FILTER=COMMAND, FILE_FILTER=FILE_FILTER, COMMAND=TORRENT_FILTER, OPTS=OPTS)