Skip to content

Commit 1b3189a

Browse files
committed
change to use multpile ids
1 parent c308423 commit 1b3189a

1 file changed

Lines changed: 65 additions & 62 deletions

File tree

app/api/youtube/views/route.tsx

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,72 +16,93 @@ const sanityWriteClient = createClient({
1616

1717

1818

19-
async function processSingleTask() {
19+
20+
async function processBatchTasks() {
21+
// Fetch up to 50 pending tasks
2022
let tasks = await sanityWriteClient.fetch(
21-
`*[_type == "youtubeUpdateTask" && (status == "pending" || status == "inProgress")]| order(lastChecked asc)[0...1]{ _id, targetDoc->{_id, _type, youtube}, status }`
23+
`*[_type == "youtubeUpdateTask" && status == "pending"]| order(lastChecked asc)[0...50]{ _id, targetDoc->{_id, _type, youtube}, status }`
2224
);
23-
if (!tasks || tasks.length === 0) return false;
24-
const task = tasks[0];
25-
const { _id: taskId, targetDoc, status } = task;
26-
if (!targetDoc || !targetDoc.youtube) {
27-
await sanityWriteClient.patch(taskId)
28-
.set({ status: "error", errorMessage: "Missing YouTube field on targetDoc", lastChecked: new Date().toISOString() })
25+
if (!tasks || tasks.length === 0) return { processed: 0 };
26+
27+
// Prepare video IDs and map taskId to docId
28+
const validTasks = [];
29+
const errorTasks = [];
30+
for (const task of tasks) {
31+
const { _id: taskId, targetDoc } = task;
32+
if (!targetDoc || !targetDoc.youtube) {
33+
errorTasks.push({ taskId, error: "Missing YouTube field on targetDoc" });
34+
continue;
35+
}
36+
const id = youtubeParser(targetDoc.youtube);
37+
if (!id) {
38+
errorTasks.push({ taskId, error: "Invalid YouTube URL" });
39+
continue;
40+
}
41+
validTasks.push({ taskId, docId: targetDoc._id, youtubeId: id });
42+
}
43+
44+
// Mark all valid tasks as inProgress
45+
for (const t of validTasks) {
46+
await sanityWriteClient.patch(t.taskId)
47+
.set({ status: "inProgress", lastChecked: new Date().toISOString() })
2948
.commit();
30-
return false;
3149
}
32-
// Mark as inProgress
33-
await sanityWriteClient.patch(taskId)
34-
.set({ status: "inProgress", lastChecked: new Date().toISOString() })
35-
.commit();
36-
37-
const id = youtubeParser(targetDoc.youtube);
38-
if (!id) {
39-
await sanityWriteClient.patch(taskId)
40-
.set({ status: "error", errorMessage: "Invalid YouTube URL", lastChecked: new Date().toISOString() })
50+
51+
// Mark all error tasks as error
52+
for (const t of errorTasks) {
53+
await sanityWriteClient.patch(t.taskId)
54+
.set({ status: "error", errorMessage: t.error, lastChecked: new Date().toISOString() })
4155
.commit();
42-
return false;
4356
}
4457

45-
try {
46-
const videoResp = await fetch(
47-
`https://www.googleapis.com/youtube/v3/videos?id=${id}&key=${process.env.YOUTUBE_API_KEY}&fields=items(id,statistics)&part=statistics`,
48-
);
49-
const json = await videoResp.json();
50-
if (videoResp.status !== 200) {
51-
await sanityWriteClient.patch(taskId)
58+
if (validTasks.length === 0) return { processed: 0, errors: errorTasks.length };
59+
60+
// Batch YouTube API call
61+
const ids = validTasks.map(t => t.youtubeId).join(",");
62+
console.log("[YOUTUBE] Fetching stats for IDs:", ids);
63+
const videoResp = await fetch(
64+
`https://www.googleapis.com/youtube/v3/videos?id=${ids}&key=${process.env.YOUTUBE_API_KEY}&fields=items(id,statistics)&part=statistics`,
65+
);
66+
const json = await videoResp.json();
67+
if (videoResp.status !== 200) {
68+
// Mark all as error
69+
for (const t of validTasks) {
70+
await sanityWriteClient.patch(t.taskId)
5271
.set({ status: "error", errorMessage: JSON.stringify(json), lastChecked: new Date().toISOString() })
5372
.commit();
54-
return false;
5573
}
56-
const statistics = json?.items?.at(0)?.statistics;
74+
return { processed: 0, errors: validTasks.length };
75+
}
76+
const statsMap = new Map();
77+
for (const item of json?.items || []) {
78+
statsMap.set(item.id, item.statistics);
79+
}
80+
81+
let completed = 0;
82+
for (const t of validTasks) {
83+
const statistics = statsMap.get(t.youtubeId);
5784
if (!statistics) {
58-
await sanityWriteClient.patch(taskId)
85+
await sanityWriteClient.patch(t.taskId)
5986
.set({ status: "error", errorMessage: "No statistics found", lastChecked: new Date().toISOString() })
6087
.commit();
61-
return false;
88+
continue;
6289
}
63-
6490
// Update target doc with stats
65-
await sanityWriteClient.patch(targetDoc._id)
91+
await sanityWriteClient.patch(t.docId)
6692
.set({
6793
"statistics.youtube.commentCount": Number.parseInt(statistics.commentCount),
6894
"statistics.youtube.favoriteCount": Number.parseInt(statistics.favoriteCount),
6995
"statistics.youtube.likeCount": Number.parseInt(statistics.likeCount),
7096
"statistics.youtube.viewCount": Number.parseInt(statistics.viewCount),
7197
})
7298
.commit();
73-
7499
// Mark task as completed
75-
await sanityWriteClient.patch(taskId)
100+
await sanityWriteClient.patch(t.taskId)
76101
.set({ status: "completed", lastChecked: new Date().toISOString(), errorMessage: undefined })
77102
.commit();
78-
return true;
79-
} catch (err) {
80-
await sanityWriteClient.patch(taskId)
81-
.set({ status: "error", errorMessage: String(err), lastChecked: new Date().toISOString() })
82-
.commit();
83-
return false;
103+
completed++;
84104
}
105+
return { processed: completed, errors: errorTasks.length + (validTasks.length - completed) };
85106
}
86107

87108
export async function POST(request: NextRequest) {
@@ -94,7 +115,7 @@ export async function POST(request: NextRequest) {
94115
try {
95116
// Repopulate youtubeUpdateTask queue if empty
96117
let tasks = await sanityWriteClient.fetch(
97-
`*[_type == "youtubeUpdateTask" && (status == "pending" || status == "inProgress")]| order(lastChecked asc)[0...1]{ _id, targetDoc->{_id, _type, youtube}, status }`
118+
`*[_type == "youtubeUpdateTask" && status == "pending"]| order(lastChecked asc)[0...1]{ _id }`
98119
);
99120
if (!tasks || tasks.length === 0) {
100121
const posts = await sanityWriteClient.fetch(
@@ -120,27 +141,9 @@ export async function POST(request: NextRequest) {
120141
}
121142
}
122143

123-
// Process a single task
124-
const didProcess = await processSingleTask();
125-
126-
// Wait in a while loop until 30 seconds have passed
127-
const startTime = Date.now();
128-
const maxDuration = 30 * 1000; // 30 seconds
129-
while (Date.now() - startTime < maxDuration) {
130-
// Busy-wait (not recommended for production, but per user request)
131-
console.log('waiting...');
132-
}
133-
134-
// Trigger the next batch by calling this API again
135-
fetch(`${publicURL()}/api/youtube/views`, {
136-
method: "POST",
137-
headers: {
138-
authorization: `Bearer ${process.env.CRON_SECRET}`,
139-
"Cache-Control": "no-cache",
140-
},
141-
});
142-
143-
return Response.json({ success: true, didProcess });
144+
// Process a batch of tasks
145+
const result = await processBatchTasks();
146+
return Response.json({ success: true, ...result });
144147
} catch (error) {
145148
console.error("[YOUTUBE] Unexpected error:", error);
146149
return Response.json({ success: false, error: String(error) }, { status: 500 });

0 commit comments

Comments
 (0)