mirror of
https://github.com/fergalmoran/picard.git
synced 2026-01-06 08:34:01 +00:00
Added remote command: FROM_FILE
Remote commands can be read directly from a file (one per line). Lines starting with `#` and empty lines are ignored.
This commit is contained in:
@@ -53,6 +53,7 @@ import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import signal
|
||||
import sys
|
||||
@@ -229,6 +230,11 @@ REMOTE_COMMANDS = {
|
||||
"handle_command_fingerprint",
|
||||
help_text="Calculate acoustic fingerprints for all (matched) files in the album pane.",
|
||||
),
|
||||
"FROM_FILE": RemoteCommand(
|
||||
"handle_command_from_file",
|
||||
help_text="Load command pipeline from a file.",
|
||||
help_args="[Absolute path to a file containing command pipeline]",
|
||||
),
|
||||
"LOAD": RemoteCommand(
|
||||
"handle_command_load",
|
||||
help_text="Load 1 or more files/MBIDs/URLs to Picard.",
|
||||
@@ -491,6 +497,29 @@ class Tagger(QtWidgets.QApplication):
|
||||
for album_name in self.albums:
|
||||
self.analyze(self.albums[album_name].iterfiles())
|
||||
|
||||
@staticmethod
|
||||
def _read_lines_from_file(filepath):
|
||||
try:
|
||||
yield from (line.strip() for line in open(filepath).readlines())
|
||||
except Exception as e:
|
||||
log.error("Error reading command file '%s': %s" % (filepath, e))
|
||||
|
||||
@staticmethod
|
||||
def _parse_commands_from_lines(lines):
|
||||
for line in lines:
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
elements = shlex.split(line)
|
||||
if not elements:
|
||||
continue
|
||||
command_args = elements[1:] or ['']
|
||||
for element in command_args:
|
||||
yield f"command://{elements[0]} {element}"
|
||||
|
||||
def handle_command_from_file(self, argstring):
|
||||
for command in self._parse_commands_from_lines(self._read_lines_from_file(argstring)):
|
||||
self.handle_command(command)
|
||||
|
||||
def handle_command_load(self, argstring):
|
||||
if argstring.startswith("command://"):
|
||||
log.error("Cannot LOAD a command: %s", argstring)
|
||||
|
||||
47
test/test_parsing_files_with_commands.py
Normal file
47
test/test_parsing_files_with_commands.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from test.picardtestcase import PicardTestCase
|
||||
|
||||
from picard.tagger import Tagger
|
||||
|
||||
|
||||
class TestParsingFilesWithCommands(PicardTestCase):
|
||||
|
||||
MOCK_FILE_CONTENTS = (
|
||||
# should be split into 2 commands
|
||||
"LOAD file1.mp3 file2.mp3",
|
||||
# should be added as one
|
||||
"FROM_FILE file0.mp3",
|
||||
"CLUSTER",
|
||||
" FINGERPRINT "
|
||||
# should be ignored
|
||||
"",
|
||||
" ",
|
||||
"\n",
|
||||
"#commented command",
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.result = tuple(x for x in Tagger._parse_commands_from_lines(self.MOCK_FILE_CONTENTS))
|
||||
|
||||
def test_no_argument_command(self):
|
||||
self.assertIn("command://CLUSTER ", self.result)
|
||||
|
||||
def test_no_argument_command_stripped_correctly(self):
|
||||
self.assertIn("command://FINGERPRINT ", self.result)
|
||||
|
||||
def test_single_argument_command(self):
|
||||
self.assertIn("command://FROM_FILE file0.mp3", self.result)
|
||||
|
||||
def test_multiple_arguments_command(self):
|
||||
self.assertIn("command://LOAD file1.mp3", self.result)
|
||||
self.assertIn("command://LOAD file2.mp3", self.result)
|
||||
|
||||
def test_empty_lines(self):
|
||||
self.assertNotIn("command:// ", self.result)
|
||||
self.assertNotIn("command://", self.result)
|
||||
# 1 FROM_FILE
|
||||
# 2 LOADs
|
||||
self.assertEqual(len(self.result), 5)
|
||||
|
||||
def test_commented_lines(self):
|
||||
self.assertNotIn("command://#commented command", self.result)
|
||||
Reference in New Issue
Block a user