feat: add jellyfin integration (#672)
* feat: #655 implement jellyfin media server * fix: table overflow * feat: pr feedback * refactor: format * refactor: merge existing code * fix: code smells * refactor: format commit
This commit is contained in:
@@ -2,6 +2,7 @@ import { analyticsJob } from "./jobs/analytics";
|
||||
import { iconsUpdaterJob } from "./jobs/icons-updater";
|
||||
import { smartHomeEntityStateJob } from "./jobs/integrations/home-assistant";
|
||||
import { mediaOrganizerJob } from "./jobs/integrations/media-organizer";
|
||||
import { mediaServerJob } from "./jobs/integrations/media-server";
|
||||
import { pingJob } from "./jobs/ping";
|
||||
import { createCronJobGroup } from "./lib";
|
||||
|
||||
@@ -10,6 +11,7 @@ export const jobGroup = createCronJobGroup({
|
||||
iconsUpdater: iconsUpdaterJob,
|
||||
ping: pingJob,
|
||||
smartHomeEntityState: smartHomeEntityStateJob,
|
||||
mediaServer: mediaServerJob,
|
||||
mediaOrganizer: mediaOrganizerJob,
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { db, eq } from "@homarr/db";
|
||||
import { items } from "@homarr/db/schema/sqlite";
|
||||
import { SonarrIntegration } from "@homarr/integrations";
|
||||
import type { CalendarEvent } from "@homarr/integrations/types";
|
||||
import { createItemWithIntegrationChannel } from "@homarr/redis";
|
||||
import { createItemAndIntegrationChannel } from "@homarr/redis";
|
||||
|
||||
// This import is done that way to avoid circular dependencies.
|
||||
import type { WidgetComponentProps } from "../../../../widgets";
|
||||
@@ -50,7 +50,7 @@ export const mediaOrganizerJob = createCronJob("mediaOrganizer", EVERY_MINUTE).w
|
||||
});
|
||||
const events = await sonarr.getCalendarEventsAsync(start, end);
|
||||
|
||||
const cache = createItemWithIntegrationChannel<CalendarEvent[]>(itemForIntegration.id, integration.integrationId);
|
||||
const cache = createItemAndIntegrationChannel<CalendarEvent[]>("calendar", integration.integrationId);
|
||||
await cache.setAsync(events);
|
||||
}
|
||||
}
|
||||
|
||||
45
packages/cron-jobs/src/jobs/integrations/media-server.ts
Normal file
45
packages/cron-jobs/src/jobs/integrations/media-server.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { decryptSecret } from "@homarr/common";
|
||||
import { EVERY_5_SECONDS } from "@homarr/cron-jobs-core/expressions";
|
||||
import { db, eq } from "@homarr/db";
|
||||
import { items } from "@homarr/db/schema/sqlite";
|
||||
import { JellyfinIntegration } from "@homarr/integrations";
|
||||
import { createItemAndIntegrationChannel } from "@homarr/redis";
|
||||
|
||||
import { createCronJob } from "../../lib";
|
||||
|
||||
export const mediaServerJob = createCronJob("mediaServer", EVERY_5_SECONDS).withCallback(async () => {
|
||||
const itemsForIntegration = await db.query.items.findMany({
|
||||
where: eq(items.kind, "mediaServer"),
|
||||
with: {
|
||||
integrations: {
|
||||
with: {
|
||||
integration: {
|
||||
with: {
|
||||
secrets: {
|
||||
columns: {
|
||||
kind: true,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const itemForIntegration of itemsForIntegration) {
|
||||
for (const integration of itemForIntegration.integrations) {
|
||||
const jellyfinIntegration = new JellyfinIntegration({
|
||||
...integration.integration,
|
||||
decryptedSecrets: integration.integration.secrets.map((secret) => ({
|
||||
...secret,
|
||||
value: decryptSecret(secret.value),
|
||||
})),
|
||||
});
|
||||
const streamSessions = await jellyfinIntegration.getCurrentSessionsAsync();
|
||||
const channel = createItemAndIntegrationChannel("mediaServer", integration.integrationId);
|
||||
await channel.publishAndUpdateLastStateAsync(streamSessions);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user