fix(people): refresh stale person metadata on view
This commit is contained in:
@@ -39,6 +39,8 @@ var personRefreshRate = ratelimit.Rate{
|
||||
Burst: 10,
|
||||
}
|
||||
|
||||
const personMetadataStaleAfter = 90 * 24 * time.Hour
|
||||
|
||||
// PeopleHandler serves person-related API endpoints.
|
||||
type PeopleHandler struct {
|
||||
personRepo peopleRepository
|
||||
@@ -131,6 +133,8 @@ func (h *PeopleHandler) HandleGetPerson(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
h.enqueuePersonRefreshIfDue(*person)
|
||||
|
||||
writeJSON(w, http.StatusOK, h.toResponse(r.Context(), *person))
|
||||
}
|
||||
|
||||
@@ -359,6 +363,29 @@ func (h *PeopleHandler) toResponse(ctx context.Context, p models.Person) personR
|
||||
return resp
|
||||
}
|
||||
|
||||
func (h *PeopleHandler) enqueuePersonRefreshIfDue(person models.Person) {
|
||||
if h.refreshQueue == nil || !personHasRefreshableProviderID(person) {
|
||||
return
|
||||
}
|
||||
|
||||
if personMetadataIncomplete(person) {
|
||||
h.refreshQueue.Enqueue(person.ID)
|
||||
return
|
||||
}
|
||||
|
||||
if person.UpdatedAt.Before(time.Now().Add(-personMetadataStaleAfter)) {
|
||||
h.refreshQueue.Enqueue(person.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func personHasRefreshableProviderID(person models.Person) bool {
|
||||
return person.TmdbID != "" || person.ImdbID != "" || person.TvdbID != ""
|
||||
}
|
||||
|
||||
func personMetadataIncomplete(person models.Person) bool {
|
||||
return person.Bio == "" || person.PhotoPath == "" || person.PhotoPath == "-" || person.BirthDate == nil
|
||||
}
|
||||
|
||||
func parseOptionalPersonDate(raw string) (*time.Time, error) {
|
||||
if raw == "" {
|
||||
return nil, nil
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { Pencil, RefreshCw } from "lucide-react";
|
||||
|
||||
import { getPerson } from "@/api/client";
|
||||
import { createEmptyQueryDefinition } from "@/api/types";
|
||||
import { createEmptyQueryDefinition, type Person } from "@/api/types";
|
||||
import type { CatalogSearchState } from "@/pages/catalogSearchParams";
|
||||
import EditPersonDialog from "@/components/EditPersonDialog";
|
||||
import ItemGrid from "@/components/ItemGrid";
|
||||
@@ -25,6 +25,7 @@ export default function PersonDetail() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [typeFilter, setTypeFilter] = useState<TypeFilter>("all");
|
||||
const [editOpen, setEditOpen] = useState(false);
|
||||
const autoRefreshWindowRef = useRef<{ personId: number; until: number } | null>(null);
|
||||
const { user } = useAuth();
|
||||
const isAdmin = user?.role === "admin";
|
||||
const refreshMutation = useRefreshPerson(id, isAdmin);
|
||||
@@ -33,6 +34,21 @@ export default function PersonDetail() {
|
||||
queryKey: personKeys.detail(id!),
|
||||
queryFn: () => getPerson(id!),
|
||||
enabled: !!id,
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
if (!data || !isPersonMetadataIncomplete(data)) {
|
||||
autoRefreshWindowRef.current = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
const current = autoRefreshWindowRef.current;
|
||||
if (!current || current.personId !== data.id) {
|
||||
autoRefreshWindowRef.current = { personId: data.id, until: Date.now() + 30_000 };
|
||||
return 3_000;
|
||||
}
|
||||
|
||||
return Date.now() < current.until ? 3_000 : false;
|
||||
},
|
||||
});
|
||||
|
||||
useDocumentTitle(person?.name ?? "Person");
|
||||
@@ -212,6 +228,10 @@ export default function PersonDetail() {
|
||||
);
|
||||
}
|
||||
|
||||
function isPersonMetadataIncomplete(person: Person) {
|
||||
return !person.bio || !person.photo_url || !person.birth_date;
|
||||
}
|
||||
|
||||
function PersonDetailSkeleton() {
|
||||
return (
|
||||
<div className="page-shell pt-8 sm:pt-10">
|
||||
|
||||
Reference in New Issue
Block a user