Skip to content

Commit 3961fbd

Browse files
committed
Fixed bug preventing emby/jellyfin from adding new backends. Closes #360
1 parent 456f7d9 commit 3961fbd

12 files changed

+99
-14
lines changed

src/Backends/Emby/EmbyClient.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function withContext(Context $context): self
9090
'token' => $context->backendToken,
9191
'app' => Config::get('name') . '/' . static::CLIENT_NAME,
9292
'os' => PHP_OS,
93-
'id' => md5($context->backendUser),
93+
'id' => md5(Config::get('name') . '/' . static::CLIENT_NAME . $context->backendUser),
9494
'version' => getAppVersion(),
9595
'user' => $context->backendUser,
9696
]

src/Backends/Jellyfin/JellyfinClient.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function withContext(Context $context): self
105105
'token' => $context->backendToken,
106106
'app' => Config::get('name') . '/' . static::CLIENT_NAME,
107107
'os' => PHP_OS,
108-
'id' => md5($context->backendUser),
108+
'id' => md5(Config::get('name') . '/' . static::CLIENT_NAME . $context->backendUser),
109109
'version' => getAppVersion(),
110110
'user' => $context->backendUser,
111111
]

src/Backends/Jellyfin/JellyfinManage.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ public function manage(array $backend, array $opts = []): array
3737
);
3838

3939
$question->setValidator(function ($answer) {
40-
$host = parse_url($answer, PHP_URL_HOST);
41-
if (false === is_string($answer)) {
40+
if (false === isValidURL($answer)) {
4241
throw new RuntimeException(
4342
'Invalid backend URL was given. Expecting something like http://example.com:8096/'
4443
);

src/Backends/Plex/PlexManage.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ public function manage(array $backend, array $opts = []): array
156156
);
157157
158158
$question->setValidator(function ($answer) {
159-
$host = parse_url($answer, PHP_URL_HOST);
160-
if (false === is_string($answer)) {
159+
if (false === isValidURL($answer)) {
161160
throw new RuntimeException(
162161
'Invalid URL was selected/given. Expecting something like http://plex:32400.'
163162
);

src/Commands/Config/AddCommand.php

+72-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66

77
use App\Command;
88
use App\Libs\Routable;
9+
use RuntimeException;
910
use Symfony\Component\Console\Exception\ExceptionInterface;
11+
use Symfony\Component\Console\Helper\QuestionHelper;
1012
use Symfony\Component\Console\Input\ArrayInput;
1113
use Symfony\Component\Console\Input\InputArgument;
1214
use Symfony\Component\Console\Input\InputInterface;
1315
use Symfony\Component\Console\Input\InputOption;
1416
use Symfony\Component\Console\Output\OutputInterface;
17+
use Symfony\Component\Console\Question\Question;
1518

1619
#[Routable(command: self::ROUTE)]
1720
final class AddCommand extends Command
@@ -23,7 +26,7 @@ protected function configure(): void
2326
$this->setName(self::ROUTE)
2427
->setDescription('Add new backend.')
2528
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
26-
->addArgument('backend', InputArgument::REQUIRED, 'Backend name')
29+
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name', null)
2730
->setHelp(
2831
r(
2932
<<<HELP
@@ -50,6 +53,31 @@ protected function configure(): void
5053
*/
5154
protected function runCommand(InputInterface $input, OutputInterface $output): int
5255
{
56+
if (function_exists('stream_isatty') && defined('STDERR')) {
57+
$tty = stream_isatty(STDERR);
58+
} else {
59+
$tty = true;
60+
}
61+
62+
if (false === $tty || $input->getOption('no-interaction')) {
63+
$output->writeln(
64+
r(
65+
<<<ERROR
66+
67+
<error>ERROR:</error> This command require <notice>interaction</notice>. For example:
68+
69+
{cmd} <cmd>{route}</cmd>
70+
71+
ERROR,
72+
[
73+
'cmd' => trim(commandContext()),
74+
'route' => self::ROUTE,
75+
]
76+
)
77+
);
78+
return self::FAILURE;
79+
}
80+
5381
$opts = [
5482
'--add' => true,
5583
];
@@ -61,7 +89,49 @@ protected function runCommand(InputInterface $input, OutputInterface $output): i
6189
$opts['--' . $option] = $val;
6290
}
6391

64-
$opts['backend'] = strtolower($input->getArgument('backend'));
92+
$backend = $input->getArgument('backend');
93+
94+
if (null !== $backend) {
95+
$opts['backend'] = strtolower($backend);
96+
} else {
97+
// -- $backend.token
98+
$opts['backend'] = (function () use (&$opts, $input, $output) {
99+
$chosen = ag($opts, 'backend');
100+
101+
$question = new Question(
102+
<<<HELP
103+
<question>What should we be calling this <value>backend</value>?</question>
104+
------------------
105+
Backend name is used to identify the backend. The backend name must only contains
106+
<value>lower case a-z</value>, <value>0-9</value> and <value>_</value>.
107+
------------------
108+
<notice>Choose good name to identify your backend. For example, <value>home_plex</value>.</notice>
109+
HELP. PHP_EOL . '> ',
110+
$chosen
111+
);
112+
113+
$question->setValidator(function ($answer) {
114+
if (empty($answer)) {
115+
throw new RuntimeException('Backend Name cannot be empty.');
116+
}
117+
if (!isValidName($answer) || strtolower($answer) !== $answer) {
118+
throw new RuntimeException(
119+
r(
120+
'<error>ERROR:</error> Invalid [<value>{name}</value>] name was given. Only [<value>a-z, 0-9, _</value>] are allowed.',
121+
[
122+
'name' => $answer
123+
],
124+
)
125+
);
126+
}
127+
return $answer;
128+
});
129+
130+
return (new QuestionHelper())->ask($input, $output, $question);
131+
})();
132+
$output->writeln('');
133+
$opts['backend'] = strtolower($opts['backend']);
134+
}
65135

66136
return $this->getApplication()?->find(ManageCommand::ROUTE)->run(new ArrayInput($opts), $output) ?? 1;
67137
}

src/Commands/Config/ManageCommand.php

-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ protected function runCommand(InputInterface $input, OutputInterface $output, nu
7070
[
7171
'cmd' => trim(commandContext()),
7272
'route' => self::ROUTE,
73-
'backend' => $input->getArgument('backend'),
7473
]
7574
)
7675

src/Commands/State/BackupCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ protected function process(InputInterface $input, OutputInterface $output): int
177177
continue;
178178
}
179179

180-
if (null === ($url = ag($backend, 'url')) || true !== is_string(parse_url($url, PHP_URL_HOST))) {
180+
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
181181
$this->logger->error('SYSTEM: Ignoring [{backend}] because of invalid URL.', [
182182
'backend' => $backendName,
183183
'url' => $url ?? 'None',

src/Commands/State/ExportCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ protected function process(InputInterface $input, OutputInterface $output): int
164164
continue;
165165
}
166166

167-
if (null === ($url = ag($backend, 'url')) || true !== is_string(parse_url($url, PHP_URL_HOST))) {
167+
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
168168
$this->logger->error(
169169
sprintf('%s: Backend does not have valid url.', $backendName),
170170
['url' => $url ?? 'None']

src/Commands/State/ImportCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ protected function process(InputInterface $input, OutputInterface $output): int
298298
continue;
299299
}
300300

301-
if (null === ($url = ag($backend, 'url')) || true !== is_string(parse_url($url, PHP_URL_HOST))) {
301+
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
302302
$this->logger->error('SYSTEM: Ignoring [{backend}] because of invalid URL.', [
303303
'backend' => $backendName,
304304
'url' => $url ?? 'None',

src/Commands/State/ProgressCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ protected function process(InputInterface $input, OutputInterface $output): int
146146
continue;
147147
}
148148

149-
if (null === ($url = ag($backend, 'url')) || true !== is_string(parse_url($url, PHP_URL_HOST))) {
149+
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
150150
$this->logger->error('SYSTEM: [{backend}] Invalid url.', [
151151
'backend' => $backendName,
152152
'url' => $url ?? 'None',

src/Commands/State/PushCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ protected function process(InputInterface $input): int
133133
continue;
134134
}
135135

136-
if (null === ($url = ag($backend, 'url')) || true !== is_string(parse_url($url, PHP_URL_HOST))) {
136+
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
137137
$this->logger->error('SYSTEM: [{backend}] Invalid url.', [
138138
'backend' => $backendName,
139139
'url' => $url ?? 'None',

src/Libs/helpers.php

+18
Original file line numberDiff line numberDiff line change
@@ -842,3 +842,21 @@ function inContainer(): bool
842842
return false;
843843
}
844844
}
845+
846+
if (false === function_exists('isValidURL')) {
847+
/**
848+
* Validate URL - RFC 3987 (IRI)
849+
*
850+
* @param string $url
851+
*
852+
* @return bool
853+
*/
854+
function isValidURL(string $url): bool
855+
{
856+
// RFC 3987 For absolute IRIs (internationalized):
857+
return (bool)@preg_match(
858+
'/^[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[-a-z0-9\._~!\$&\'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}|\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&\'\(\)\*\+,;=:@])|[\/\?])*)?$/iu',
859+
$url
860+
);
861+
}
862+
}

0 commit comments

Comments
 (0)