fix(jellyfin): fix discovery loop, device identity, tray state, and Disc

- Derive device identity from OS hostname; remove legacy configurable client/device fields
- Prevent discovery playback from reloading active item, misreporting pause state, and duplicate overlay restores
- Restart stale tray discovery sessions without re-login when server drops SubMiner cast target
- Sync tray discovery checkbox state on Linux after CLI/startup/remote-session changes
- Stop Discord presence falling back to stream URLs; prime title before tokenized stream loads
- Fix picker library discovery when log level is above info
- Fix config.example.jsonc trailing commas and array formatting
This commit is contained in:
2026-05-22 01:36:11 -07:00
parent 85d838ac96
commit 2f2dfa3e91
72 changed files with 2063 additions and 589 deletions
@@ -194,6 +194,124 @@ test('stops active discovery from tray', async () => {
]);
});
test('uses checked tray state to start discovery instead of blind toggling', async () => {
const calls: string[] = [];
let session: { advertiseNow: () => Promise<boolean> } | null = null;
await toggleJellyfinDiscoveryFromTray(
{
getRemoteSession: () => session,
stopRemoteSession: () => calls.push('stop'),
startRemoteSession: async (options) => {
assert.deepEqual(options, { explicit: true });
calls.push('start');
session = {
advertiseNow: async () => {
calls.push('advertise');
return true;
},
};
},
refreshTrayMenu: () => calls.push('refresh'),
logger: {
info: (message) => calls.push(`info:${message}`),
warn: (message) => calls.push(`warn:${message}`),
error: (message) => calls.push(`error:${message}`),
},
showMpvOsd: (message) => calls.push(`osd:${message}`),
},
{ desiredActive: true },
);
assert.deepEqual(calls, [
'start',
'advertise',
'info:Jellyfin discovery started; cast target is visible in server sessions.',
'osd:Jellyfin discovery started',
'refresh',
]);
});
test('uses unchecked tray state to stop discovery without visibility probing', async () => {
const calls: string[] = [];
await toggleJellyfinDiscoveryFromTray(
{
getRemoteSession: () => ({
advertiseNow: async () => {
calls.push('advertise');
return true;
},
}),
stopRemoteSession: () => calls.push('stop'),
startRemoteSession: async () => {
calls.push('start');
},
refreshTrayMenu: () => calls.push('refresh'),
logger: {
info: (message) => calls.push(`info:${message}`),
warn: (message) => calls.push(`warn:${message}`),
error: (message) => calls.push(`error:${message}`),
},
showMpvOsd: (message) => calls.push(`osd:${message}`),
},
{ desiredActive: false },
);
assert.deepEqual(calls, [
'stop',
'info:Jellyfin discovery stopped.',
'osd:Jellyfin discovery stopped',
'refresh',
]);
});
test('restarts active discovery when current session is not visible', async () => {
const calls: string[] = [];
let session: { advertiseNow: () => Promise<boolean> } | null = {
advertiseNow: async () => {
calls.push('advertise-stale');
return false;
},
};
await toggleJellyfinDiscoveryFromTray({
getRemoteSession: () => session,
stopRemoteSession: () => {
calls.push('stop');
session = null;
},
startRemoteSession: async (options) => {
assert.deepEqual(options, { explicit: true });
calls.push('start');
session = {
advertiseNow: async () => {
calls.push('advertise-fresh');
return true;
},
};
},
refreshTrayMenu: () => calls.push('refresh'),
logger: {
info: (message) => calls.push(`info:${message}`),
warn: (message) => calls.push(`warn:${message}`),
error: (message) => calls.push(`error:${message}`),
},
showMpvOsd: (message) => calls.push(`osd:${message}`),
});
assert.deepEqual(calls, [
'advertise-stale',
'warn:Jellyfin discovery was active but not visible; restarting.',
'stop',
'start',
'advertise-fresh',
'info:Jellyfin discovery started; cast target is visible in server sessions.',
'osd:Jellyfin discovery started',
'refresh',
]);
});
test('warns and refreshes tray when explicit discovery cannot create a session', async () => {
const calls: string[] = [];