ombi: adopt the Plex entry that plex itself answers for
ace's ombi holds one Plex entry, loaded from an older server and later retyped to plex's public name: its stored machineIdentifier is not plex's, while its address answers as plex. Matching by identifier alone would leave it and add a second entry for the same server. When no entry carries the server's identifier, each entry's own address is asked for /identity, and an entry plex answers for is adopted: the bound connection laid over, and the identifier corrected (ombi builds its "view in Plex" links from it). Its name, libraries and every other choice stay. An entry that cannot be asked, or answers as another server, is left alone; nothing is guessed. Every call of the step is now bounded, since an entry may name a host that no longer answers.
This commit is contained in:
@@ -45,6 +45,13 @@ function fakes(plexSettings: Record<string, unknown>, opts: { reachable?: boolea
|
||||
text: async () => (value === undefined ? "" : JSON.stringify(value)),
|
||||
});
|
||||
const u = new URL(url);
|
||||
// Other servers an entry may name: a friend's, and plex's own public name (the same server).
|
||||
if (u.hostname === "10.0.0.9") return reply(200, { MediaContainer: { machineIdentifier: "another-server" } });
|
||||
if (u.hostname === "gone.example") throw new Error("getaddrinfo ENOTFOUND");
|
||||
if (u.hostname === "plex.zurag.be") {
|
||||
if (u.pathname === "/identity") return reply(200, { MediaContainer: { machineIdentifier: MACHINE } });
|
||||
return reply(401);
|
||||
}
|
||||
if (u.port === "32400" || u.hostname === "ace.internal") {
|
||||
if (opts.reachable === false) throw new Error("connect ECONNREFUSED");
|
||||
if (u.pathname === "/identity") return reply(200, { MediaContainer: { machineIdentifier: MACHINE } });
|
||||
@@ -171,3 +178,46 @@ test("every entry naming the server is laid over, not only the first", () => {
|
||||
assert.equal(laid.added, false);
|
||||
assert.deepEqual((laid.next.servers as { ip: string }[]).map((s) => s.ip), ["ace.internal", "ace.internal"]);
|
||||
});
|
||||
|
||||
// ace's own ombi: its one entry was loaded from an older server (a stale identifier) and retyped to
|
||||
// plex's public name, so it IS this server, reached another way (read from ace, 2026-09-30).
|
||||
const acesOmbi = () => ({
|
||||
enable: true,
|
||||
enableWatchlistImport: true,
|
||||
servers: [{
|
||||
name: "Nami", plexAuthToken: TOKEN, machineIdentifier: "76562198623e708eef85b46aedb72c8f2fe671aa", episodeBatchSize: 0,
|
||||
plexSelectedLibraries: [1, 2, 3, 4, 5, 6].map((k) => ({ key: String(k), enabled: true })), ssl: true, subDir: null,
|
||||
ip: "plex.zurag.be", port: 443, id: 1,
|
||||
}],
|
||||
id: 4,
|
||||
});
|
||||
|
||||
test("an entry whose own address answers as this server is adopted: connection and identifier, nothing else", async () => {
|
||||
const f = fakes(acesOmbi());
|
||||
const out = await reconcilePlex(f.http, OMBI, binding(), TOKEN);
|
||||
assert.deepEqual(out, { app: "plex", result: "written", fields: ["ip", "port", "ssl", "machineIdentifier"] });
|
||||
const want = acesOmbi();
|
||||
Object.assign(want.servers[0], { ip: "ace.internal", port: 32400, ssl: false, machineIdentifier: MACHINE });
|
||||
assert.deepEqual(f.store.plex, want, "one entry, still named Nami, its six libraries kept; none added");
|
||||
});
|
||||
|
||||
test("an entry answering as another server, or not at all, is not adopted; this server gets its own", async () => {
|
||||
const doc = {
|
||||
servers: [
|
||||
{ name: "a friend", machineIdentifier: "stale-1", ip: "10.0.0.9", port: 32400, ssl: false, plexAuthToken: "theirs" },
|
||||
{ name: "gone", machineIdentifier: "stale-2", ip: "gone.example", port: 32400, ssl: false, plexAuthToken: "old" },
|
||||
],
|
||||
};
|
||||
const f = fakes(structuredClone(doc));
|
||||
const out = await reconcilePlex(f.http, OMBI, binding(), TOKEN);
|
||||
assert.deepEqual(out, { app: "plex", result: "written", fields: ["server"] });
|
||||
const servers = f.store.plex.servers as Record<string, unknown>[];
|
||||
assert.deepEqual(servers.slice(0, 2), doc.servers, "both left exactly as they were");
|
||||
assert.equal(servers[2].machineIdentifier, MACHINE);
|
||||
});
|
||||
|
||||
test("no entry is probed once one carries the server's identifier", async () => {
|
||||
const f = fakes(operatorPlex());
|
||||
await reconcilePlex(f.http, OMBI, binding(), TOKEN);
|
||||
assert.equal(f.calls.some((c) => c.url.startsWith("http://10.0.0.9")), false, "the friend's server was not asked");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user