update mapper.yaml spec
This commit is contained in:
59
FAQ.md
59
FAQ.md
@@ -236,35 +236,42 @@ the [mapper.yaml](#whats-the-schema-for-the-mapperyaml-file) section.
|
||||
The schema is simple, it's a list of users in the following format:
|
||||
|
||||
```yaml
|
||||
# 1st user...
|
||||
- my_plex_server:
|
||||
name: "mike_jones"
|
||||
options: { }
|
||||
my_jellyfin_server:
|
||||
name: "jones_mike"
|
||||
options: { }
|
||||
my_emby_server:
|
||||
name: "mikeJones"
|
||||
options: { }
|
||||
# 2nd user...
|
||||
- my_emby_server:
|
||||
name: "jiji_jones"
|
||||
options: { }
|
||||
my_plex_server:
|
||||
name: "jones_jiji"
|
||||
options: { }
|
||||
my_jellyfin_server:
|
||||
name: "jijiJones"
|
||||
options: { }
|
||||
#.... more users
|
||||
version: "1.5"
|
||||
mapping:
|
||||
# 1st user...
|
||||
- my_plex_server:
|
||||
name: "mike_jones"
|
||||
options: { } # optional key.
|
||||
my_jellyfin_server:
|
||||
name: "jones_mike"
|
||||
my_emby_server:
|
||||
name: "mikeJones"
|
||||
replace_with: "mike_jones" # optional action, to replace the username with the new one.
|
||||
# 2nd user...
|
||||
- my_emby_server:
|
||||
name: "jiji_jones"
|
||||
options: { } # optional key.
|
||||
my_plex_server:
|
||||
name: "jones_jiji"
|
||||
my_jellyfin_server:
|
||||
name: "jijiJones"
|
||||
replace_with: "jiji_jones" # optional action, to replace the username with the new one.
|
||||
#.... more users
|
||||
```
|
||||
|
||||
> ![NOTE]
|
||||
> the server names `my_plex_server`, `my_jellyfin_server`, `my_emby_server` are the names you have chosen for your
|
||||
> backends.
|
||||
> the `name` is the real username for that user from the backend.
|
||||
> [!IMPORTANT]
|
||||
> As we enforce specific naming convention for backend names and usernames they must follow the following format
|
||||
> `^[a-z_0-9]+$` which means, lowercase letters, numbers and `_` are allowed. No spaces, uppercase letters or special
|
||||
> characters are allowed. you can use the `replace_with` key to replace the username with the new one. if it's not
|
||||
> complying with the naming convention, or you want to force specific display name.
|
||||
|
||||
This yaml file helps map your users username in the different backends, so the tool can sync the correct user data. If
|
||||
> ![NOTE]
|
||||
> the backend names `my_plex_server`, `my_jellyfin_server`, `my_emby_server` are the names you have chosen for
|
||||
> your> backends.
|
||||
>
|
||||
> The `name` field is whatever the backend is reporting the username as.
|
||||
|
||||
This yaml file helps map your users usernames in the different backends, so the tool can sync the correct user data. If
|
||||
you added or updated mapping, you should delete `users` directory and generate new data. by running the `backend:create`
|
||||
command as described in the previous section.
|
||||
|
||||
|
||||
14
composer.lock
generated
14
composer.lock
generated
@@ -3580,12 +3580,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||
"reference": "0b51a6c830ba6dd6c63715ceded239a62bf2274f"
|
||||
"reference": "975c081c7e430d0316a94047e5d8ab26e0a8f49e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0b51a6c830ba6dd6c63715ceded239a62bf2274f",
|
||||
"reference": "0b51a6c830ba6dd6c63715ceded239a62bf2274f",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/975c081c7e430d0316a94047e5d8ab26e0a8f49e",
|
||||
"reference": "975c081c7e430d0316a94047e5d8ab26e0a8f49e",
|
||||
"shasum": ""
|
||||
},
|
||||
"conflict": {
|
||||
@@ -3614,7 +3614,8 @@
|
||||
"andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5",
|
||||
"apache-solr-for-typo3/solr": "<2.8.3",
|
||||
"apereo/phpcas": "<1.6",
|
||||
"api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3|>=3.3.8,<3.3.15",
|
||||
"api-platform/core": "<4.0.22",
|
||||
"api-platform/graphql": "<4.0.22",
|
||||
"appwrite/server-ce": "<=1.2.1",
|
||||
"arc/web": "<3",
|
||||
"area17/twill": "<1.2.5|>=2,<2.5.3",
|
||||
@@ -3688,7 +3689,7 @@
|
||||
"codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9",
|
||||
"components/jquery": ">=1.0.3,<3.5",
|
||||
"composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7",
|
||||
"concrete5/concrete5": "<9.4.0.0-RC1-dev",
|
||||
"concrete5/concrete5": "<9.4.0.0-RC2-dev",
|
||||
"concrete5/core": "<8.5.8|>=9,<9.1",
|
||||
"contao-components/mediaelement": ">=2.14.2,<2.21.1",
|
||||
"contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4",
|
||||
@@ -3746,6 +3747,7 @@
|
||||
"drupal/matomo": "<1.24",
|
||||
"drupal/oauth2_client": "<4.1.3",
|
||||
"drupal/oauth2_server": "<2.1",
|
||||
"drupal/obfuscate": "<2.0.1",
|
||||
"drupal/rapidoc_elements_field_formatter": "<1.0.1",
|
||||
"drupal/spamspan": "<3.2.1",
|
||||
"drupal/tfa": "<1.10",
|
||||
@@ -4468,7 +4470,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-02T18:06:24+00:00"
|
||||
"time": "2025-04-04T15:05:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"cronstrue": "^2.57.0",
|
||||
"floating-vue": "^5.2.2",
|
||||
"hls.js": "^1.6.0",
|
||||
"hls.js": "^1.6.1",
|
||||
"marked": "^15.0.7",
|
||||
"marked-base-url": "^1.1.3",
|
||||
"moment": "^2.30.1",
|
||||
|
||||
@@ -531,11 +531,11 @@
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@nuxt/cli@^3.24.0":
|
||||
version "3.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-3.24.0.tgz#084e3be55e4abd22c7e1c5e07b4bf3c61a7e49fe"
|
||||
integrity sha512-D/rCodMHecznWZAxsb81lKSMhCcWIUI6TyEDQ3WIl2bTNBn4WvIYrZP3rIPJn7X4A+/CG5H8yhKDVP6Mq7XopA==
|
||||
version "3.24.1"
|
||||
resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-3.24.1.tgz#7a864e3133506859254547dc221fab2f11b852a6"
|
||||
integrity sha512-dWoB3gZj2H04x58QWNWpshQUxjsf0TB6Ppy7YKswS5hGtQkOlQ5k85f133+Bg50TJqzNuZ3OUMRduftppdJjrg==
|
||||
dependencies:
|
||||
c12 "^3.0.2"
|
||||
c12 "^3.0.3"
|
||||
chokidar "^4.0.3"
|
||||
citty "^0.1.6"
|
||||
clipboardy "^4.0.0"
|
||||
@@ -1593,22 +1593,22 @@ bundle-name@^4.1.0:
|
||||
dependencies:
|
||||
run-applescript "^7.0.0"
|
||||
|
||||
c12@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/c12/-/c12-3.0.2.tgz#5ceba55cf081ff4cf95b22c593c80b34cf1f3d2e"
|
||||
integrity sha512-6Tzk1/TNeI3WBPpK0j/Ss4+gPj3PUJYbWl/MWDJBThFvwNGNkXtd7Cz8BJtD4aRwoGHtzQD0SnxamgUiBH0/Nw==
|
||||
c12@^3.0.2, c12@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/c12/-/c12-3.0.3.tgz#4d6d4d35f084606ff616d1bcae60e6676eacd4bd"
|
||||
integrity sha512-uC3MacKBb0Z15o5QWCHvHWj5Zv34pGQj9P+iXKSpTuSGFS0KKhUWf4t9AJ+gWjYOdmWCPEGpEzm8sS0iqbpo1w==
|
||||
dependencies:
|
||||
chokidar "^4.0.3"
|
||||
confbox "^0.1.8"
|
||||
confbox "^0.2.2"
|
||||
defu "^6.1.4"
|
||||
dotenv "^16.4.7"
|
||||
exsolve "^1.0.0"
|
||||
exsolve "^1.0.4"
|
||||
giget "^2.0.0"
|
||||
jiti "^2.4.2"
|
||||
ohash "^2.0.5"
|
||||
ohash "^2.0.11"
|
||||
pathe "^2.0.3"
|
||||
perfect-debounce "^1.0.0"
|
||||
pkg-types "^2.0.0"
|
||||
pkg-types "^2.1.0"
|
||||
rc9 "^2.1.2"
|
||||
|
||||
cac@^6.7.14:
|
||||
@@ -1627,9 +1627,9 @@ caniuse-api@^3.0.0:
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001688, caniuse-lite@^1.0.30001702:
|
||||
version "1.0.30001707"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz#c5e104d199e6f4355a898fcd995a066c7eb9bf41"
|
||||
integrity sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==
|
||||
version "1.0.30001711"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001711.tgz#8f9e7c5ec8a027f88e00462f796ef1fd6c63f734"
|
||||
integrity sha512-OpFA8GsKtoV3lCcsI3U5XBAV+oVrMu96OS8XafKqnhOaEAW2mveD1Mx81Sx/02chERwhDakuXs28zbyEc4QMKg==
|
||||
|
||||
chokidar@^4.0.3:
|
||||
version "4.0.3"
|
||||
@@ -1726,10 +1726,10 @@ confbox@^0.1.8:
|
||||
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06"
|
||||
integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
|
||||
|
||||
confbox@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.1.tgz#ae39f2c99699afa451d00206479f15f9a1208a8b"
|
||||
integrity sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==
|
||||
confbox@^0.2.1, confbox@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110"
|
||||
integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==
|
||||
|
||||
consola@^3.2.3, consola@^3.4.0, consola@^3.4.2:
|
||||
version "3.4.2"
|
||||
@@ -1983,9 +1983,9 @@ depd@2.0.0:
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
destr@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449"
|
||||
integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb"
|
||||
integrity sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==
|
||||
|
||||
destroy@1.2.0:
|
||||
version "1.2.0"
|
||||
@@ -2070,9 +2070,9 @@ ee-first@1.1.1:
|
||||
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
|
||||
|
||||
electron-to-chromium@^1.5.73:
|
||||
version "1.5.129"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.129.tgz#fafa835aea5d15fcd5cbe9bd6bf1cb5d4b3aa06e"
|
||||
integrity sha512-JlXUemX4s0+9f8mLqib/bHH8gOHf5elKS6KeWG3sk3xozb/JTq/RLXIv8OKUWiK4Ah00Wm88EFj5PYkFr4RUPA==
|
||||
version "1.5.132"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.132.tgz#081b8086d7cecc58732f7cc1f1c19306c5510c5f"
|
||||
integrity sha512-QgX9EBvWGmvSRa74zqfnG7+Eno0Ak0vftBll0Pt2/z5b3bEGYL6OUXLgKPtvx73dn3dvwrlyVkjPKRRlhLYTEg==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
@@ -2210,7 +2210,7 @@ execa@^8.0.1:
|
||||
signal-exit "^4.1.0"
|
||||
strip-final-newline "^3.0.0"
|
||||
|
||||
exsolve@^1.0.0, exsolve@^1.0.1, exsolve@^1.0.4:
|
||||
exsolve@^1.0.1, exsolve@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.4.tgz#7de5c75af82ecd15998328fbf5f2295883be3a39"
|
||||
integrity sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==
|
||||
@@ -2344,9 +2344,9 @@ giget@^2.0.0:
|
||||
pathe "^2.0.3"
|
||||
|
||||
git-up@^8.0.0:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/git-up/-/git-up-8.0.1.tgz#2a82cfbc77b5eb04074ab1e48593911981654fc7"
|
||||
integrity sha512-2XFu1uNZMSjkyetaF+8rqn6P0XqpMq/C+2ycjI6YwrIKcszZ5/WR4UubxjN0lILOKqLkLaHDaCr2B6fP1cke6g==
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/git-up/-/git-up-8.1.0.tgz#1494a4b2b20a8cdef1b32539f12cb546a199fc5e"
|
||||
integrity sha512-cT2f5ERrhFDMPS5wLHURcjRiacC8HonX0zIAWBTwHv1fS6HheP902l6pefOX/H9lNmvCHDwomw0VeN7nhg5bxg==
|
||||
dependencies:
|
||||
is-ssh "^1.4.0"
|
||||
parse-url "^9.2.0"
|
||||
@@ -2435,10 +2435,10 @@ hasown@^2.0.2:
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
hls.js@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.6.0.tgz#ec0118f1dcd0fce536e52c27f674cdf944055b30"
|
||||
integrity sha512-AlW8ymcDKZuKtzXCUmEy4nOcHRkebnShH6t6hC2+QJQP0WXlTUSSO9Kp22uSEYdCgpwkXEJsfOhqxrgO2tDctQ==
|
||||
hls.js@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.6.1.tgz#2a808924d90465e44db8bf29dde31de8e4d313cf"
|
||||
integrity sha512-7GOkcqn0Y9EqU2OJZlzkwxj9Uynuln7URvr7dRjgqNJNZ5UbbjL/v1BjAvQogy57Psdd/ek1u2s6IDEFYlabrA==
|
||||
|
||||
hookable@^5.5.3:
|
||||
version "5.5.3"
|
||||
@@ -2885,9 +2885,9 @@ mime@^3.0.0:
|
||||
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
|
||||
|
||||
mime@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.6.tgz#ca83bec0bcf2a02353d0e02da99be05603d04839"
|
||||
integrity sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.7.tgz#0b7a98b08c63bd3c10251e797d67840c9bde9f13"
|
||||
integrity sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==
|
||||
|
||||
mimic-fn@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -3227,7 +3227,7 @@ ofetch@^1.4.1:
|
||||
node-fetch-native "^1.6.4"
|
||||
ufo "^1.5.4"
|
||||
|
||||
ohash@^2.0.11, ohash@^2.0.4, ohash@^2.0.5:
|
||||
ohash@^2.0.11, ohash@^2.0.4:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/ohash/-/ohash-2.0.11.tgz#60b11e8cff62ca9dee88d13747a5baa145f5900b"
|
||||
integrity sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==
|
||||
@@ -3997,9 +3997,9 @@ statuses@2.0.1:
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
std-env@^3.7.0, std-env@^3.8.1:
|
||||
version "3.8.1"
|
||||
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.1.tgz#2b81c631c62e3d0b964b87f099b8dcab6c9a5346"
|
||||
integrity sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.9.0.tgz#1a6f7243b339dca4c9fd55e1c7504c77ef23e8f1"
|
||||
integrity sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==
|
||||
|
||||
streamx@^2.15.0:
|
||||
version "2.22.0"
|
||||
@@ -4227,9 +4227,9 @@ tslib@^2.4.0:
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
type-fest@^4.18.2:
|
||||
version "4.39.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.39.0.tgz#c7758be50a83a5b879e7a59ea52421e9816b3928"
|
||||
integrity sha512-w2IGJU1tIgcrepg9ZJ82d8UmItNQtOFJG0HCUE3SzMokKkTsruVDALl2fAdiEzJlfduoU+VyXJWIIUZ+6jV+nw==
|
||||
version "4.39.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.39.1.tgz#7521f6944e279abaf79cf60cfbc4823f4858083e"
|
||||
integrity sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==
|
||||
|
||||
ufo@^1.1.2, ufo@^1.5.4:
|
||||
version "1.5.4"
|
||||
@@ -4237,9 +4237,9 @@ ufo@^1.1.2, ufo@^1.5.4:
|
||||
integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==
|
||||
|
||||
ultrahtml@^1.5.3:
|
||||
version "1.5.3"
|
||||
resolved "https://registry.yarnpkg.com/ultrahtml/-/ultrahtml-1.5.3.tgz#e7a903a4b28a0e49b71b0801b444050bb0a369c7"
|
||||
integrity sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/ultrahtml/-/ultrahtml-1.6.0.tgz#0d1aad7bbfeae512438d30e799c11622127a1ac8"
|
||||
integrity sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==
|
||||
|
||||
uncrypto@^0.1.3:
|
||||
version "0.1.3"
|
||||
@@ -4484,9 +4484,9 @@ vite-plugin-vue-tracer@^0.1.3:
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
"vite@^5.0.0 || ^6.0.0", vite@^6.2.4:
|
||||
version "6.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.4.tgz#05809de3f918fded87f73a838761995a4d66a680"
|
||||
integrity sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.5.tgz#d093b5fe8eb96e594761584a966ab13f24457820"
|
||||
integrity sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
postcss "^8.5.3"
|
||||
|
||||
@@ -43,6 +43,7 @@ class CreateUsersCommand extends Command
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->addOption('regenerate-tokens', 'g', InputOption::VALUE_NONE, 'Generate new tokens for PLEX users.')
|
||||
->addOption('--dry-run', null, InputOption::VALUE_NONE, 'Do not commit any changes.')
|
||||
->addOption(
|
||||
'update',
|
||||
'u',
|
||||
@@ -125,6 +126,12 @@ class CreateUsersCommand extends Command
|
||||
*/
|
||||
protected function runCommand(iInput $input, iOutput $output): int
|
||||
{
|
||||
$dryRun = $input->getOption('dry-run');
|
||||
|
||||
if ($dryRun) {
|
||||
$this->logger->notice('SYSTEM: Running in dry-run mode. No changes will be made.');
|
||||
}
|
||||
|
||||
$supported = Config::get('supported', []);
|
||||
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
|
||||
$configFile->setLogger($this->logger);
|
||||
@@ -134,7 +141,12 @@ class CreateUsersCommand extends Command
|
||||
|
||||
if (file_exists($mapFile) && filesize($mapFile) > 10) {
|
||||
$map = ConfigFile::open(Config::get('mapper_file'), 'yaml');
|
||||
$mapping = $map->getAll();
|
||||
$mapping = $map->get('map', $map->getAll());
|
||||
if (false === $map->has('version') || false === $map->has('map')) {
|
||||
$this->logger->warning(
|
||||
"SYSTEM: UPGRADE your mapper.yaml file to v1.5 format spec, check the FAQ.md for the updated format. Th old format will be removed in future releases.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$backends = [];
|
||||
@@ -187,6 +199,9 @@ class CreateUsersCommand extends Command
|
||||
foreach ($client->getUsersList() as $user) {
|
||||
/** @var array $info */
|
||||
$info = $backend;
|
||||
|
||||
$user = $this->map_actions($user, ag($backend, 'name'), $mapping);
|
||||
|
||||
$info['user'] = ag($user, 'id', ag($info, 'user'));
|
||||
$info['backendName'] = strtolower(r("{backend}_{user}", [
|
||||
'backend' => ag($backend, 'name'),
|
||||
@@ -206,7 +221,7 @@ class CreateUsersCommand extends Command
|
||||
if (false === isValidName($info['displayName'])) {
|
||||
$rename = substr(md5($info['displayName']), 0, 8);
|
||||
$this->logger->error(
|
||||
message: "SYSTEM: Renaming invalid username '{name}'. username must be in [a-z_0-9], renaming to '{renamed}'",
|
||||
message: "SYSTEM: Renaming invalid display username '{name}'. username must be in [a-z_0-9], renaming to '{renamed}'",
|
||||
context: ['name' => $info['displayName'], 'renamed' => $rename]
|
||||
);
|
||||
$info['displayName'] = $rename;
|
||||
@@ -262,7 +277,7 @@ class CreateUsersCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$users = $this->generate_users_list($users, $mapping);
|
||||
$users = $this->generate_users_list($users);
|
||||
|
||||
if (count($users) < 1) {
|
||||
$this->logger->warning('No users were found.');
|
||||
@@ -274,7 +289,7 @@ class CreateUsersCommand extends Command
|
||||
]);
|
||||
|
||||
foreach ($users as $user) {
|
||||
$userName = strtolower(ag($user, 'name', 'Unknown'));
|
||||
$userName = strtolower(ag($user, 'name', 'unknown'));
|
||||
if (false === isValidName($userName)) {
|
||||
$rename = substr(md5($userName), 0, 8);
|
||||
$this->logger->error(
|
||||
@@ -292,7 +307,7 @@ class CreateUsersCommand extends Command
|
||||
'path' => $subUserPath
|
||||
]);
|
||||
|
||||
if (false === mkdir($subUserPath, 0755, true)) {
|
||||
if (false === $dryRun && false === mkdir($subUserPath, 0755, true)) {
|
||||
$this->logger->error("SYSTEM: Failed to create '{user}' directory '{path}'.", [
|
||||
'user' => $userName,
|
||||
'path' => $subUserPath
|
||||
@@ -307,7 +322,14 @@ class CreateUsersCommand extends Command
|
||||
'file' => $config_file
|
||||
]);
|
||||
|
||||
$perUser = ConfigFile::open($config_file, 'yaml', autoCreate: true);
|
||||
$perUser = ConfigFile::open(
|
||||
file: $dryRun ? fopen("php://memory", 'a') : $config_file,
|
||||
type: 'yaml',
|
||||
autoSave: !$dryRun,
|
||||
autoCreate: !$dryRun,
|
||||
autoBackup: !$dryRun
|
||||
);
|
||||
|
||||
$perUser->setLogger($this->logger);
|
||||
$regenerateTokens = $input->getOption('regenerate-tokens');
|
||||
|
||||
@@ -432,10 +454,14 @@ class CreateUsersCommand extends Command
|
||||
'user' => $userName,
|
||||
'db' => $dbFile
|
||||
]);
|
||||
perUserDb($userName);
|
||||
if (false === $dryRun) {
|
||||
perUserDb($userName);
|
||||
}
|
||||
}
|
||||
|
||||
$perUser->persist();
|
||||
if (false === $dryRun) {
|
||||
$perUser->persist();
|
||||
}
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
@@ -445,11 +471,10 @@ class CreateUsersCommand extends Command
|
||||
* Generate a list of users that are matched across all backends.
|
||||
*
|
||||
* @param array $users The list of users from all backends.
|
||||
* @param array{string: array{string: string, options: array}} $map The map of users to match.
|
||||
*
|
||||
* @return array{name: string, backends: array<string, array<string, mixed>>}[] The list of matched users.
|
||||
*/
|
||||
private function generate_users_list(array $users, array $map = []): array
|
||||
private function generate_users_list(array $users): array
|
||||
{
|
||||
$allBackends = [];
|
||||
foreach ($users as $u) {
|
||||
@@ -464,7 +489,10 @@ class CreateUsersCommand extends Command
|
||||
$backend = $user['backend'];
|
||||
$nameLower = strtolower($user['name']);
|
||||
if (ag($user, 'id') === ag($user, 'client_data.options.' . Options::ALT_ID)) {
|
||||
$this->logger->debug('Skipping main user "{name}".', ['name' => $user['name']]);
|
||||
$this->logger->debug('Skipping main user "{backend}: {name}".', [
|
||||
'name' => $user['name'],
|
||||
'backend' => $user['backend'],
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
if (!isset($usersBy[$backend])) {
|
||||
@@ -570,80 +598,6 @@ class CreateUsersCommand extends Command
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map-based matching first
|
||||
$matchedMapEntry = null;
|
||||
foreach ($map as $mapRow) {
|
||||
if (isset($mapRow[$backend]['name']) && strtolower($mapRow[$backend]['name']) === $nameLower) {
|
||||
$matchedMapEntry = $mapRow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($matchedMapEntry) {
|
||||
// Build mapMatch from the map row.
|
||||
$mapMatch = [$backend => $userObj];
|
||||
|
||||
// Gather all the other backends from the map
|
||||
foreach ($allBackends as $otherBackend) {
|
||||
if ($otherBackend === $backend) {
|
||||
continue;
|
||||
}
|
||||
if (isset($matchedMapEntry[$otherBackend]['name'])) {
|
||||
$mappedNameLower = strtolower($matchedMapEntry[$otherBackend]['name']);
|
||||
if (isset($usersBy[$otherBackend][$mappedNameLower])) {
|
||||
$mapMatch[$otherBackend] = $usersBy[$otherBackend][$mappedNameLower];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we matched ≥ 2 backends, unify them
|
||||
if (count($mapMatch) >= 2) {
|
||||
// --- MERGE map-based "options" into client_data => options, if any ---
|
||||
foreach ($mapMatch as $b => &$matchedUser) {
|
||||
// If the map entry has an 'options' array for this backend,
|
||||
// merge it into $matchedUser['client_data']['options'].
|
||||
if (isset($matchedMapEntry[$b]['options']) && is_array($matchedMapEntry[$b]['options'])) {
|
||||
$mapOptions = $matchedMapEntry[$b]['options'];
|
||||
|
||||
// Ensure $matchedUser['client_data'] is an array
|
||||
if (!isset($matchedUser['client_data']) || !is_array($matchedUser['client_data'])) {
|
||||
$matchedUser['client_data'] = [];
|
||||
}
|
||||
|
||||
// Ensure $matchedUser['client_data']['options'] is an array
|
||||
if (!isset($matchedUser['client_data']['options']) || !is_array(
|
||||
$matchedUser['client_data']['options']
|
||||
)) {
|
||||
$matchedUser['client_data']['options'] = [];
|
||||
}
|
||||
|
||||
// Merge the map's options
|
||||
$matchedUser['client_data']['options'] = array_replace_recursive(
|
||||
$matchedUser['client_data']['options'],
|
||||
$mapOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
unset($matchedUser); // break reference from the loop
|
||||
|
||||
// Build final row
|
||||
$results[] = $buildUnifiedRow($mapMatch);
|
||||
|
||||
// Mark & remove from $usersBy
|
||||
foreach ($mapMatch as $b => $mu) {
|
||||
$nm = strtolower($mu['name']);
|
||||
$used[] = [$b, $nm];
|
||||
unset($usersBy[$b][$nm]);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
$this->logger->error("No partial fallback match via map for '{backend}: {user}'", [
|
||||
'backend' => $userObj['backend'],
|
||||
'user' => $userObj['name'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Direct-name matching if map fails
|
||||
$directMatch = [$backend => $userObj];
|
||||
foreach ($allBackends as $otherBackend) {
|
||||
@@ -671,7 +625,7 @@ class CreateUsersCommand extends Command
|
||||
}
|
||||
|
||||
// If neither map nor direct matched for ≥2
|
||||
$this->logger->error("Cannot match user '{backend}: {user}' in any map row or direct match.", [
|
||||
$this->logger->error("Direct mapping failed for '{backend}: {user}' no match found.", [
|
||||
'backend' => $userObj['backend'],
|
||||
'user' => $userObj['name']
|
||||
]);
|
||||
@@ -702,4 +656,83 @@ class CreateUsersCommand extends Command
|
||||
|
||||
return $chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run actions on the user data, early.
|
||||
*
|
||||
* @param array $user The remote user data.
|
||||
* @param string $backend The backend name.
|
||||
* @param array $mapping the mapper file data.
|
||||
*
|
||||
* @return array the modified user data if any.
|
||||
*
|
||||
* - my_plex_server:
|
||||
* name: "mike_jones"
|
||||
* options: { }
|
||||
* my_jellyfin_server:
|
||||
* name: "jones_mike"
|
||||
* options: { }
|
||||
* my_emby_server:
|
||||
* name: "mikeJones"
|
||||
* replace_with: "mike_jones"
|
||||
* options: { }
|
||||
* ```
|
||||
*/
|
||||
private function map_actions(array $user, string $backend, array $mapping): array
|
||||
{
|
||||
if (null === ($username = ag($user, 'name'))) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
$found = false;
|
||||
$user_map = [];
|
||||
|
||||
foreach ($mapping as $map) {
|
||||
$map_backend = array_keys($map)[0];
|
||||
|
||||
if ($backend !== $map_backend) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ag($map, "{$backend}.name") !== $username) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$found = true;
|
||||
$user_map = ag($map, $backend, []);
|
||||
break;
|
||||
}
|
||||
|
||||
if (false === $found) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
// -- replace_with action.
|
||||
if (null !== ($newUsername = ag($user_map, 'replace_with'))) {
|
||||
if (!is_string($newUsername) || false === isValidName($newUsername)) {
|
||||
$this->logger->error(
|
||||
message: "SYSTEM: Mapper failed to rename '{backend}: {username}' to '{backend}: {new_username}' name must be in [a-z_0-9] format.",
|
||||
context: [
|
||||
'backend' => $backend,
|
||||
'username' => $username,
|
||||
'new_username' => $newUsername
|
||||
]
|
||||
);
|
||||
return $user;
|
||||
}
|
||||
|
||||
$this->logger->notice(
|
||||
message: "SYSTEM: Mapper is renaming '{backend}: {username}' to '{backend}: {new_username}'.",
|
||||
context: [
|
||||
'backend' => $backend,
|
||||
'username' => $username,
|
||||
'new_username' => $newUsername
|
||||
]
|
||||
);
|
||||
|
||||
$user['name'] = $newUsername;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,16 +27,17 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
/**
|
||||
* ConfigFile constructor.
|
||||
*
|
||||
* @param string $file The config file.
|
||||
* @param string|resource $file The config file.
|
||||
* @param string $type The content type. Default to 'yaml'.
|
||||
* @param bool $autoSave Auto save changes. Default to 'true'.
|
||||
* @param bool $autoCreate Auto create the file if it does not exist. Default is 'false'.
|
||||
* @param bool $autoBackup Auto backup the file. Default is 'true'.
|
||||
* @param array $opts Additional options.
|
||||
*
|
||||
* @throws InvalidArgumentException If the content type is invalid.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $file,
|
||||
private readonly mixed $file,
|
||||
private readonly string $type = 'yaml',
|
||||
private readonly bool $autoSave = true,
|
||||
private readonly bool $autoCreate = false,
|
||||
@@ -50,7 +51,7 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
]));
|
||||
}
|
||||
|
||||
if (false === file_exists($this->file)) {
|
||||
if (false === is_resource($file) && false === file_exists($this->file)) {
|
||||
if (false === $this->autoCreate) {
|
||||
throw new InvalidArgumentException(r("File '{file}' does not exist.", ['file' => $file]));
|
||||
}
|
||||
@@ -62,8 +63,20 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
$this->loadData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a config file.
|
||||
*
|
||||
* @param string|resource $file The config file.
|
||||
* @param string $type The content type. Default to 'yaml'.
|
||||
* @param bool $autoSave Auto save changes. Default to 'true'.
|
||||
* @param bool $autoCreate Auto create the file if it does not exist. Default is 'false'.
|
||||
* @param bool $autoBackup Auto backup the file. Default is 'true'.
|
||||
* @param array $opts Additional options.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function open(
|
||||
string $file,
|
||||
mixed $file,
|
||||
string $type = 'yaml',
|
||||
bool $autoSave = true,
|
||||
bool $autoCreate = false,
|
||||
@@ -181,7 +194,7 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
$json_encode = $this->opts['json_encode'];
|
||||
}
|
||||
|
||||
if (true === $this->autoBackup) {
|
||||
if (true === $this->autoBackup && false === is_resource($this->file)) {
|
||||
try {
|
||||
copy($this->file, $this->file . '.bak');
|
||||
} catch (\Exception) {
|
||||
@@ -259,7 +272,7 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
$jsonOpts = $this->opts['json_decode'];
|
||||
}
|
||||
|
||||
$stream = $stream ?? new Stream($this->file, 'r');
|
||||
$stream = Stream::make($this->file, 'r');
|
||||
|
||||
if ($stream->isSeekable()) {
|
||||
$stream->seek(0);
|
||||
@@ -351,6 +364,10 @@ final class ConfigFile implements ArrayAccess, LoggerAwareInterface
|
||||
|
||||
private function getFileHash(): string
|
||||
{
|
||||
if (is_resource($this->file)) {
|
||||
return hash('sha256', (string)Stream::make($this->file, 'r'));
|
||||
}
|
||||
|
||||
return hash_file('sha256', $this->file);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user