fix(reader): the watched-channels list keeps its channels, its shares and its retries
- A channel someone follows: the videos its exploration brings in (the list's dialog, the channel page's explore) come in as the catalog's own, not flagged via_explore, which subscribing would never clear and which kept their watched marks waiting for good. - The explore cleanup keeps the row of a channel a Takeout history shows watched (it still reclaims the videos), so a looked-at channel no longer drops off the list. - The Shorts job takes up only users whose list still has lengths to ask or channels to name, by each user's own follows, blocks and dismissals; a naming that failed is tried again, and the list says it is not complete. - The length lookups have a daily share of their own: a large history no longer leaves the export's Watch later file waiting a day. - Only a channel of the user's own history can be put out of the list. - The dialog's videos have a query root of their own: the list's invalidations no longer re-ask (and re-explore) under an open dialog.
This commit is contained in:
@@ -38,7 +38,9 @@ export const qk = {
|
||||
channel: (id: string) => ["channel", id] as const,
|
||||
discoveredChannels: () => ["discovered-channels"] as const,
|
||||
watchedChannels: () => ["watched-channels"] as const,
|
||||
watchedChannelVideos: (id: string) => ["watched-channels", "videos", id] as const,
|
||||
// A root of its own, not under the list's: asking for them explores the channel (a write), so the
|
||||
// list's invalidations must not refetch them under an open dialog.
|
||||
watchedChannelVideos: (id: string) => ["watched-channel-videos", id] as const,
|
||||
blockedChannels: () => ["blocked-channels"] as const,
|
||||
|
||||
// --- playlists ---
|
||||
|
||||
@@ -47,6 +47,7 @@ vi.mock("../../features/player/PlayerModal", () => ({
|
||||
}));
|
||||
|
||||
import WatchedChannels from "./WatchedChannels";
|
||||
import { qk } from "../../lib/queryKeys";
|
||||
import { api, type Video, type WatchedChannel, type WatchedChannels as List } from "../../lib/api";
|
||||
|
||||
afterEach(() => {
|
||||
@@ -160,6 +161,20 @@ describe("WatchedChannels", () => {
|
||||
await waitFor(() => expect(h.player).toHaveBeenLastCalledWith("a", ["a", "b", "c"], 0));
|
||||
});
|
||||
|
||||
it("asks for a channel's videos once per opening, whatever the list does meanwhile", async () => {
|
||||
// The ask explores the channel and may spend quota: the list's own refetch (an Undo, a follow)
|
||||
// must not repeat it under an open dialog, nor swap the queue of a video playing.
|
||||
const videos = vi
|
||||
.spyOn(api, "watchedChannelVideos")
|
||||
.mockResolvedValue({ ok: true, items: [video("a")], gone: 0 });
|
||||
const qc = mount({ imported: true, pending: 0, channels: [channel(1)] });
|
||||
fireEvent.click(await screen.findByRole("button", { name: "29" }));
|
||||
await within(await screen.findByRole("dialog")).findByText("Video a");
|
||||
await act(() => qc.invalidateQueries({ queryKey: qk.watchedChannels() }));
|
||||
await waitFor(() => expect(api.watchedChannels).toHaveBeenCalledTimes(2));
|
||||
expect(videos).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("follows a channel from its videos after the confirm, and closes", async () => {
|
||||
vi.spyOn(api, "watchedChannelVideos").mockResolvedValue({
|
||||
ok: true,
|
||||
|
||||
Reference in New Issue
Block a user