feat(m5d): demand-driven deep backfill + per-user ETA
Per-user opt-in to full-history (deep) backfill so a new user's unique channels no longer trigger a big shared-quota burst. - migration 0007: Subscription.deep_requested (default false); seed admins' existing subscriptions to preserve today's global-backfill behaviour - run_deep_backfill is now demand-driven: only channels at least one user has requested are deep-backfilled; recent backfill stays unconditional (cheap) - estimate_deep_backfill ETA helper (quota-bound) surfaced in /api/sync/my-status - POST /api/sync/deep-all to opt all my channels in; PATCH channels accepts deep_requested - UI: per-channel Full history toggle, Backfill everything action, deep progress + ETA in Channels header and Settings - Sync
This commit is contained in:
parent
ba2abf5019
commit
6eb78b9475
9 changed files with 256 additions and 18 deletions
|
|
@ -1,8 +1,9 @@
|
|||
import { useCallback, useEffect, useState, useSyncExternalStore } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Bell, Monitor, Pause, Play, RefreshCw, User, X } from "lucide-react";
|
||||
import { Bell, History, Monitor, Pause, Play, RefreshCw, User, X } from "lucide-react";
|
||||
import { SCHEMES, type Scheme, type ThemePrefs } from "../lib/theme";
|
||||
import { api, type Me } from "../lib/api";
|
||||
import { formatEta } from "../lib/format";
|
||||
import {
|
||||
configureNotifications,
|
||||
getNotifSettings,
|
||||
|
|
@ -335,6 +336,18 @@ function Sync({ me }: { me: Me }) {
|
|||
mutationFn: (paused: boolean) => (paused ? api.resumeSync() : api.pauseSync()),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["my-status"] }),
|
||||
});
|
||||
const deepAll = useMutation({
|
||||
mutationFn: () => api.deepAll(true),
|
||||
onSuccess: (r: { updated?: number }) => {
|
||||
qc.invalidateQueries({ queryKey: ["my-status"] });
|
||||
qc.invalidateQueries({ queryKey: ["channels"] });
|
||||
notify({
|
||||
level: "success",
|
||||
message: `Full history requested for ${r.updated ?? 0} channels`,
|
||||
});
|
||||
},
|
||||
onError: () => notify({ level: "error", message: "Couldn't request full history" }),
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -352,10 +365,18 @@ function Sync({ me }: { me: Me }) {
|
|||
</Row>
|
||||
<Row
|
||||
label="Full history"
|
||||
hint="Channels whose entire back-catalog has been fetched. The rest backfill gradually (opt in per channel)."
|
||||
hint="Channels whose entire back-catalog has been fetched, out of the ones you've requested full history for (opt in per channel on the Channels page)."
|
||||
>
|
||||
{`${s.channels_deep_done}/${s.channels_total}`}
|
||||
{`${s.channels_deep_done}/${s.channels_deep_requested}`}
|
||||
</Row>
|
||||
{s.deep_pending_count > 0 && (
|
||||
<Row
|
||||
label="Full history ETA"
|
||||
hint={`Rough estimate to finish full-history backfill of ${s.deep_pending_count} pending channel(s), based on the shared daily quota.`}
|
||||
>
|
||||
{formatEta(s.deep_eta_seconds)}
|
||||
</Row>
|
||||
)}
|
||||
<Row label="My videos" hint="Total videos available to you across your subscribed channels.">
|
||||
{s.my_videos.toLocaleString()}
|
||||
</Row>
|
||||
|
|
@ -382,6 +403,16 @@ function Sync({ me }: { me: Me }) {
|
|||
Sync subscriptions
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip hint="Request full back-catalog backfill for every channel you're subscribed to. Older videos + complete search fill in as the shared daily quota allows.">
|
||||
<button
|
||||
onClick={() => deepAll.mutate()}
|
||||
disabled={deepAll.isPending}
|
||||
className="glass-card glass-hover flex items-center gap-2 px-3 py-2 rounded-xl text-sm disabled:opacity-50 transition mt-2"
|
||||
>
|
||||
<History className={`w-4 h-4 ${deepAll.isPending ? "animate-pulse" : ""}`} />
|
||||
Backfill everything
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Section>
|
||||
|
||||
{me.role === "admin" && s && (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue