Streamlined command interface.

This commit is contained in:
abdulmohsen
2024-03-08 21:08:15 +03:00
parent cc3a3b9b19
commit 7bd0c7ca34
27 changed files with 234 additions and 295 deletions

60
FAQ.md
View File

@@ -158,13 +158,16 @@ $ docker exec -ti console backend:users:list --with-tokens -- [BACKEND_NAME]
### How do i migrate invited friends i.e. (external user) data from from plex to emby/jellyfin?
As this tool is designed to work with single user, You have to treat each invited friend as a separate user. what is
needed, you need to contact that friend of yours and ask him to give you a copy of his [X-Plex-Token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/),
needed, you need to contact that friend of yours and ask him to give you a copy of
his [X-Plex-Token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/),
then create new container and add the backend with the token you got from your friend.
After that, add your other backends like emby/jellyfin using your regular API key. jellyfin/emby differentiate between users by using the userId which
After that, add your other backends like emby/jellyfin using your regular API key. jellyfin/emby differentiate between
users by using the userId which
you should select at the start of the add process.
After that. run the `state:import -f -s [plex_server_name]` command to import the user watch state. After that, you can run the `state:export -fi -s [emby/jellyfin_server_name]` to export the
After that. run the `state:import -f -s [plex_server_name]` command to import the user watch state. After that, you can
run the `state:export -fi -s [emby/jellyfin_server_name]` to export the
watch state to the new backend.
You have to repeat these steps for each user you want to migrate their data off the plex server.
@@ -256,8 +259,11 @@ $ mv /config/db/watchstate_v01-repaired.db /config/db/watchstate_v01.db
* com.plexapp.agents.xbmcnfo://(id)?lang=en `(XBMC NFO Movies agent)`
* com.plexapp.agents.xbmcnfotv://(id)?lang=en `(XBMC NFO TV agent)`
* com.plexapp.agents.hama://(db)\d?-(id)?lang=en `(HAMA multi source db agent mainly for anime)`
* com.plexapp.agents.ytinforeader://(id)?lang=en [ytinforeader.bundle](https://github.com/arabcoders/plex-ytdlp-info-reader-agent) With [jp_scanner.py](https://github.com/arabcoders/plex-daily-scanner) as scanner.
* com.plexapp.agents.cmdb://(id)?lang=en [cmdb.bundle](https://github.com/arabcoders/cmdb.bundle) `(User custom metadata database)`.
* com.plexapp.agents.ytinforeader://(id)
?lang=en [ytinforeader.bundle](https://github.com/arabcoders/plex-ytdlp-info-reader-agent)
With [jp_scanner.py](https://github.com/arabcoders/plex-daily-scanner) as scanner.
* com.plexapp.agents.cmdb://(id)
?lang=en [cmdb.bundle](https://github.com/arabcoders/cmdb.bundle) `(User custom metadata database)`.
---
@@ -269,8 +275,10 @@ $ mv /config/db/watchstate_v01-repaired.db /config/db/watchstate_v01.db
* tvmaze://(id)
* tvrage://(id)
* anidb://(id)
* ytinforeader://(id) [jellyfin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin) & [Emby](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin). `(A yt-dlp info reader plugin)`.
* cmdb://(id) [jellyfin](https://github.com/arabcoders/jf-custom-metadata-db) & [Emby](https://github.com/arabcoders/emby-custom-metadata-db). `(User custom metadata database)`.
* ytinforeader://(
id) [jellyfin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin) & [Emby](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin). `(A yt-dlp info reader plugin)`.
* cmdb://(
id) [jellyfin](https://github.com/arabcoders/jf-custom-metadata-db) & [Emby](https://github.com/arabcoders/emby-custom-metadata-db). `(User custom metadata database)`.
---
@@ -295,7 +303,7 @@ These environment variables relates to the tool itself, you can load them via th
|-------------------------|---------|-------------------------------------------------------------------------|--------------------|
| WS_DATA_PATH | string | Where to store main data. (config, db). | `${BASE_PATH}/var` |
| WS_TMP_DIR | string | Where to store temp data. (logs, cache) | `${WS_DATA_PATH}` |
| WS_TZ | string | Set timezone. | `UTC` |
| WS_TZ | string | Set timezone. Fallback to to `TZ` variable if `WS_TZ` not set. | `UTC` |
| WS_CRON_{TASK} | bool | Enable {task} task. Value casted to bool. | `false` |
| WS_CRON_{TASK}_AT | string | When to run {task} task. Valid Cron Expression Expected. | `*/1 * * * *` |
| WS_CRON_{TASK}_ARGS | string | Flags to pass to the {task} command. | `-v` |
@@ -481,15 +489,19 @@ Those are some web hook limitations we discovered for the following media backen
#### Emby
* Emby does not send webhooks events for newly added items.
~~[See feature request](https://emby.media/community/index.php?/topic/97889-new-content-notification-webhook/)~~ implemented in `4.7.9` still does not work as expected no metadata being sent when the item notification goes out.
* Emby webhook test event does not contain data. To test if your setup works, play something or do mark an item as played or unplayed you should see changes reflected in `docker exec -ti watchstate console db:list`.
~~[See feature request](https://emby.media/community/index.php?/topic/97889-new-content-notification-webhook/)~~
implemented in `4.7.9` still does not work as expected no metadata being sent when the item notification goes out.
* Emby webhook test event does not contain data. To test if your setup works, play something or do mark an item as
played or unplayed you should see changes reflected in `docker exec -ti watchstate console db:list`.
#### Jellyfin
* If you don't select a user id, the plugin will send `itemAdd` event without user data, and will fail the check if you happen to enable `webhook.match.user` for jellyfin.
* If you don't select a user id, the plugin will send `itemAdd` event without user data, and will fail the check if you
happen to enable `webhook.match.user` for jellyfin.
* Sometimes jellyfin will fire webhook `itemAdd` event without the item being matched.
* Even if you select user id, sometimes `itemAdd` event will fire without user data.
* Items might be marked as unplayed if Libraries > Display - `Date added behavior for new content:` is set to `Use date scanned into library`. This happens if the media file has been replaced.
* Items might be marked as unplayed if Libraries > Display - `Date added behavior for new content:` is set
to `Use date scanned into library`. This happens if the media file has been replaced.
---
@@ -497,7 +509,8 @@ Those are some web hook limitations we discovered for the following media backen
As stated in webhook limitation section sometimes media backends don't make it easy to receive those events, as such, to
complement webhooks, you should enable import/export tasks by settings their respective environment variables in
your `docker-compose.yaml` file. For more information run help on `system:env` command as well as `system:tasks` command.
your `docker-compose.yaml` file. For more information run help on `system:env` command as well as `system:tasks`
command.
---
@@ -548,10 +561,13 @@ location and delete the empty directories.
### How to get WatchState working with YouTube content/library?
Due to the nature on how people name their youtube files i had to pick something specific for it to work cross supported
media agents. Please visit [this link](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin#usage) to know how to name your files. Please be aware these plugins and scanners `REQUIRE`
that you have a `yt-dlp` `.info.json` files named exactly as your media file. For example, if you have `20231030 my awesome youtube video [youtube-RandomString].mkv`
media agents. Please visit [this link](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin#usage) to know how to
name your files. Please be aware these plugins and scanners `REQUIRE`
that you have a `yt-dlp` `.info.json` files named exactly as your media file. For example, if you
have `20231030 my awesome youtube video [youtube-RandomString].mkv`
you should have `20231030 my awesome youtube video [youtube-RandomString].info.json` in the same directory. In the
future, I plan to make `.info.json` optional However at the moment the file is required for emby/jellyfin plugin to work.
future, I plan to make `.info.json` optional However at the moment the file is required for emby/jellyfin plugin to
work.
#### Plex Setup
@@ -561,11 +577,13 @@ future, I plan to make `.info.json` optional However at the moment the file is r
#### Jellyfin Setup
* Download this plugin [jf-ytdlp-info-reader-plugin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin). Please refer to the link on how to install it.
* Download this plugin [jf-ytdlp-info-reader-plugin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin). Please
refer to the link on how to install it.
#### Emby Setup
* Download this plugin [emby-ytdlp-info-reader-plugin](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin). Please refer to the link on how to install it.
* Download this plugin [emby-ytdlp-info-reader-plugin](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin).
Please refer to the link on how to install it.
If your media is not matching correctly or not marking it as expected, it's most likely scanners issues as plex and
jellyfin/emby reports the GUID differently, and we try our best to match them. So, please hop on discord with the
@@ -618,10 +636,12 @@ If everything is working correctly you should see something like this previous j
### I keep receiving this warning in log `INFO: Ignoring [xxx] Episode range, and treating it as single episode. Backend says it covers [00-00]`?
We recently added guard clause to prevent backends from sending possibly invalid episode ranges, as such if you see this,
We recently added guard clause to prevent backends from sending possibly invalid episode ranges, as such if you see
this,
this likely means your backend mis-identified episodes range. By default, we allow an episode to cover up to 4 episodes.
If this is not enough for your library content. fear not we have you covered you can increase the limit by running the following command:
If this is not enough for your library content. fear not we have you covered you can increase the limit by running the
following command:
```bash
$ docker exec -ti watchstate console config:edit --key options.MAX_EPISODE_RANGE --set 10 -- [BACKEND_NAME]

View File

@@ -7,7 +7,21 @@
This tool primary goal is to sync your backends play state without relying on third party services,
out of the box, this tool support `Jellyfin`, `Plex` and `Emby` media servers.
## Feature updates
## updates
### 2024-03-08
This update include breaking changes to how we process commands, we have streamlined the command interface to accept
some consistent flags and options. Notably, we have added `-s, --select-backend` flag to all commands that accept it.
commands that were accepting comma separated list of backends now needs to be separate option call for example
`--select-backend home_plex --select-backend home_jellyfin` instead of `--select-backend home_plex,home_jellyfin`.
All commands that was accepting backend name as argument now accepts `-s, --select-backend` flag. This change is to make
the
command interface more consistent and easier to use.
We started working no a `Web API` which hopefully will lead to a `web frontend` to manage the tool. This is a long
term goal, and it's not expected to be ready soon. However, the `Web API` is expected within 3rd quarter of 2024.
### 2023-11-11
@@ -136,10 +150,10 @@ $ docker exec -ti watchstate console state:import -v
```
This command will pull your play state from all your backends. To import from specific backends use
the `[-s, --select-backends]` flag which accept comma seperated list of backend names. For example,
the `[-s, --select-backend]` flag. For example,
```bash
$ docker exec -ti watchstate console state:import -v --select-backends 'home_plex,home_jellyfin'
$ docker exec -ti watchstate console state:import -v -s home_plex -s home_jellyfin
```
> [!NOTE]
@@ -176,11 +190,10 @@ $ docker exec -ti watchstate console state:export -v
```
This command will export your current play state to all of your export enabled backends. To export to
specific backends use the `[-s, --select-backends]` flag which accept comma seperated list of backend names. For
example,
specific backends use the `[-s, --select-backend]`flag. For example,
```bash
$ docker exec -ti watchstate console state:export -v --select-backends 'home_plex,home_jellyfin'
$ docker exec -ti watchstate console state:export -v -s home_plex -s home_jellyfin
```
> [!NOTE]

View File

@@ -21,7 +21,7 @@ return (function () {
$config = [
'name' => 'WatchState',
'version' => '$(version_via_ci)',
'tz' => env('WS_TZ', 'UTC'),
'tz' => env('WS_TZ', env('TZ', 'UTC')),
'path' => fixPath(env('WS_DATA_PATH', fn() => $inContainer ? '/config' : __DIR__ . '/../var')),
'logs' => [
'context' => (bool)env('WS_LOGS_CONTEXT', false),

View File

@@ -51,10 +51,15 @@ final class ListCommand extends Command
protected function configure(): void
{
$this->setName(self::ROUTE)
->addOption('type', null, InputOption::VALUE_REQUIRED, 'Filter based on type.')
->addOption('backend', null, InputOption::VALUE_REQUIRED, 'Filter based on backend.')
->addOption('db', null, InputOption::VALUE_REQUIRED, 'Filter based on db.')
->addOption('id', null, InputOption::VALUE_REQUIRED, 'Filter based on id.')
->addOption(
'select-backend',
's',
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Filter based on backend.'
)
->addOption('type', 't', InputOption::VALUE_REQUIRED, 'Filter based on type.')
->addOption('db', 'd', InputOption::VALUE_REQUIRED, 'Filter based on db.')
->addOption('id', 'i', InputOption::VALUE_REQUIRED, 'Filter based on id.')
->setDescription('List Ignored external ids.')
->setHelp(
r(
@@ -69,11 +74,11 @@ final class ListCommand extends Command
<question># List all ignore rules that relate to specific backend.</question>
{cmd} <cmd>{route}</cmd> <flag>--backend</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>-s</flag> <value>backend_name</value>
<question># Appending more filters to narrow down list</question>
{cmd} <cmd>{route}</cmd> <flag>--backend</flag> <value>backend_name</value> <flag>--db</flag> <value>tvdb</value>
{cmd} <cmd>{route}</cmd> <flag>-s</flag> <value>backend_name</value> <flag>-d</flag> <value>tvdb</value>
HELP,
[
@@ -102,10 +107,10 @@ final class ListCommand extends Command
$list = [];
$fBackend = $input->getOption('backend');
$fType = $input->getOption('type');
$fDb = $input->getOption('db');
$fId = $input->getOption('id');
$backends = $input->getOption('select-backend');
$ids = Config::get('ignore', []);
@@ -118,19 +123,40 @@ final class ListCommand extends Command
$id = ag($urlParts, 'pass');
$scope = ag($urlParts, 'query');
if (null !== $fBackend && $backend !== $fBackend) {
if (!empty($backends) && !in_array($backend, $backends)) {
if (true === str_contains($backend, ',')) {
throw new \RuntimeException(
'The option [-s --select-backend] does not support comma separated values. it should be used multiple times.'
);
}
$output->writeln(r('<comment>Skipping \'{rule}\' as requested by [-s, --select-backend].</comment>', [
'rule' => $guid,
'backend' => $backend
]), OutputInterface::VERBOSITY_DEBUG);
continue;
}
if (null !== $fType && $type !== $fType) {
$output->writeln(r('<comment>Skipping \'{rule}\' as requested by [-t, --type].</comment>', [
'rule' => $guid,
'type' => $type
]), OutputInterface::VERBOSITY_DEBUG);
continue;
}
if (null !== $fDb && $db !== $fDb) {
$output->writeln(r('<comment>Skipping \'{rule}\' as requested by [-d, --db].</comment>', [
'rule' => $guid,
'db' => $db
]), OutputInterface::VERBOSITY_DEBUG);
continue;
}
if (null !== $fId && $id !== $fId) {
$output->writeln(r('<comment>Skipping \'{rule}\' as requested by [-i, --id].</comment>', [
'rule' => $guid,
'id' => $id
]), OutputInterface::VERBOSITY_DEBUG);
continue;
}

View File

@@ -33,7 +33,7 @@ final class ManageCommand extends Command
protected function configure(): void
{
$this->setName(self::ROUTE)
->setDescription('Add/Remove external id from ignore list.')
->setDescription('Add or remove external id from ignore list.')
->addOption('remove', 'r', InputOption::VALUE_NONE, 'Remove id from ignore list.')
->addArgument('id', InputArgument::REQUIRED, 'id.')
->setHelp(

View File

@@ -8,7 +8,6 @@ use App\Command;
use App\Libs\Attributes\Route\Cli;
use App\Libs\Options;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -35,8 +34,7 @@ class InfoCommand extends Command
$this->setName(self::ROUTE)
->setDescription('Get backend product info.')
->addOption('include-raw-response', null, InputOption::VALUE_NONE, 'Include unfiltered raw response.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name to restore.');
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.');
}
/**
@@ -48,23 +46,14 @@ class InfoCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$mode = $input->getOption('output');
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$mode = $input->getOption('output');
$opts = [];
if ($input->getOption('include-raw-response')) {

View File

@@ -11,7 +11,6 @@ use App\Libs\Config;
use App\Libs\ConfigFile;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -40,7 +39,6 @@ final class IgnoreCommand extends Command
$this->setName(self::ROUTE)
->setDescription('Manage Backend ignored libraries.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -61,9 +59,7 @@ final class IgnoreCommand extends Command
You are mainly interested in the <notice>Id</notice> column, once you have list of your ids,
you can run the following command to update the backend ignorelist.
{cmd} <cmd>{backend_edit}</cmd> <flag>--key</flag> '<value>options.ignore</value>' <flag>--set</flag> '<value>id1</value>,<value>id2</value>,<value>id3</value>' -- <value>backend_name</value>
You can also directly update the config file at [<value>{configPath}</value>].
{cmd} <cmd>{backend_edit}</cmd> <flag>--key</flag> '<value>options.ignore</value>' <flag>--set</flag> '<value>id1</value>,<value>id2</value>,<value>id3</value>' <flag>-s</flag> <value>backend_name</value>
The [<value>options.ignore</value>] key accept comma seperated list of ids.
@@ -89,16 +85,7 @@ final class IgnoreCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output, null|array $rerun = null): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));

View File

@@ -8,7 +8,6 @@ use App\Command;
use App\Libs\Attributes\Route\Cli;
use App\Libs\Options;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -32,7 +31,6 @@ final class ListCommand extends Command
->setDescription('Get Backend libraries list.')
->addOption('include-raw-response', null, InputOption::VALUE_NONE, 'Include unfiltered raw response.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
<<<HELP
@@ -53,24 +51,14 @@ final class ListCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$mode = $input->getOption('output');
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$mode = $input->getOption('output');
$opts = $backendOpts = [];
if ($input->getOption('include-raw-response')) {

View File

@@ -11,7 +11,6 @@ use App\Libs\Options;
use RuntimeException;
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;
use Symfony\Component\Console\Output\OutputInterface;
@@ -86,7 +85,6 @@ final class MismatchCommand extends Command
->addOption('cutoff', null, InputOption::VALUE_REQUIRED, 'Increase title cutoff', self::CUTOFF)
->addOption('id', null, InputOption::VALUE_REQUIRED, 'backend Library id.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -156,27 +154,16 @@ final class MismatchCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$mode = $input->getOption('output');
$showAll = $input->getOption('show-all');
$percentage = $input->getOption('percentage');
$id = $input->getOption('id');
$cutoff = (int)$input->getOption('cutoff');
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$backendOpts = $opts = $list = [];

View File

@@ -9,7 +9,6 @@ use App\Libs\Attributes\Route\Cli;
use App\Libs\Config;
use App\Libs\Options;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -45,7 +44,6 @@ final class UnmatchedCommand extends Command
->addOption('cutoff', null, InputOption::VALUE_REQUIRED, 'Increase title cutoff', self::CUTOFF)
->addOption('id', null, InputOption::VALUE_REQUIRED, 'backend Library id.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -87,27 +85,17 @@ final class UnmatchedCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$mode = $input->getOption('output');
$showAll = $input->getOption('show-all');
$id = $input->getOption('id');
$cutoff = (int)$input->getOption('cutoff');
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$mode = $input->getOption('output');
$showAll = $input->getOption('show-all');
$id = $input->getOption('id');
$cutoff = (int)$input->getOption('cutoff');
$backendOpts = $opts = $list = [];
if ($input->getOption('timeout')) {

View File

@@ -87,7 +87,7 @@ class RestoreCommand extends Command
For example,
{cmd} <cmd>{route}</cmd> <flag>--execute</flag> <flag>-vv</flag> -s <value>backend_name</value> -- <value>{backupDir}/backup_file.json</value>
{cmd} <cmd>{route}</cmd> <flag>--execute</flag> <flag>-vv -s</flag> <value>backend_name</value> -- <value>{backupDir}/backup_file.json</value>
-------
<notice>[ FAQ ]</notice>
@@ -148,13 +148,13 @@ class RestoreCommand extends Command
*/
protected function process(InputInterface $input, OutputInterface $output): int
{
if (null === ($name = $input->getOption('select-backend'))) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backends].</error>'));
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$name = explode(',', $name, 2)[0];
$file = $input->getArgument('file');
if (false === file_exists($file) || false === is_readable($file)) {

View File

@@ -44,7 +44,7 @@ final class IdCommand extends Command
[<flag>--output</flag>] flag to [<value>json</value> or <value>yaml</value>] and use the [<flag>--include-raw-response</flag>] flag.
For example,
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response</flag> -- <value>backend_name</value> <value>backend_item_id</value>
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response -s</flag> <value>backend_name</value> <value>backend_item_id</value>
HELP,
[
@@ -67,14 +67,11 @@ final class IdCommand extends Command
{
$mode = $input->getOption('output');
$id = $input->getArgument('id');
$name = $input->getOption('select-backend');
if (null === ($name = $input->getOption('select-backend'))) {
$output->writeln(
r('<error>ERROR: You must select a backend using [-s, --select-backends] option.</error>')
);
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
} else {
$name = explode(',', $name)[0];
}
$backendOpts = [];

View File

@@ -46,7 +46,7 @@ final class QueryCommand extends Command
[<flag>--output</flag>] flag to [<value>json</value> or <value>yaml</value>] and use the [<flag>--include-raw-response</flag>] flag.
For example,
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response</flag> -- <value>backend_name</value> '<value>search query word</value>'
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response -s</flag> <value>backend_name</value> '<value>search query word</value>'
HELP,
[
@@ -69,14 +69,11 @@ final class QueryCommand extends Command
{
$mode = $input->getOption('output');
$query = $input->getArgument('query');
$name = $input->getOption('select-backend');
if (null === ($name = $input->getOption('select-backend'))) {
$output->writeln(
r('<error>ERROR: You must select a backend using [-s, --select-backends] option.</error>')
);
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
} else {
$name = explode(',', $name)[0];
}
$opts = $backendOpts = [];

View File

@@ -9,7 +9,6 @@ use App\Command;
use App\Libs\Attributes\Route\Cli;
use App\Libs\Options;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -42,7 +41,6 @@ final class ListCommand extends Command
->addOption('use-token', 'u', InputOption::VALUE_REQUIRED, 'Use this given token.')
->addOption('include-raw-response', null, InputOption::VALUE_NONE, 'Include unfiltered raw response.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -56,7 +54,7 @@ final class ListCommand extends Command
<question># How to get user tokens?</question>
{cmd} <cmd>{route}</cmd> <flag>--with-tokens</flag> <flag>-s</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>--with-tokens -s</flag> <value>backend_name</value>
<notice>Notice: If you have many plex users and request tokens for all of them you may get rate-limited by plex api,
you shouldn't do this unless you have good reason. In most cases you don't need to, and can use
@@ -68,7 +66,7 @@ final class ListCommand extends Command
<question># How to see the raw response?</question>
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response</flag> <flag>-s</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>--output</flag> <value>yaml</value> <flag>--include-raw-response -s</flag> <value>backend_name</value>
<question># My Plex backend report only one user?</question>
@@ -76,7 +74,7 @@ final class ListCommand extends Command
work for managed user we have to use the managed user token instead of the admin user token due to
plex api limitation. To see list of your users you can do the following.
{cmd} <cmd>{route}</cmd> <flag>--use-token</flag> <value>PLEX_TOKEN</value> <flag>-s</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>--use-token</flag> <value>PLEX_ADMIN_TOKEN</value> <flag>-s</flag> <value>backend_name</value>
HELP,
[
@@ -100,24 +98,14 @@ final class ListCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$mode = $input->getOption('output');
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$mode = $input->getOption('output');
$opts = $backendOpts = [];
if ($input->getOption('with-tokens')) {

View File

@@ -80,14 +80,12 @@ final class SessionsCommand extends Command
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
$mode = $input->getOption('output');
if (null === ($name = $input->getOption('select-backend'))) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backends].</error>'));
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;
}
$name = explode(',', $name, 2)[0];
$opts = $backendOpts = [];
if ($input->getOption('include-raw-response')) {

View File

@@ -7,7 +7,6 @@ namespace App\Commands\Backend;
use App\Command;
use App\Libs\Attributes\Route\Cli;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -29,8 +28,7 @@ class VersionCommand extends Command
{
$this->setName(self::ROUTE)
->setDescription('Get backend product version.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name to restore.');
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.');
}
/**
@@ -43,17 +41,7 @@ class VersionCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;

View File

@@ -8,7 +8,6 @@ use App\Command;
use App\Libs\Attributes\Route\Cli;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -33,7 +32,6 @@ final class AddCommand extends Command
{
$this->setName(self::ROUTE)
->setDescription('Add new backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name', null)
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->setHelp(
r(
@@ -103,22 +101,11 @@ final class AddCommand extends Command
$opts['--' . $option] = $val;
}
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
$name = $input->getOption('select-backend');
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
if (null !== $name) {
$opts['backend'] = strtolower($name);
} else {
if (empty($name)) {
// -- $backend.token
$opts['backend'] = (function () use (&$opts, $input, $output) {
$name = (function () use (&$opts, $input, $output) {
$chosen = ag($opts, 'backend');
$question = new Question(
@@ -152,10 +139,10 @@ final class AddCommand extends Command
return (new QuestionHelper())->ask($input, $output, $question);
})();
$output->writeln('');
$opts['--select-backend'] = strtolower($opts['backend']);
}
$opts['--select-backend'] = strtolower($name);
return $this->getApplication()?->find(ManageCommand::ROUTE)->run(new ArrayInput($opts), $output) ?? 1;
}
}

View File

@@ -11,7 +11,6 @@ use App\Libs\ConfigFile;
use App\Libs\Database\DatabaseInterface as iDB;
use PDO;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -45,7 +44,6 @@ final class DeleteCommand extends Command
$this->setName(self::ROUTE)
->setDescription('Delete Local backend data.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -110,17 +108,7 @@ final class DeleteCommand extends Command
return self::FAILURE;
}
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
return self::FAILURE;

View File

@@ -11,7 +11,6 @@ use App\Libs\ConfigFile;
use Psr\Log\LoggerInterface;
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;
use Symfony\Component\Console\Output\OutputInterface;
@@ -45,14 +44,13 @@ final class EditCommand extends Command
->addOption('delete', 'd', InputOption::VALUE_NONE, 'Delete value.')
->addOption('regenerate-webhook-token', 'g', InputOption::VALUE_NONE, 'Re-generate backend webhook token.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name')
->setHelp(
r(
<<<HELP
This command allow you to <notice>edit</notice> backend config settings <notice>inline</notice>.
The [<flag>--key</flag>] accept string value. the list of officially supported keys are:
The [<flag>-k, --key</flag>] accept string value. the list of officially supported keys are:
[{keyNames}]
@@ -62,7 +60,7 @@ final class EditCommand extends Command
<question># How to edit config setting?</question>
{cmd} <cmd>{route}</cmd> <flag>--key</flag> <value>key</value> <flag>--set</flag> <value>value</value> <flag>-s</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>-k</flag> <value>key</value> <flag>-e</flag> <value>value</value> <flag>-s</flag> <value>backend_name</value>
<question># How to change the re-generate webhook token?</question>
@@ -102,16 +100,7 @@ final class EditCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output, null|array $rerun = null): int
{
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));

View File

@@ -14,7 +14,6 @@ use App\Libs\Options;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -44,7 +43,6 @@ final class ManageCommand extends Command
->setDescription('Manage backend settings.')
->addOption('add', 'a', InputOption::VALUE_NONE, 'Add Backend.')
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
->setHelp(
r(
<<<HELP
@@ -95,16 +93,7 @@ final class ManageCommand extends Command
return self::FAILURE;
}
if (null !== ($name = $input->getOption('select-backend'))) {
$name = explode(',', $name, 2)[0];
}
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
$name = $input->getArgument('backend');
$output->writeln(
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
);
}
$name = $input->getOption('select-backend');
if (empty($name)) {
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
@@ -451,7 +440,7 @@ final class ManageCommand extends Command
);
$cmd = $this->getApplication()?->find(ImportCommand::ROUTE);
$cmd->run(new ArrayInput(['--quiet', '--select-backends' => $name]), $output);
$cmd->run(new ArrayInput(['--quiet', '--select-backend' => $name]), $output);
}
$output->writeln('<info>Import complete</info>');

View File

@@ -4,11 +4,10 @@ declare(strict_types=1);
namespace App\Commands\Config;
use App\API\Backends\Index;
use App\Command;
use App\Libs\Attributes\Route\Cli;
use App\Libs\Config;
use App\Libs\Exceptions\RuntimeException;
use App\Libs\Options;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\Table;
@@ -29,15 +28,6 @@ final class ViewCommand extends Command
{
public const ROUTE = 'config:view';
/**
* @var array Keys to be hidden from general view.
*/
private array $hidden = [
'token',
'webhook.token',
'options.' . Options::ADMIN_TOKEN
];
/**
* Configure the command.
*/
@@ -45,8 +35,13 @@ final class ViewCommand extends Command
{
$this->setName(self::ROUTE)
->setDescription('View Backends settings.')
->addOption('select-backends', 's', InputOption::VALUE_REQUIRED, 'Select backends. comma , seperated.')
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backends logic.')
->addOption(
'select-backend',
's',
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Select backend.'
)
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backend logic.')
->addOption('expose', 'x', InputOption::VALUE_NONE, 'Expose the secret tokens in the view.')
->addArgument(
'filter',
@@ -66,11 +61,11 @@ final class ViewCommand extends Command
<question># How to show one backend information?</question>
The flag [<flag>-s, --select-backends</flag>] accept comma seperated list of backends name, Using the flag
in combination with [<flag>--exclude</flag>] flag will flip the logic to exclude the selected backends
rather than include them.
The flag [<flag>-s, --select-backend</flag>] is array option with can accept many backends names,
Using the flag in combination with [<flag>--exclude</flag>] flag will flip the logic to exclude
the selected backends rather than include them.
{cmd} <cmd>{route}</cmd> <flag>--select-backends</flag> <value>my_backend</value>
{cmd} <cmd>{route}</cmd> <flag>-s</flag> <value>my_backend</value>
<question># How to show specific <value>key</value>?</question>
@@ -98,16 +93,14 @@ final class ViewCommand extends Command
*/
protected function runCommand(InputInterface $input, OutputInterface $output): int
{
$selectBackends = (string)$input->getOption('select-backends');
$list = [];
$selected = array_map('trim', explode(',', $selectBackends));
$isCustom = !empty($selectBackends) && count($selected) >= 1;
$selected = $input->getOption('select-backend');
$isCustom = count($selected) > 0;
$filter = $input->getArgument('filter');
foreach (Config::get('servers', []) as $backendName => $backend) {
if ($isCustom && $input->getOption('exclude') === in_array($backendName, $selected)) {
$output->writeln(r('Ignoring backend \'{backend}\' as requested by [-s, --select-backends].', [
$output->writeln(r('Ignoring backend \'{backend}\' as requested by [-s, --select-backend].', [
'backend' => $backendName
]), OutputInterface::VERBOSITY_VERY_VERBOSE);
continue;
@@ -117,9 +110,10 @@ final class ViewCommand extends Command
}
if (empty($list)) {
throw new RuntimeException(
$isCustom ? '[-s, --select-backends] did not return any backend.' : 'No backends were found.'
);
$output->writeln(r('<error>{error}</error>', [
'error' => $isCustom ? '[-s, --select-backend] did not return any backend.' : 'No backends were found.'
]));
return self::FAILURE;
}
$x = 0;
@@ -189,7 +183,7 @@ final class ViewCommand extends Command
private function filterData(array $backend, string|null $filter = null, bool $expose = false): string
{
if (null === $filter && true !== $expose) {
foreach ($this->hidden as $hideValue) {
foreach (Index::BLACK_LIST as $hideValue) {
if (true === ag_exists($backend, $hideValue)) {
$backend = ag_set($backend, $hideValue, '*HIDDEN*');
}

View File

@@ -59,8 +59,13 @@ class BackupCommand extends Command
)
->addOption('dry-run', null, InputOption::VALUE_NONE, 'No actions will be committed.')
->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Set request timeout in seconds.')
->addOption('select-backends', 's', InputOption::VALUE_OPTIONAL, 'Select backends. comma , seperated.', '')
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backends logic.')
->addOption(
'select-backend',
's',
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Select backend.',
)
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backend logic.')
->addOption(
'no-enhance',
null,
@@ -88,7 +93,7 @@ class BackupCommand extends Command
Backups generated without [<flag>-k</flag>, <flag>--keep</flag>] flag are subject to be <notice>REMOVED</notice> during system:prune run.
To keep permanent copy of your backups you can use the [<flag>-k</flag>, </flag>--keep</info>] flag. For example:
{cmd} <cmd>{route}</cmd> <info>--keep</info> [<flag>--select-backends</flag> <value>backend_name</value>]
{cmd} <cmd>{route}</cmd> <info>--keep</info> [<flag>--select-backend</flag> <value>backend_name</value>]
Backups generated with [<flag>-k</flag>, <flag>--keep</flag>] flag will not contain a date and will be named [<value>backend_name.json</value>]
where automated backups will be named [<value>backend_name.00000000{date}.json</value>]
@@ -112,11 +117,11 @@ class BackupCommand extends Command
<question># I want different file name for my backup?</question>
Backup names are something tricky, however it's possible to choose the backup filename if the total number
of backed up backends are 1. So, in essence you have to combine two flags [<flag>-s</flag>, <flag>--select-backends</flag>] and [<flag>--file</flag>].
of backed up backends are 1. So, in essence you have to combine two flags [<flag>-s</flag>, <flag>--select-backend</flag>] and [<flag>--file</flag>].
For example, to back up [<value>backend_name</value>] backend data to [<value>/tmp/backend_name.json</value>] do the following:
{cmd} <cmd>{route}</cmd> <flag>--select-backends</flag> <value>backend_name</value> <flag>--file</flag> <value>/tmp/my_backend.json</value>
{cmd} <cmd>{route}</cmd> <flag>--select-backend</flag> <value>backend_name</value> <flag>--file</flag> <value>/tmp/my_backend.json</value>
HELP,
[
@@ -152,9 +157,8 @@ class BackupCommand extends Command
protected function process(InputInterface $input): int
{
$list = [];
$selectBackends = (string)$input->getOption('select-backends');
$selected = explode(',', $selectBackends);
$isCustom = !empty($selectBackends) && count($selected) >= 1;
$selected = $input->getOption('select-backend');
$isCustom = !empty($selected) && count($selected) > 0;
$supported = Config::get('supported', []);
$mapperOpts = [];
@@ -211,7 +215,7 @@ class BackupCommand extends Command
if (empty($list)) {
$this->logger->warning(
$isCustom ? '[-s, --select-backends] flag did not match any backend.' : 'No backends were found.'
$isCustom ? '[-s, --select-backend] flag did not match any backend.' : 'No backends were found.'
);
return self::FAILURE;
}

View File

@@ -67,8 +67,13 @@ class ExportCommand extends Command
->addOption('force-full', 'f', InputOption::VALUE_NONE, 'Force full export. Ignore last export date.')
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit changes to backends.')
->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Set request timeout in seconds.')
->addOption('select-backends', 's', InputOption::VALUE_OPTIONAL, 'Select backends. comma , seperated.', '')
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backends logic.')
->addOption(
'select-backend',
's',
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
'Select backend.'
)
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backend logic.')
->addOption('ignore-date', 'i', InputOption::VALUE_NONE, 'Ignore date comparison.')
->addOption('logfile', null, InputOption::VALUE_REQUIRED, 'Save console output to file.')
->setHelp(
@@ -84,15 +89,15 @@ class ExportCommand extends Command
<question># How to force export play state to a backend?</question>
You have to use the following flags [<flag>-f</flag>, <flag>--force-full</flag>] and [<flag>-i</flag>, <flag>--ignore-date</flag>]. For example,
You have to use the following flags [<flag>-f</flag>, <flag>-f</flag>] and [<flag>-i</flag>, <flag>-i</flag>]. For example,
{cmd} <cmd>{route}</cmd> <flag>-fi</flag> <flag>--select-backends</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>-fi</flag> <flag>-s</flag> <value>backend_name</value>
<question># how to see what will be changed without committing them?</question>
You have to use the [<flag>--dry-run</flag>]. For example,
{cmd} <cmd>{route}</cmd> <flag>-v --dry-run</flag> <flag>--select-backends</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>-v --dry-run -s</flag> <value>backend_name</value>
<question># Ignoring [backend_name] [item_title]. [Movie|Episode] Is not imported yet.</question>
@@ -145,11 +150,9 @@ class ExportCommand extends Command
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
$configFile->setLogger($this->logger);
$selectBackends = (string)$input->getOption('select-backends');
$backends = [];
$selected = explode(',', $selectBackends);
$isCustom = !empty($selectBackends) && count($selected) >= 1;
$selected = $input->getOption('select-backend');
$isCustom = !empty($selected) && count($selected) > 0;
$supported = Config::get('supported', []);
$export = $push = $entities = [];
@@ -161,7 +164,7 @@ class ExportCommand extends Command
$type = strtolower(ag($backend, 'type', 'unknown'));
if ($isCustom && $input->getOption('exclude') === in_array($backendName, $selected)) {
$this->logger->info('{backend}: Ignoring backend as requested by [-s, --select-backends].', [
$this->logger->info('{backend}: Ignoring backend as requested by [-s, --select-backend].', [
'backend' => $backendName
]);
continue;
@@ -197,7 +200,7 @@ class ExportCommand extends Command
if (empty($backends)) {
$this->logger->warning(
$isCustom ? '[-s, --select-backends] flag did not match any backend.' : 'No backends were found.'
$isCustom ? '[-s, --select-backend] flag did not match any backend.' : 'No backends were found.'
);
return self::FAILURE;
}

View File

@@ -66,8 +66,13 @@ class ImportCommand extends Command
->addOption('force-full', 'f', InputOption::VALUE_NONE, 'Force full import. Ignore last sync date.')
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit any changes.')
->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Set request timeout in seconds.')
->addOption('select-backends', 's', InputOption::VALUE_OPTIONAL, 'Select backends. comma , seperated.', '')
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backends logic.')
->addOption(
'select-backend',
's',
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
'Select backend.'
)
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backend logic.')
->addOption(
'direct-mapper',
null,
@@ -106,7 +111,7 @@ class ImportCommand extends Command
<question># How to import from specific backend?</question>
{cmd} <cmd>{route}</cmd> <flag>--select-backends</flag> <value>backend_name</value>
{cmd} <cmd>{route}</cmd> <flag>-s</flag> <value>backend_name</value>
<question># How to Import the metadata only?</question>
@@ -116,7 +121,7 @@ class ImportCommand extends Command
If you want to permanently increase the <notice>timeout</notice> for specific backend, you can do the following
{cmd} <cmd>{config_edit}</cmd> <flag>--key</flag> <value>options.client.timeout</value> <flag>--set</flag> <value>600.0</value> -- <value>backend_name</value>
{cmd} <cmd>{config_edit}</cmd> <flag>-k</flag> <value>options.client.timeout</value> <flag>-e</flag> <value>600.0</value> <flag>-s</flag> <value>backend_name</value>
<value>600.0</value> seconds is equal to 10 minutes before the timeout handler kicks in. Alternatively, you can also increase the
timeout temporarily by using the [<flag>--timeout</flag>] flag. It will increase the timeout for all backends during this run.
@@ -142,8 +147,8 @@ class ImportCommand extends Command
By default commands only show log level <value>WARNING</value> and higher, to see more verbose output
You can use the [<flag>-v|-vv|-vvv</flag>] flag to signal that you want more output. And you can enable
even more info by using [<flag>--trace</flag>] and [<flag>--context</flag>] flags. Be warned the output using all those flags
is quite excessive and shouldn't be used unless told by the team.
even more info by using [<flag>--debug</flag>] flag. Be warned the output is quite excessive
and shouldn't be used unless told by the team.
{cmd} <cmd>{route}</cmd> <flag>-vvv --trace --context</flag>
@@ -170,7 +175,7 @@ class ImportCommand extends Command
or you could use the built-in unmatched checker.
{cmd} <cmd>{unmatched_route}</cmd> -- <value>backend_name</value>
{cmd} <cmd>{unmatched_route}</cmd> <flag>-s</flag> <value>backend_name</value>
If you don't have any unmatched items, this likely means you are using unsupported external db ids.
@@ -201,7 +206,7 @@ class ImportCommand extends Command
Running this command will force full export your current database state to the selected backend. Once that done you can
turn on import from the new backend. by editing the backend setting:
{cmd} <cmd>config:manage</cmd> <value>backend_name</value>
{cmd} <cmd>config:manage</cmd> <flag>-s</flag> <value>backend_name</value>
HELP,
[
@@ -246,9 +251,8 @@ class ImportCommand extends Command
$list = [];
$selectBackends = (string)$input->getOption('select-backends');
$selected = explode(',', $selectBackends);
$isCustom = !empty($selectBackends) && count($selected) >= 1;
$selected = $input->getOption('select-backend');
$isCustom = !empty($selected) && count($selected) > 0;
$supported = Config::get('supported', []);
$mapperOpts = [];
@@ -330,7 +334,7 @@ class ImportCommand extends Command
if (empty($list)) {
$this->logger->warning(
$isCustom ? '[-s, --select-backends] flag did not match any backend.' : 'No backends were found.'
$isCustom ? '[-s, --select-backend] flag did not match any backend.' : 'No backends were found.'
);
return self::FAILURE;
}

View File

@@ -20,6 +20,8 @@ final class EnvCommand extends Command
{
public const ROUTE = 'system:env';
private const EXEMPT_KEYS = ['HTTP_PORT', 'TZ'];
/**
* Configure the command.
*/
@@ -43,6 +45,8 @@ final class EnvCommand extends Command
* the key SHOULD attempt to mirror the key path in default config, If not applicable or otherwise impossible it
should then use an approximate path.
* The following keys are exempt from the rules: [<flag>{exempt_keys}</flag>].
-------
<notice>[ FAQ ]</notice>
-------
@@ -57,7 +61,6 @@ final class EnvCommand extends Command
For example, to enable import task, do the following:
-------------------------------
version: '3.3'
services:
watchstate:
image: ghcr.io/arabcoders/watchstate:latest
@@ -80,7 +83,8 @@ final class EnvCommand extends Command
HELP,
[
'path' => after(Config::get('path') . '/config', ROOT_PATH)
'path' => after(Config::get('path') . '/config', ROOT_PATH),
'exempt_keys' => implode(', ', self::EXEMPT_KEYS),
]
)
);
@@ -100,7 +104,7 @@ final class EnvCommand extends Command
$keys = [];
foreach (getenv() as $key => $val) {
if (false === str_starts_with($key, 'WS_') && $key !== 'HTTP_PORT') {
if (false === str_starts_with($key, 'WS_') && in_array($key, self::EXEMPT_KEYS)) {
continue;
}

View File

@@ -131,6 +131,7 @@ final class ReportCommand extends Command
$this->getTasks($output);
$output->writeln('<info>[ Logs ]</info>' . PHP_EOL);
$this->getLogs($input, $output);
$this->printFooter($output);
return self::SUCCESS;
}
@@ -407,4 +408,20 @@ final class ReportCommand extends Command
$output->writeln($line);
}
}
private function printFooter(iOutput $output)
{
$output->writeln('<info>[ Notice ]</info>');
$output->writeln(
trim(
<<<FOOTER
<value>
Beware, while we try to make sure no sensitive information is leaked, it's possible
that some private information might be leaked via the logs section.
Please review the report before posting it.
</value>
FOOTER
)
);
}
}

View File

@@ -47,13 +47,7 @@ final class ServerCommand extends Command
->addOption('interface', 'i', InputOption::VALUE_REQUIRED, 'Bind to interface.', '0.0.0.0')
->addOption('port', 'p', InputOption::VALUE_REQUIRED, 'Bind to port.', 8080)
->addOption('threads', 't', InputOption::VALUE_REQUIRED, 'How many threads to use.', 1)
->setHelp(
<<<HELP
This server is not meant to be used in production. It is mainly for testing purposes.
HELP
);
->setHelp('This server is not meant to be used in production. It is mainly for testing purposes.');
}
/**