Added autocomplete for common options and argument values.

This commit is contained in:
Abdulmhsen B. A. A
2022-05-23 22:04:58 +03:00
parent b08c08db74
commit dcf4586bc0
10 changed files with 200 additions and 41 deletions

21
FAQ.md
View File

@@ -202,17 +202,26 @@ $ docker exec -ti watchstate console servers:edit --key options.client.timeout -
### Q: Can I search my server remote libraries?
Yes, Run the following command
Yes, you can search your backend media servers. You can use `--search '[searchTerm]'`
or `--search-id [backend_media_id]`. For example, to search for specific title keyword run the following command:
```bash
$ docker exec -ti console server servers:remote --search '[searchTerm]' -- [SERVER_NAME]
$ docker exec -ti console server servers:remote --search 'Gundam' -- [SERVER_NAME]
```
Flags:
or if you want to get a specific item metadata run the following command:
* (required) `--search` Search query. For example, `GUNDAM`.
* (optional) `--search-limit` To limit returned results. Defaults to `25`.
* (optional) `--search-output` Set output style, it can be `yaml` or `json`. Defaults to `json`.
```bash
$ docker exec -ti console server servers:remote --search-id 2514 -- [SERVER_NAME]
```
### Optional flags related to `--search` and `--search-id`
Those flags can be combined with the search parameter
* `--search-raw` Return unfiltered response.
* `--search-limit` To limit returned results. Defaults to `25`.
* `--search-output` Set output style, it can be `yaml` or `json`. Defaults to `json`.
---

19
config/servers.spec.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
return [
'name',
'type',
'url',
'token',
'uuid',
'user',
'import.enabled',
'import.lastSync',
'export.enabled',
'export.lastSync',
'webhook.import',
'webhook.push',
'webhook.match.user',
'webhook.match.uuid',
'webhook.token',
];

View File

@@ -5,9 +5,12 @@ declare(strict_types=1);
namespace App;
use App\Libs\Config;
use DirectoryIterator;
use RuntimeException;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Symfony\Component\Console\Command\LockableTrait;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Xhgui\Profiler\Profiler;
@@ -130,4 +133,39 @@ class Command extends BaseCommand
return $config;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestOptionValuesFor('config')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (new DirectoryIterator(getcwd()) as $name) {
if (!$name->isFile()) {
continue;
}
if (empty($currentValue) || str_starts_with($name->getFilename(), $currentValue)) {
$suggest[] = $name->getFilename();
}
}
$suggestions->suggestValues($suggest);
}
if ($input->mustSuggestOptionValuesFor('servers-filter') || $input->mustSuggestArgumentValuesFor('server')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (array_keys(Config::get('servers', [])) as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Commands\Database;
use App\Command;
use App\Libs\Config;
use App\Libs\Container;
use App\Libs\Entity\StateInterface as iFace;
use App\Libs\Guid;
@@ -12,6 +13,8 @@ use App\Libs\Storage\StorageInterface;
use Exception;
use PDO;
use RuntimeException;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
@@ -313,4 +316,51 @@ final class ListCommand extends Command
return self::SUCCESS;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestOptionValuesFor('via') || $input->mustSuggestOptionValuesFor('metadata-as')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (array_keys(Config::get('servers', [])) as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
if ($input->mustSuggestOptionValuesFor('type')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach ([iFace::TYPE_MOVIE, iFace::TYPE_EPISODE] as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
if ($input->mustSuggestOptionValuesFor('output')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (['json', 'yaml', 'table'] as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -6,6 +6,8 @@ namespace App\Commands\Servers;
use App\Command;
use App\Libs\Config;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -23,14 +25,8 @@ final class EditCommand extends Command
->addOption('key', 'k', InputOption::VALUE_REQUIRED, 'Key to update.')
->addOption('set', 's', InputOption::VALUE_REQUIRED, 'Value to set.')
->addOption('delete', 'd', InputOption::VALUE_NONE, 'Delete value.')
->addOption(
'regenerate-api-key',
null,
InputOption::VALUE_NONE,
'Re-generate backend webhook token. *Not used. will be removed*'
)
->addOption('regenerate-webhook-token', 'g', InputOption::VALUE_NONE, 'Re-generate backend webhook token.')
->addArgument('name', InputArgument::REQUIRED, 'Server name');
->addArgument('server', InputArgument::REQUIRED, 'Backend name');
}
protected function runCommand(InputInterface $input, OutputInterface $output, null|array $rerun = null): int
@@ -55,7 +51,7 @@ final class EditCommand extends Command
$servers = (array)Config::get('servers', []);
}
$name = $input->getArgument('name');
$name = $input->getArgument('server');
if (!isValidName($name)) {
$output->writeln(
@@ -72,7 +68,7 @@ final class EditCommand extends Command
return self::FAILURE;
}
if ($input->getOption('regenerate-api-key') || $input->getOption('regenerate-webhook-token')) {
if ($input->getOption('regenerate-webhook-token')) {
try {
$apiToken = bin2hex(random_bytes(Config::get('webhook.tokenLength')));
@@ -156,4 +152,22 @@ final class EditCommand extends Command
return self::SUCCESS;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestOptionValuesFor('key')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (require __DIR__ . '/../../../config/servers.spec.php' as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -25,7 +25,7 @@ final class ManageCommand extends Command
->setDescription('Manage Server settings.')
->addOption('add', 'a', InputOption::VALUE_NONE, 'Add Server')
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
->addArgument('name', InputArgument::REQUIRED, 'Server name');
->addArgument('server', InputArgument::REQUIRED, 'Server name');
}
/**
@@ -71,7 +71,7 @@ final class ManageCommand extends Command
}
$add = $input->getOption('add');
$name = $input->getArgument('name');
$name = $input->getArgument('server');
if (!isValidName($name)) {
$output->writeln(
@@ -549,5 +549,4 @@ final class ManageCommand extends Command
return self::SUCCESS;
}
}

View File

@@ -31,13 +31,13 @@ final class RemoteCommand extends Command
->addOption('list-users', null, InputOption::VALUE_NONE, 'List Server users.')
->addOption('list-users-with-tokens', null, InputOption::VALUE_NONE, 'Show users list with tokens.')
->addOption('use-token', null, InputOption::VALUE_REQUIRED, 'Override server config token.')
->addOption('search', null, InputOption::VALUE_REQUIRED, 'Search query')
->addOption('search-id', null, InputOption::VALUE_REQUIRED, 'Get metadata related to given id')
->addOption('search', null, InputOption::VALUE_REQUIRED, 'Search query.')
->addOption('search-id', null, InputOption::VALUE_REQUIRED, 'Get metadata related to given id.')
->addOption('search-raw', null, InputOption::VALUE_NONE, 'Return Unfiltered results.')
->addOption('search-limit', null, InputOption::VALUE_REQUIRED, 'Search limit', 25)
->addOption('search-output', null, InputOption::VALUE_REQUIRED, 'Search output style [json,yaml]', 'json')
->addOption('search-limit', null, InputOption::VALUE_REQUIRED, 'Search limit.', 25)
->addOption('search-output', null, InputOption::VALUE_REQUIRED, 'Search output style [json,yaml].', 'json')
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
->addArgument('name', InputArgument::REQUIRED, 'Server name');
->addArgument('server', InputArgument::REQUIRED, 'Server name');
}
/**
@@ -56,7 +56,7 @@ final class RemoteCommand extends Command
}
}
$name = $input->getArgument('name');
$name = $input->getArgument('server');
$ref = "servers.{$name}";
if (null === Config::get("{$ref}.type", null)) {
@@ -213,6 +213,8 @@ final class RemoteCommand extends Command
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestOptionValuesFor('search-output')) {
$currentValue = $input->getCompletionValue();
@@ -226,19 +228,5 @@ final class RemoteCommand extends Command
$suggestions->suggestValues($suggest);
}
if ($input->mustSuggestArgumentValuesFor('name')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (array_keys(Config::get('servers', [])) as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -6,6 +6,8 @@ namespace App\Commands\Servers;
use App\Command;
use App\Libs\Config;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -176,4 +178,23 @@ final class UnifyCommand extends Command
$output->writeln(sprintf('<info>%s global webhook API key is: %s</info>', ucfirst($type), $apiToken));
return self::SUCCESS;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestArgumentValuesFor('type')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (array_keys(Config::get('supported', [])) as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -8,6 +8,8 @@ use App\Command;
use App\Libs\Config;
use Exception;
use RuntimeException;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputArgument;
@@ -33,7 +35,7 @@ final class ViewCommand extends Command
->addArgument(
'filter',
InputArgument::OPTIONAL,
'Can be any key from config, use dot notion to access sub keys, for example "webhook.token"'
'Can be any key from servers.yaml, use dot notion to access sub keys, for example "webhook.token"'
);
}
@@ -102,4 +104,23 @@ final class ViewCommand extends Command
return self::SUCCESS;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
parent::complete($input, $suggestions);
if ($input->mustSuggestArgumentValuesFor('filter')) {
$currentValue = $input->getCompletionValue();
$suggest = [];
foreach (require __DIR__ . '/../../../config/servers.spec.php' as $name) {
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
$suggest[] = $name;
}
}
$suggestions->suggestValues($suggest);
}
}
}

View File

@@ -21,12 +21,12 @@ final class MakeCommand extends Command
{
$this->setName('storage:make')
->setDescription('Create storage backend migration.')
->addArgument('name', InputArgument::REQUIRED, 'Migration name.');
->addArgument('filename', InputArgument::REQUIRED, 'Migration name.');
}
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
$file = $this->storage->makeMigration($input->getArgument('name'));
$file = $this->storage->makeMigration($input->getArgument('filename'));
$output->writeln(sprintf('<info>Created new migration at \'%s\'.</info>', $file));