diff --git a/src/Backends/Jellyfin/JellyfinManage.php b/src/Backends/Jellyfin/JellyfinManage.php
index c07afa34..f420fd51 100644
--- a/src/Backends/Jellyfin/JellyfinManage.php
+++ b/src/Backends/Jellyfin/JellyfinManage.php
@@ -60,10 +60,13 @@ class JellyfinManage implements ManageInterface
$chosen = ag($backend, 'token');
$question = new Question(
- r('Enter [{name}] API token. {default}' . PHP_EOL . '> ', [
- 'name' => ag($backend, 'name'),
- 'default' => null !== $chosen ? "[Default: {$chosen}]" : '',
- ]),
+ r(
+ 'Enter [{name}] API key or "username:password" for oauth token generation. {default}' . PHP_EOL . '> ',
+ [
+ 'name' => ag($backend, 'name'),
+ 'default' => null !== $chosen ? "[Default: {$chosen}]" : '',
+ ]
+ ),
$chosen
);
@@ -86,7 +89,47 @@ class JellyfinManage implements ManageInterface
});
$token = $this->questionHelper->ask($this->input, $this->output, $question);
- $backend = ag_set($backend, 'token', $token);
+
+ if (true === str_contains($token, ':')) {
+ [$username, $password] = explode(':', $token, 2);
+ if (empty($username) || empty($password)) {
+ $this->output->writeln('Invalid username or password was given.');
+ goto re_goto_token;
+ }
+
+ // we are probably dealing with a username:password, try to generate oAuth token.
+ $this->output->writeln(
+ 'Attempting to generate oAuth token from username and password. Please wait...'
+ );
+
+ $backend = ag_set($backend, 'token', 'oauth_token');
+
+ try {
+ $accessToken = makeBackend($backend)->generateAccessToken($username, $password);
+ } catch (Throwable $e) {
+ $this->output->writeln('Failed to generate oAuth token from username and password.');
+ $this->output->writeln(
+ sprintf(
+ 'ERROR - %s: %s.' . PHP_EOL,
+ afterLast(get_class($e), '\\'),
+ $e->getMessage()
+ )
+ );
+ $backend = ag_set($backend, 'token', null);
+ goto re_goto_token;
+ }
+
+ $backend = ag_set($backend, 'token', ag($accessToken, 'accesstoken'));
+ $backend = ag_set($backend, 'user', ag($accessToken, 'user'));
+ $backend = ag_set($backend, 'uuid', ag($accessToken, 'identifier'));
+ $backend = ag_set($backend, 'options.' . Options::IS_LIMITED_TOKEN, true);
+ } else {
+ $backend = ag_set($backend, 'token', $token);
+ }
+
+ if (true === (bool)ag($backend, 'options.' . Options::IS_LIMITED_TOKEN, false)) {
+ return;
+ }
$this->output->writeln('');
@@ -124,6 +167,8 @@ class JellyfinManage implements ManageInterface
]
)
);
+ $backend = ag_set($backend, 'uuid', $chosen);
+ return;
} catch (Throwable $e) {
$this->output->writeln('Failed to get the backend unique identifier.');
$this->output->writeln(r('ERROR - {kind}: {message}.' . PHP_EOL, [
@@ -135,66 +180,6 @@ class JellyfinManage implements ManageInterface
goto re_goto_token;
}
-
- $question = new Question(
- r(
- <<Enter [{name}] Unique identifier. {default}
- ------------------
- The Server Unique identifier is randomly generated string on server setup.
- ------------------
- If you select invalid or give incorrect server unique identifier, Some checks will
- fail And you may not be able to sync your backend.
- ------------------
- DO NOT CHANGE the default value unless you know what you are doing, or was told by devs.
- HELP. PHP_EOL . '> ',
- [
- 'name' => ag($backend, 'name'),
- 'default' => "[Default: {$chosen}]",
- ]
- ),
- $chosen
- );
-
- $question->setValidator(function ($answer) use ($custom) {
- if (empty($answer)) {
- throw new RuntimeException('Backend unique identifier cannot be empty.');
- }
-
- if (!is_string($answer) && !is_int($answer)) {
- throw new RuntimeException(
- r(
- "Backend unique identifier is invalid. Expecting string or integer, but got '{type}' instead.",
- [
- 'type' => get_debug_type($answer)
- ]
- )
- );
- }
-
- $backendUUid = makeBackend($custom, ag($custom, 'name'))->getIdentifier(true);
-
- if ('auto' === $answer && !empty($backendUUid)) {
- return $backendUUid;
- }
-
- if ($answer !== $backendUUid) {
- throw new RuntimeException(
- r(
- 'Invalid backend unique identifier was given. Expecting "{uuid}", but got "{answer}" instead.',
- [
- 'uuid' => $backendUUid,
- 'answer' => $answer
- ]
- )
- );
- }
-
- return $answer;
- });
-
- $uuid = $this->questionHelper->ask($this->input, $this->output, $question);
- $backend = ag_set($backend, 'uuid', $uuid);
})();
$this->output->writeln('');
diff --git a/src/Commands/Config/AddCommand.php b/src/Commands/Config/AddCommand.php
index b58ed14a..76113b1f 100644
--- a/src/Commands/Config/AddCommand.php
+++ b/src/Commands/Config/AddCommand.php
@@ -23,7 +23,7 @@ use Symfony\Component\Console\Question\Question;
#[Cli(command: self::ROUTE)]
final class AddCommand extends Command
{
- public const ROUTE = 'config:add';
+ public const string ROUTE = 'config:add';
/**
* Configures the command.
diff --git a/src/Commands/Config/ManageCommand.php b/src/Commands/Config/ManageCommand.php
index b9914173..9dbbaa9a 100644
--- a/src/Commands/Config/ManageCommand.php
+++ b/src/Commands/Config/ManageCommand.php
@@ -5,11 +5,11 @@ declare(strict_types=1);
namespace App\Commands\Config;
use App\Command;
-use App\Commands\State\ImportCommand;
use App\Commands\System\IndexCommand;
use App\Libs\Attributes\Route\Cli;
use App\Libs\Config;
use App\Libs\ConfigFile;
+use App\Libs\Exceptions\Backends\InvalidContextException;
use App\Libs\Options;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Exception\ExceptionInterface;
@@ -30,7 +30,7 @@ use Throwable;
#[Cli(command: self::ROUTE)]
final class ManageCommand extends Command
{
- public const ROUTE = 'config:manage';
+ public const string ROUTE = 'config:manage';
public function __construct(private LoggerInterface $logger)
{
@@ -117,6 +117,8 @@ final class ManageCommand extends Command
return self::FAILURE;
}
+ go_start:
+
if (true === $add) {
if (null !== $configFile->get("{$name}.type", null)) {
$output->writeln(
@@ -384,7 +386,24 @@ final class ManageCommand extends Command
);
if (false === $helper->ask($input, $output, $question)) {
- return $this->runCommand($input, $output, $u);
+ goto go_start;
+ }
+
+ try {
+ $output->writeln('Validating backend context. Please wait...');
+ $client = makeBackend($u, $name);
+ $client->setLogger($this->logger);
+ if (false === $client->validateContext($client->getContext())) {
+ $output->writeln('ERROR: Backend context is invalid.');
+ goto go_start;
+ }
+ } catch (InvalidContextException $e) {
+ $output->writeln(
+ r('ERROR: Backend context validation has failed. {error}', [
+ 'error' => $e->getMessage()
+ ])
+ );
+ goto go_start;
}
$configFile->set($name, $u)->persist();
@@ -411,41 +430,6 @@ final class ManageCommand extends Command
if (true === $helper->ask($input, $output, $question)) {
$this->getApplication()?->find(IndexCommand::ROUTE)->run(new ArrayInput([]), $output);
}
-
- $importEnabled = (bool)ag($u, 'import.enabled');
- $metaEnabled = (bool)ag($u, 'options.' . Options::IMPORT_METADATA_ONLY);
-
- if (true === $importEnabled || true === $metaEnabled) {
- $importType = $importEnabled ? 'play state & metadata' : 'metadata only.';
-
- $helper = $this->getHelper('question');
- $text =
- <<Would you like to import {type} from the backend now? [Y|N] [Default: No]
- -----------------
- P.S: this could take few minutes to execute.
-
- TEXT;
-
- $text = r($text, ['type' => $importType]);
-
- $question = new ConfirmationQuestion($text . PHP_EOL . '> ', false);
-
- if (true === $helper->ask($input, $output, $question)) {
- $output->writeln(
- r('Importing {type} from {name}', [
- 'name' => $name,
- 'type' => $importType
- ])
- );
-
- $cmd = $this->getApplication()?->find(ImportCommand::ROUTE);
- $cmd->run(new ArrayInput(['--quiet', '--select-backend' => [$name]]), $output);
- }
-
- $output->writeln('Import complete');
- }
}
return self::SUCCESS;
diff --git a/src/Commands/Config/TestCommand.php b/src/Commands/Config/TestCommand.php
index e84cf68b..35270887 100644
--- a/src/Commands/Config/TestCommand.php
+++ b/src/Commands/Config/TestCommand.php
@@ -144,7 +144,7 @@ final class TestCommand extends Command
foreach ($backends as $backendName => $backend) {
$backend = $this->getBackend($backendName);
$context = $backend->getContext();
- $output->writeln(r("Running '{client}' functional tests on '{backend}'.", [
+ $output->writeln(r("Running '{client}' client functional tests on '{backend}'.", [
'client' => $context->clientName,
'backend' => $context->backendName,
]));