11export const fetchCache = "force-no-store" ;
22
3+
34import { publicURL , youtubeParser } from "@/lib/utils" ;
45import { createClient } from "next-sanity" ;
56import type { NextRequest } from "next/server" ;
@@ -13,96 +14,91 @@ const sanityWriteClient = createClient({
1314 useCdn : false ,
1415} ) ;
1516
17+
1618export async function POST ( request : NextRequest ) {
1719 const authHeader = request . headers . get ( "authorization" ) ;
1820 if ( authHeader !== `Bearer ${ process . env . CRON_SECRET } ` ) {
19- return new Response ( "Unauthorized" , {
20- status : 401 ,
21- } ) ;
21+ console . error ( "[YOUTUBE] Unauthorized request: invalid authorization header" ) ;
22+ return new Response ( "Unauthorized" , { status : 401 } ) ;
2223 }
2324
24- const searchParams = request . nextUrl . searchParams ;
25- const lastIdParam = searchParams . get ( "lastId" ) ;
26-
2725 try {
28- // Assume if lastId is missing that the request will be the initial starting the process.
29- const sanityRead = await sanityWriteClient . fetch (
30- `*[youtube != null && _id > $lastId]| order(_id)[0]{
31- _id,
32- youtube
33- }` ,
34- {
35- lastId : lastIdParam || "" ,
36- } ,
26+ // Fetch up to 10 pending/inProgress youtubeUpdateTask docs
27+ const tasks = await sanityWriteClient . fetch (
28+ `*[_type == "youtubeUpdateTask" && (status == "pending" || status == "inProgress")]| order(lastChecked asc nulls first)[0...10]{ _id, targetDoc->{_id, _type, youtube}, status }`
3729 ) ;
3830
39- const lastId = sanityRead ?. _id ;
40-
41- if ( ! lastId ) {
42- const message = `No doc found based on lastId ${ lastId } ` ;
31+ if ( ! tasks || tasks . length === 0 ) {
32+ const message = `[YOUTUBE] No youtubeUpdateTask docs to process` ;
4333 console . log ( message ) ;
4434 return Response . json ( { success : true , message } , { status : 200 } ) ;
4535 }
4636
47- // These should never match, if they do bail.
48- if ( lastId === lastIdParam ) {
49- console . error ( "lastId matches current doc, stopping calls." ) ;
50- return new Response ( "lastId matches current doc, stopping calls." , {
51- status : 200 ,
52- } ) ;
53- }
37+ let updatedCount = 0 ;
38+ for ( const task of tasks ) {
39+ const { _id : taskId , targetDoc, status } = task ;
40+ if ( ! targetDoc || ! targetDoc . youtube ) {
41+ await sanityWriteClient . patch ( taskId )
42+ . set ( { status : "error" , errorMessage : "Missing YouTube field on targetDoc" , lastChecked : new Date ( ) . toISOString ( ) } )
43+ . commit ( ) ;
44+ continue ;
45+ }
46+ // Mark as inProgress
47+ await sanityWriteClient . patch ( taskId )
48+ . set ( { status : "inProgress" , lastChecked : new Date ( ) . toISOString ( ) } )
49+ . commit ( ) ;
5450
55- const id = youtubeParser ( sanityRead ?. youtube ) ;
51+ const id = youtubeParser ( targetDoc . youtube ) ;
52+ if ( ! id ) {
53+ await sanityWriteClient . patch ( taskId )
54+ . set ( { status : "error" , errorMessage : "Invalid YouTube URL" , lastChecked : new Date ( ) . toISOString ( ) } )
55+ . commit ( ) ;
56+ continue ;
57+ }
5658
57- if ( ! id ) {
58- console . error ( "Missing YouTube Id" ) ;
59- return new Response ( "Missing YouTube Id" , { status : 404 } ) ;
60- }
59+ try {
60+ const videoResp = await fetch (
61+ `https://www.googleapis.com/youtube/v3/videos?id=${ id } &key=${ process . env . YOUTUBE_API_KEY } &fields=items(id,statistics)&part=statistics` ,
62+ ) ;
63+ const json = await videoResp . json ( ) ;
64+ if ( videoResp . status !== 200 ) {
65+ await sanityWriteClient . patch ( taskId )
66+ . set ( { status : "error" , errorMessage : JSON . stringify ( json ) , lastChecked : new Date ( ) . toISOString ( ) } )
67+ . commit ( ) ;
68+ continue ;
69+ }
70+ const statistics = json ?. items ?. at ( 0 ) ?. statistics ;
71+ if ( ! statistics ) {
72+ await sanityWriteClient . patch ( taskId )
73+ . set ( { status : "error" , errorMessage : "No statistics found" , lastChecked : new Date ( ) . toISOString ( ) } )
74+ . commit ( ) ;
75+ continue ;
76+ }
6177
62- const videoResp = await fetch (
63- `https://www.googleapis.com/youtube/v3/videos?id=${ id } &key=${ process . env . YOUTUBE_API_KEY } &fields=items(id,statistics)&part=statistics` ,
64- ) ;
65- const json = await videoResp . json ( ) ;
66- if ( videoResp . status !== 200 ) {
67- console . error ( JSON . stringify ( json ) ) ;
68- return Response . json ( json , { status : videoResp . status } ) ;
69- }
70- console . log ( JSON . stringify ( json ) ) ;
71- const statistics = json ?. items ?. at ( 0 ) ?. statistics ;
78+ // Update target doc with stats
79+ await sanityWriteClient . patch ( targetDoc . _id )
80+ . set ( {
81+ "statistics.youtube.commentCount" : Number . parseInt ( statistics . commentCount ) ,
82+ "statistics.youtube.favoriteCount" : Number . parseInt ( statistics . favoriteCount ) ,
83+ "statistics.youtube.likeCount" : Number . parseInt ( statistics . likeCount ) ,
84+ "statistics.youtube.viewCount" : Number . parseInt ( statistics . viewCount ) ,
85+ } )
86+ . commit ( ) ;
7287
73- if ( ! statistics ) {
74- const words = `No statistics found for YouTube Id ${ id } ` ;
75- console . error ( words ) ;
76- return new Response ( words , { status : 404 } ) ;
88+ // Mark task as completed
89+ await sanityWriteClient . patch ( taskId )
90+ . set ( { status : "completed" , lastChecked : new Date ( ) . toISOString ( ) , errorMessage : undefined } )
91+ . commit ( ) ;
92+ updatedCount ++ ;
93+ } catch ( err ) {
94+ await sanityWriteClient . patch ( taskId )
95+ . set ( { status : "error" , errorMessage : String ( err ) , lastChecked : new Date ( ) . toISOString ( ) } )
96+ . commit ( ) ;
97+ }
7798 }
78-
79- // Update current doc with stats
80- const sanityUpdate = await sanityWriteClient
81- . patch ( lastId )
82- . set ( {
83- "statistics.youtube.commentCount" : Number . parseInt (
84- statistics . commentCount ,
85- ) ,
86- "statistics.youtube.favoriteCount" : Number . parseInt (
87- statistics . favoriteCount ,
88- ) ,
89- "statistics.youtube.likeCount" : Number . parseInt ( statistics . likeCount ) ,
90- "statistics.youtube.viewCount" : Number . parseInt ( statistics . viewCount ) ,
91- } )
92- . commit ( ) ;
93-
94- // Trigger next call, don't wait for response
95- fetch ( publicURL ( ) + `/api/youtube/views?lastId=${ lastId } ` , {
96- method : "POST" ,
97- headers : {
98- authorization : `Bearer ${ process . env . CRON_SECRET } ` ,
99- "Cache-Control" : "no-cache" ,
100- } ,
101- } ) ;
102-
103- return Response . json ( sanityUpdate ) ;
99+ return Response . json ( { success : true , updatedCount } ) ;
104100 } catch ( error ) {
105- console . error ( JSON . stringify ( error ) ) ;
106- return Response . json ( { success : false } , { status : 404 } ) ;
101+ console . error ( "[YOUTUBE] Unexpected error:" , error ) ;
102+ return Response . json ( { success : false , error : String ( error ) } , { status : 500 } ) ;
107103 }
108104}
0 commit comments