Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/centralize-duplicate-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/library-membership-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ent-mcp/server": minor
---

Added a media library that tracks the titles you own and keeps the set in sync with your collection providers.
5 changes: 5 additions & 0 deletions .changeset/library-real-data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ent-mcp/client": minor
---

The library page now browses your real owned collection across all five lenses with infinite scroll, quality chips, and faceted filters.
5 changes: 5 additions & 0 deletions .changeset/plugin-sdk-collection-membership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ent-mcp/plugin-sdk": minor
---

Metadata items can now carry collection membership.
5 changes: 5 additions & 0 deletions .changeset/tmdb-collection-membership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ent-mcp/plugin-tmdb": minor
---

TMDB now reports a movie's franchise so it can be grouped with the rest of its collection.
22 changes: 0 additions & 22 deletions .fallow/dupes-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
"clone_groups": [
"apps/client/src/features/admin-plugins/shared/fetchers.ts:27-39|apps/client/src/features/admin-plugins/shared/fetchers.ts:51-63",
"apps/client/src/features/admin-plugins/shared/fetchers.ts:32-49|apps/client/src/features/notifications/shared/fetchers.ts:49-61",
"apps/client/src/features/admin-plugins/shared/use-plugin-mutation.ts:34-38|apps/client/src/features/admin-users/hooks/use-delete-user.ts:16-20",
"apps/client/src/features/admin-roles/lib/permission-tree.ts:19-48|apps/client/src/features/admin-roles/lib/permission-tree.ts:68-97",
"apps/client/src/features/admin-roles/lib/permission-tree.ts:24-50|apps/client/src/features/admin-roles/lib/permission-tree.ts:78-104",
"apps/client/src/features/admin-users/hooks/use-assign-role.ts:23-30|apps/client/src/features/admin-users/hooks/use-delete-user.ts:16-20",
"apps/client/src/features/admin-users/hooks/use-assign-role.ts:24-32|apps/client/src/features/admin-users/hooks/use-delete-user.ts:17-20|apps/client/src/features/settings-notifications/lib/optimistic-channels.ts:14-17",
"apps/client/src/features/admin-users/hooks/use-assign-role.ts:30-41|apps/client/src/features/admin-users/hooks/use-delete-user.ts:20-28",
"apps/client/src/features/admin-users/hooks/use-delete-user.ts:9-19|apps/client/src/features/settings-notifications/hooks/use-toggle-subscription.ts:13-27",
"apps/client/src/features/admin-users/lib/fetchers.ts:23-27|apps/client/src/features/notifications/shared/fetchers.ts:74-78",
"apps/client/src/features/admin-users/lib/types.ts:29-39|apps/client/src/features/notifications/shared/types.ts:38-48",
Expand Down Expand Up @@ -46,10 +42,7 @@
"apps/server/src/catalog/service/index.ts:371-398|apps/server/src/catalog/service/index.ts:399-425",
"apps/server/src/connections/auth.ts:172-177|apps/server/src/media/service/id-resolver.ts:116-121",
"apps/server/src/connections/auth.ts:232-236|apps/server/src/notifications/repo/inbox.ts:188-192",
"apps/server/src/connections/auth.ts:302-307|apps/server/src/connections/auth.ts:375-380",
"apps/server/src/connections/auth.ts:424-433|apps/server/src/connections/auth.ts:486-499",
"apps/server/src/connections/helpers.ts:23-29|apps/server/src/connections/helpers.ts:344-350",
"apps/server/src/connections/helpers.ts:42-50|apps/server/src/crypto/helpers.ts:15-23",
"apps/server/src/connections/primary-service.ts:59-68|apps/server/src/plugin-runtime/internal/admin-policy.ts:89-98",
"apps/server/src/connections/service.ts:181-190|apps/server/src/plugin-runtime/service/runtime.ts:187-192",
"apps/server/src/connections/service.ts:246-254|apps/server/src/connections/service.ts:296-299",
Expand All @@ -58,7 +51,6 @@
"apps/server/src/connections/service.ts:395-402|apps/server/src/jobs/plugin-jobs.ts:216-223",
"apps/server/src/connections/service.ts:459-465|apps/server/src/plugin-runtime/internal/host-bridge.ts:88-94",
"apps/server/src/crypto/helpers.ts:20-26|apps/server/src/crypto/helpers.ts:27-34",
"apps/server/src/diagnostics/capture.ts:100-105|apps/server/src/diagnostics/capture.ts:85-90",
"apps/server/src/diagnostics/database-sink.ts:15-25|apps/server/src/diagnostics/database-sink.ts:35-45",
"apps/server/src/diagnostics/database-sink.ts:35-45|apps/server/src/notifications/repo/inbox.ts:36-46",
"apps/server/src/diagnostics/http-errors.ts:37-46|apps/server/src/diagnostics/http-errors.ts:71-80",
Expand All @@ -73,11 +65,8 @@
"apps/server/src/jobs/history.ts:127-131|apps/server/src/plugin-runtime/internal/connections-access.ts:70-74",
"apps/server/src/jobs/history.ts:218-232|apps/server/src/notifications/repo/deliveries.ts:275-291",
"apps/server/src/jobs/history.ts:223-235|apps/server/src/notifications/repo/deliveries.ts:279-291",
"apps/server/src/jobs/plugin-jobs.ts:243-255|apps/server/src/plugin-runtime/internal/user-pool.ts:83-92",
"apps/server/src/jobs/runtime-events.ts:32-40|packages/shared/src/connections/schemas.ts:32-41",
"apps/server/src/jobs/scheduled-per-row.ts:49-68|apps/server/src/jobs/scheduled.ts:26-50",
"apps/server/src/mcp/composite-tools/ent-activity.ts:55-61|apps/server/src/mcp/composite-tools/ent-discover.ts:61-67",
"apps/server/src/mcp/composite-tools/ent-activity.ts:73-87|apps/server/src/mcp/composite-tools/ent-discover.ts:85-100",
"apps/server/src/mcp/composite-tools/ent-activity.ts:106-120|apps/server/src/mcp/composite-tools/ent-activity.ts:85-97",
"apps/server/src/mcp/composite-tools/ent-activity.ts:103-112|apps/server/src/mcp/composite-tools/ent-activity.ts:126-143|apps/server/src/mcp/composite-tools/ent-activity.ts:147-167",
"apps/server/src/mcp/composite-tools/ent-activity.ts:122-126|apps/server/src/mcp/composite-tools/ent-activity.ts:174-179",
Expand All @@ -92,38 +81,27 @@
"apps/server/src/mcp/registry.ts:105-119|apps/server/src/plugin-runtime/internal/registry.ts:54-68",
"apps/server/src/mcp/response-shapes.ts:20-24|packages/shared/src/home/schemas.ts:83-87",
"apps/server/src/mcp/response-shapes.ts:21-25|packages/plugin-sdk/src/capabilities/metadata.ts:26-30",
"apps/server/src/media/classify.ts:57-63|apps/server/src/media/enrich.ts:519-527",
"apps/server/src/media/index.ts:1-43|apps/server/src/plugin-runtime/index.ts:1-43",
"apps/server/src/media/index.ts:19-65|apps/server/src/plugin-runtime/index.ts:2-48",
"apps/server/src/media/index.ts:37-71|packages/shared/src/notifications/index.ts:5-39",
"apps/server/src/media/internal/strategies/aggregate.ts:27-33|apps/server/src/media/internal/strategies/primary-with-enrichment.ts:125-131",
"apps/server/src/media/repo/reads.ts:68-78|apps/server/src/media/repo/writes.ts:34-44|apps/server/src/media/repo/writes.ts:89-99",
"apps/server/src/media/repo/reads.ts:83-88|apps/server/src/media/repo/reads.ts:94-102",
"apps/server/src/media/repo/reads.ts:99-103|apps/server/src/plugin-runtime/internal/connections-access.ts:71-75",
"apps/server/src/media/repo/reads.ts:107-112|apps/server/src/plugin-runtime/internal/connections-access.ts:69-74",
"apps/server/src/media/repo/reads.ts:107-111|apps/server/src/media/repo/seed.ts:24-28",
"apps/server/src/media/repo/writes.ts:26-47|apps/server/src/media/repo/writes.ts:82-102",
"apps/server/src/media/service/connection-targeted.ts:35-40|apps/server/src/plugin-runtime/internal/shared-credentials.ts:74-81",
"apps/server/src/media/service/connection-targeted.ts:58-68|apps/server/src/media/service/id-resolver.ts:114-121",
"apps/server/src/media/service/id-resolver.ts:116-128|apps/server/src/preferences/repo/storage.ts:33-39",
"apps/server/src/media/service/index.ts:113-130|apps/server/src/media/service/index.ts:463-479",
"apps/server/src/media/service/index.ts:652-670|apps/server/src/media/service/index.ts:745-773",
"apps/server/src/media/service/index.ts:842-860|apps/server/src/media/service/index.ts:911-929",
"apps/server/src/notifications/errors.ts:2-17|apps/server/src/watchlist/errors.ts:2-13",
"apps/server/src/notifications/internal/deliver-handler.ts:67-72|apps/server/src/notifications/jobs/delivery.ts:80-85",
"apps/server/src/notifications/internal/deliver-handler.ts:67-73|apps/server/src/notifications/internal/deliver-handler.ts:85-92",
"apps/server/src/notifications/internal/deliver-handler.ts:84-91|apps/server/src/notifications/jobs/delivery.ts:96-105",
"apps/server/src/notifications/jobs/delivery.ts:80-86|apps/server/src/notifications/jobs/delivery.ts:96-106",
"apps/server/src/notifications/jobs/on-jobs-sync-succeeded.ts:10-19|apps/server/src/notifications/jobs/on-media-connection-auth-expired.ts:11-18",
"apps/server/src/notifications/repo/deliveries.ts:83-89|apps/server/src/notifications/repo/inbox.ts:54-59",
"apps/server/src/notifications/repo/deliveries.ts:142-160|apps/server/src/notifications/repo/deliveries.ts:99-111",
"apps/server/src/notifications/repo/deliveries.ts:275-287|apps/server/src/notifications/repo/inbox.ts:213-224",
"apps/server/src/notifications/repo/inbox.ts:149-154|apps/server/src/notifications/repo/inbox.ts:160-165",
"apps/server/src/notifications/repo/inbox.ts:154-160|apps/server/src/notifications/repo/inbox.ts:165-174",
"apps/server/src/notifications/repo/inbox.ts:154-160|apps/server/src/notifications/repo/inbox.ts:165-174|apps/server/src/notifications/repo/inbox.ts:190-198",
"apps/server/src/notifications/repo/inbox.ts:155-165|apps/server/src/notifications/repo/inbox.ts:181-191",
"apps/server/src/notifications/repo/subscriptions.ts:13-19|apps/server/src/notifications/repo/subscriptions.ts:56-66",
"apps/server/src/plugin-runtime/internal/shared-credentials.ts:53-57|apps/server/src/plugin-runtime/service/runtime.ts:190-194",
"apps/server/src/plugin-runtime/internal/shared-credentials.ts:62-68|apps/server/src/plugin-runtime/service/runtime.ts:168-170|apps/server/src/plugin-runtime/service/runtime.ts:190-192",
"apps/server/src/plugin-runtime/service/runtime.ts:429-458|apps/server/src/plugin-runtime/service/runtime.ts:505-526",
"apps/server/src/preferences/internal/catalog-provider.ts:70-77|apps/server/src/preferences/internal/catalog-provider.ts:81-88",
Expand Down
66 changes: 65 additions & 1 deletion .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@
"name": "server-mod-home-internal",
"patterns": ["apps/server/src/home/**"]
},
{
"name": "server-mod-library",
"patterns": ["apps/server/src/library/index.ts"]
},
{
"name": "server-mod-library-internal",
"patterns": ["apps/server/src/library/**"]
},
{
"name": "server-mod-media",
"patterns": ["apps/server/src/media/index.ts"]
Expand Down Expand Up @@ -313,6 +321,10 @@
"name": "server-schema-home",
"patterns": ["apps/server/src/db/schema/home/**"]
},
{
"name": "server-schema-library",
"patterns": ["apps/server/src/db/schema/library/**"]
},
{
"name": "server-schema-media",
"patterns": ["apps/server/src/db/schema/media/**"]
Expand Down Expand Up @@ -466,7 +478,14 @@
},
{
"from": "client-feat-library",
"allow": ["client-shared-ui", "client-shared-components", "client-shared-lib", "shared-pkg"]
"allow": [
"client-shared-ui",
"client-shared-components",
"client-shared-virtualized",
"client-shared-lib",
"client-shared-media",
"shared-pkg"
]
},
{
"from": "client-feat-auth",
Expand Down Expand Up @@ -725,6 +744,7 @@
"server-mod-auth",
"server-mod-catalog",
"server-mod-home",
"server-mod-library",
"server-mod-media",
"server-mod-notifications",
"server-mod-preferences",
Expand All @@ -744,6 +764,7 @@
"server-mod-auth",
"server-mod-catalog",
"server-mod-home",
"server-mod-library",
"server-mod-media",
"server-mod-notifications",
"server-mod-preferences",
Expand All @@ -770,6 +791,7 @@
"server-mod-auth",
"server-mod-catalog",
"server-mod-home",
"server-mod-library",
"server-mod-media",
"server-mod-notifications",
"server-mod-preferences",
Expand Down Expand Up @@ -925,6 +947,42 @@
"plugin-sdk"
]
},
{
"from": "server-mod-library",
"allow": [
"server-mod-library-internal",
"server-mod-artwork",
"server-mod-auth",
"server-mod-catalog",
"server-mod-home",
"server-mod-media",
"server-mod-notifications",
"server-mod-preferences",
"server-mod-plugin-runtime",
"server-infra",
"shared-pkg",
"plugin-sdk"
]
},
{
"from": "server-mod-library-internal",
"allow": [
"server-mod-library",
"server-mod-artwork",
"server-mod-auth",
"server-mod-catalog",
"server-mod-home",
"server-mod-media",
"server-mod-notifications",
"server-mod-preferences",
"server-mod-plugin-runtime",
"server-infra",
"server-schema-library",
"server-schema-infra",
"shared-pkg",
"plugin-sdk"
]
},
{
"from": "server-mod-watchlist",
"allow": [
Expand Down Expand Up @@ -1114,6 +1172,7 @@
"server-schema-auth",
"server-schema-catalog",
"server-schema-home",
"server-schema-library",
"server-schema-notifications",
"server-schema-plugin-runtime",
"server-schema-preferences",
Expand All @@ -1135,6 +1194,10 @@
"from": "server-schema-home",
"allow": ["server-schema-auth", "shared-pkg"]
},
{
"from": "server-schema-library",
"allow": ["server-schema-auth", "shared-pkg"]
},
{
"from": "server-schema-notifications",
"allow": ["server-schema-auth", "server-schema-plugin-runtime", "shared-pkg"]
Expand All @@ -1157,6 +1220,7 @@
"server-schema-auth",
"server-schema-catalog",
"server-schema-home",
"server-schema-library",
"server-schema-notifications",
"server-schema-plugin-runtime",
"server-schema-preferences",
Expand Down
8 changes: 5 additions & 3 deletions apps/client/messages/library/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@
],
"library_section_count": "{count} titles",
"library_timeline_unknown": "Unknown year",
"library_row_prev": "Previous {decade}",
"library_row_next": "Next {decade}",
"library_az_rail_label": "Jump to letter",
"library_az_jump": "Jump to {letter}",
"library_decade_rail_label": "Jump to decade",
"library_decade_jump": "Jump to {decade}",
"library_empty_title": "Nothing matches",
"library_empty_description": "Try clearing a filter to see more titles.",
"library_empty_reset": "Reset filters",
"library_card_open": "Open details for {title}",
"library_card_progress": "{percent}% watched",
"library_load_error_title": "Library couldn't load",
"library_load_error_retry": "Retry"
"library_load_error_retry": "Retry",
"library_load_more": "Load more",
"library_loading_more": "Loading…"
}
8 changes: 5 additions & 3 deletions apps/client/messages/library/fa.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@
],
"library_section_count": "{count} عنوان",
"library_timeline_unknown": "سال نامشخص",
"library_row_prev": "{decade} قبلی",
"library_row_next": "{decade} بعدی",
"library_az_rail_label": "پرش به حرف",
"library_az_jump": "پرش به {letter}",
"library_decade_rail_label": "پرش به دهه",
"library_decade_jump": "پرش به {decade}",
"library_empty_title": "چیزی یافت نشد",
"library_empty_description": "برای دیدن عنوان‌های بیشتر یک فیلتر را حذف کنید.",
"library_empty_reset": "بازنشانی فیلترها",
"library_card_open": "نمایش جزئیات {title}",
"library_card_progress": "{percent}٪ تماشا شده",
"library_load_error_title": "کتابخانه بارگذاری نشد",
"library_load_error_retry": "تلاش مجدد"
"library_load_error_retry": "تلاش مجدد",
"library_load_more": "بارگذاری بیشتر",
"library_loading_more": "در حال بارگذاری…"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";

import { rollbackQuery, snapshotQuery } from "@/shared/lib/query/optimistic";
import { adminPluginsKeys } from "./query-keys";
import type { PluginRow } from "./types";

Expand Down Expand Up @@ -32,15 +33,15 @@ export function useOptimisticPluginMutation<TInput extends { pluginId: string },
return useMutation({
mutationFn,
onMutate: async (input) => {
await qc.cancelQueries({ queryKey: adminPluginsKeys.list() });
const snapshot = qc.getQueryData<PluginRow[]>(adminPluginsKeys.list());
qc.setQueryData<PluginRow[] | undefined>(adminPluginsKeys.list(), (rows) =>
rows?.map((p) => (p.id === input.pluginId ? patch(p, input) : p)),
const { prev: snapshot } = await snapshotQuery<PluginRow[]>(
qc,
adminPluginsKeys.list(),
(rows) => rows?.map((p) => (p.id === input.pluginId ? patch(p, input) : p)),
);
return { snapshot };
},
onError: (_err, _input, ctx) => {
if (ctx?.snapshot) qc.setQueryData(adminPluginsKeys.list(), ctx.snapshot);
if (ctx?.snapshot) rollbackQuery(qc, adminPluginsKeys.list(), ctx.snapshot);
toast.error(errorMsg);
},
onSuccess: successMsg
Expand Down
13 changes: 5 additions & 8 deletions apps/client/src/features/admin-users/hooks/use-assign-role.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { m } from "@/paraglide/messages";
import { rollbackQuery, snapshotQuery } from "@/shared/lib/query/optimistic";
import { fetchAssignRole } from "../lib/fetchers";
import { adminUsersKeys } from "../lib/query-keys";
import type { AdminUserSummary } from "../lib/types";
Expand All @@ -20,22 +21,18 @@ export function useAssignRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, roleId }: Vars) => fetchAssignRole(userId, roleId),
onMutate: async ({ userId, roleId, roleName }) => {
await qc.cancelQueries({ queryKey: adminUsersKeys.list() });
const prev = qc.getQueryData<ListSnapshot>(adminUsersKeys.list());
qc.setQueryData<ListSnapshot>(adminUsersKeys.list(), (data) =>
onMutate: ({ userId, roleId, roleName }) =>
snapshotQuery<ListSnapshot>(qc, adminUsersKeys.list(), (data) =>
data
? {
users: data.users.map((u) =>
u.id === userId ? { ...u, role: { id: roleId, name: roleName } } : u,
),
}
: data,
);
return { prev };
},
),
onError: (err, _vars, ctx) => {
if (ctx?.prev) qc.setQueryData(adminUsersKeys.list(), ctx.prev);
if (ctx?.prev) rollbackQuery(qc, adminUsersKeys.list(), ctx.prev);
toast.error(err instanceof AdminUsersApiError ? err.message : String(err));
},
onSuccess: (_data, { roleName }) => {
Expand Down
13 changes: 5 additions & 8 deletions apps/client/src/features/admin-users/hooks/use-delete-user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { m } from "@/paraglide/messages";
import { rollbackQuery, snapshotQuery } from "@/shared/lib/query/optimistic";
import { fetchDeleteUser } from "../lib/fetchers";
import { adminUsersKeys } from "../lib/query-keys";
import { AdminUsersApiError, type AdminUserSummary } from "../lib/types";
Expand All @@ -13,16 +14,12 @@ export function useDeleteUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: (userId: string) => fetchDeleteUser(userId),
onMutate: async (userId) => {
await qc.cancelQueries({ queryKey: adminUsersKeys.list() });
const prev = qc.getQueryData<ListSnapshot>(adminUsersKeys.list());
qc.setQueryData<ListSnapshot>(adminUsersKeys.list(), (data) =>
onMutate: (userId) =>
snapshotQuery<ListSnapshot>(qc, adminUsersKeys.list(), (data) =>
data ? { users: data.users.filter((u) => u.id !== userId) } : data,
);
return { prev };
},
),
onError: (err, _vars, ctx) => {
if (ctx?.prev) qc.setQueryData(adminUsersKeys.list(), ctx.prev);
if (ctx?.prev) rollbackQuery(qc, adminUsersKeys.list(), ctx.prev);
toast.error(err instanceof AdminUsersApiError ? err.message : String(err));
},
onSuccess: () => toast.success(m.admin_users_detail_delete_toast()),
Expand Down
Loading
Loading