(()=>{var e={};e.id=127,e.ids=[127],e.modules={28303:e=>{function t(e){var t=Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=28303,e.exports=t},10846:e=>{"use strict";e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},44870:e=>{"use strict";e.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},3295:e=>{"use strict";e.exports=require("next/dist/server/app-render/after-task-async-storage.external.js")},29294:e=>{"use strict";e.exports=require("next/dist/server/app-render/work-async-storage.external.js")},63033:e=>{"use strict";e.exports=require("next/dist/server/app-render/work-unit-async-storage.external.js")},12412:e=>{"use strict";e.exports=require("assert")},79428:e=>{"use strict";e.exports=require("buffer")},55511:e=>{"use strict";e.exports=require("crypto")},94735:e=>{"use strict";e.exports=require("events")},29021:e=>{"use strict";e.exports=require("fs")},81630:e=>{"use strict";e.exports=require("http")},73496:e=>{"use strict";e.exports=require("http2")},55591:e=>{"use strict";e.exports=require("https")},91645:e=>{"use strict";e.exports=require("net")},21820:e=>{"use strict";e.exports=require("os")},33873:e=>{"use strict";e.exports=require("path")},19771:e=>{"use strict";e.exports=require("process")},27910:e=>{"use strict";e.exports=require("stream")},41204:e=>{"use strict";e.exports=require("string_decoder")},66136:e=>{"use strict";e.exports=require("timers")},34631:e=>{"use strict";e.exports=require("tls")},83997:e=>{"use strict";e.exports=require("tty")},79551:e=>{"use strict";e.exports=require("url")},28354:e=>{"use strict";e.exports=require("util")},74075:e=>{"use strict";e.exports=require("zlib")},4573:e=>{"use strict";e.exports=require("node:buffer")},37739:(e,t,r)=>{"use strict";r.r(t),r.d(t,{patchFetch:()=>g,routeModule:()=>m,serverHooks:()=>R,workAsyncStorage:()=>I,workUnitAsyncStorage:()=>f});var s={};r.r(s),r.d(s,{GET:()=>A,POST:()=>_});var o=r(42706),n=r(28203),i=r(45994),a=r(39187),l=r(27914),c=r(89768),u=r(54911),d=r(79707);r(12241);let h=["US","GB","CA","AU"],E=["0","1","2","10","15","17","19","20","22","23","24","25","26","27","28","29"];async function T(e,t){let r=`${e}_${t}`;try{let s={part:"snippet,statistics,contentDetails",chart:"mostPopular",regionCode:e,maxResults:50,hl:"en"};return"0"!==t&&(s.videoCategoryId=t),((await (0,d.E)("/videos",s)).items||[]).map(s=>({title:s.snippet?.title||"",channel:s.snippet?.channelTitle||"",channelId:s.snippet?.channelId||"",views:s.statistics?.viewCount||"0",videoId:s.id,thumbnail:s.snippet?.thumbnails?.medium?.url||s.snippet?.thumbnails?.default?.url||"",durationSecs:function(e){if(!e)return 0;let t=e.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);return t?3600*parseInt(t[1]||"0")+60*parseInt(t[2]||"0")+parseInt(t[3]||"0"):0}(s.contentDetails?.duration||""),sessionId:r,source:`api_${e}_cat${t}`,categoryId:t,region:e})).filter(e=>e.title.length>5&&e.durationSecs>0&&e.durationSecs<=60)}catch(r){return console.warn(`[CrawlJob] API fetch failed for ${e}/${t}: ${r.message}`),[]}}async function p(){console.log(`[CrawlJob] Starting Shorts-only trending crawl via YouTube API…`);try{await l.A.execute("DELETE FROM algo_feed_snapshots WHERE crawled_at < NOW() - INTERVAL 12 HOUR")}catch(e){console.warn("[CrawlJob] Cleanup skipped (table may not exist yet)")}let e=[];for(let t of h)for(let r of E)e.push([t,r]);let t=[],r=new Set;for(let s=0;s<e.length;s+=12){let o=e.slice(s,s+12);for(let e of(await Promise.all(o.map(([e,t])=>T(e,t)))))for(let s of e)r.has(s.videoId)||(r.add(s.videoId),t.push(s));s+12<e.length&&await new Promise(e=>setTimeout(e,500))}if(console.log(`[CrawlJob] Fetched ${t.length} unique Shorts (≤60s) across ${e.length} region/category combos`),0===t.length)return console.error("[CrawlJob] No videos fetched — check YOUTUBE_API_KEY and quota."),{crawled:0,clusters:0};for(let e of t)try{await l.A.execute(`INSERT INTO algo_feed_snapshots (session_id, title, channel, views, video_id, thumbnail, source)
                 VALUES (?, ?, ?, ?, ?, ?, ?)`,[e.sessionId,e.title,e.channel,e.views,e.videoId,e.thumbnail,`${e.source}|ch:${e.channelId}`])}catch{}let s=(0,c.w)(t.map(e=>({title:e.title,channel:e.channel,sessionId:e.sessionId})),2);console.log(`[CrawlJob] Found ${s.length} raw clusters`);let o=new Date().toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!0}),n=s;if(s.length>0)try{let e=`You are a YouTube niche analyst. For each topic cluster below, generate a short punchy niche name (3-5 words max). Respond ONLY with a JSON array of strings in the SAME ORDER.

Clusters:
${s.map((e,t)=>`${t+1}. Keywords: [${e.keywords.slice(0,5).join(", ")}] — Samples: "${e.titles.slice(0,2).join('" / "')}"`).join("\n")}

Respond with ONLY: ["Name 1", "Name 2", ...]`,t=(await (0,u.e)(e)).match(/\[[\s\S]*\]/);if(t){let e=JSON.parse(t[0]);n=s.map((t,r)=>({...t,name:e[r]&&e[r].trim()?e[r]:`${t.keywords[0]||"Trend"} \xb7 ${o}`}))}else n=s.map(e=>({...e,name:`${e.keywords[0]||"Trend"} \xb7 ${o}`}))}catch(e){console.warn("[CrawlJob] Gemini naming failed — using timestamp fallback:",e),n=s.map(e=>({...e,name:`${e.keywords[0]||"Trend"} \xb7 ${o}`}))}let i=n.map(e=>new Set(t.filter(t=>e.titles.includes(t.title)).map(e=>e.sessionId)).size);try{await l.A.execute("DELETE FROM discovered_niches WHERE source = 'algo_feed'")}catch{}for(let e=0;e<n.length;e++){let t=n[e],r=i[e],s=t.score+15*r;try{await l.A.execute(`INSERT INTO discovered_niches (name, keywords, source, session_count, item_count, score, sample_titles, sample_channels)
                 VALUES (?, ?, 'algo_feed', ?, ?, ?, ?, ?)`,[t.name,t.keywords.join(", "),r,t.titles.length,s,t.titles.slice(0,4).join(" | "),t.channels.slice(0,4).join(", ")])}catch(e){console.warn("[CrawlJob] Insert cluster failed:",e)}try{await l.A.execute(`INSERT INTO niche_score_history (niche_name, score, session_count, item_count)
                 VALUES (?, ?, ?, ?)`,[t.name,s,r,t.titles.length])}catch(e){console.warn("[CrawlJob] Insert history failed:",e)}}try{await l.A.execute("DELETE FROM niche_score_history WHERE crawled_at < NOW() - INTERVAL 30 DAY")}catch{}return console.log(`[CrawlJob] Done. ${t.length} Shorts → ${n.length} clusters stored.`),{crawled:t.length,clusters:n.length}}async function w(){let[e]=await l.A.execute("SELECT * FROM discovered_niches WHERE source = 'algo_feed' ORDER BY score DESC LIMIT 50");return await Promise.all(e.map(async e=>{try{let[t]=await l.A.execute(`SELECT score, crawled_at FROM niche_score_history
                 WHERE niche_name = ? ORDER BY crawled_at ASC LIMIT 10`,[e.name]);return{...e,history:t.map(e=>e.score)}}catch{return{...e,history:[]}}}))}async function A(){try{let e=await w(),[t]=await l.A.execute("SELECT MAX(crawled_at) AS last FROM algo_feed_snapshots");return a.NextResponse.json({results:e,lastCrawled:t[0]?.last||null})}catch(e){return a.NextResponse.json({error:e.message},{status:500})}}async function _(){try{let e=await p(),t=await w();return a.NextResponse.json({...e,results:t})}catch(e){return console.error("[Crawl POST]",e),a.NextResponse.json({error:e.message},{status:500})}}let m=new o.AppRouteRouteModule({definition:{kind:n.RouteKind.APP_ROUTE,page:"/api/discover/crawl/route",pathname:"/api/discover/crawl",filename:"route",bundlePath:"app/api/discover/crawl/route"},resolvedPagePath:"C:\\Users\\HP\\Desktop\\youtubenichefinder\\src\\app\\api\\discover\\crawl\\route.ts",nextConfigOutput:"",userland:s}),{workAsyncStorage:I,workUnitAsyncStorage:f,serverHooks:R}=m;function g(){return(0,i.patchFetch)({workAsyncStorage:I,workUnitAsyncStorage:f})}},96487:()=>{},78335:()=>{},89768:(e,t,r)=>{"use strict";r.d(t,{w:()=>o});let s=new Set(["the","a","an","and","or","but","in","on","at","to","for","of","with","is","are","was","were","be","been","being","have","has","had","do","does","did","will","would","could","should","may","might","can","i","you","he","she","we","they","it","this","that","these","those","my","your","his","her","our","their","its","me","him","us","them","what","how","why","when","where","who","all","any","both","each","few","more","most","other","some","such","no","not","only","own","same","so","than","too","very","just","about","after","before","between","up","down","out","off","over","under","new","get","got","make","made","go","going","gone","also","from","by","into","through","during","s","t","re","m","ll","ve","d","isn","aren"]);function o(e,t=2){let r=e.map(e=>({...e,tokens:new Set(function(e){let t=e.toLowerCase().replace(/[^a-z0-9\s]/g," ").split(/\s+/).filter(e=>e.length>3&&!s.has(e)),r=[];for(let e=0;e<t.length-1;e++)r.push(`${t[e]} ${t[e+1]}`);return[...t,...r]}(e.title))})),n=r.map(e=>[...e.tokens]),i=function(e){let t=new Map,r=e.length;for(let r of e)for(let e of new Set(r))t.set(e,(t.get(e)||0)+1);let s=new Map;return t.forEach((e,t)=>{s.set(t,Math.log((r+1)/(e+1))+1)}),s}(n),a=new Map;for(let e of n)for(let t of e)a.set(t,(a.get(t)||0)+1);let l=n.length,c=[...a.entries()].filter(([,e])=>e>=t&&e<.7*l).sort((e,t)=>{let r=(i.get(e[0])||1)*e[1];return(i.get(t[0])||1)*t[1]-r}).slice(0,60).map(([e])=>e),u=new Set,d=[];for(let e of c){let s=r.map((e,t)=>({item:e,idx:t})).filter(({item:t,idx:r})=>!u.has(r)&&t.tokens.has(e));if(s.length<t)continue;let o=[];for(let e of c)s.filter(({item:t})=>t.tokens.has(e)).length>=t&&o.push(e);for(let{idx:e}of s)u.add(e);let n=new Set(s.map(e=>e.item.sessionId||"x")).size;d.push({name:o.slice(0,3).join(" \xb7 "),keywords:o.slice(0,10),titles:s.map(e=>e.item.title),channels:[...new Set(s.map(e=>e.item.channel))],score:20*n+5*s.length})}return d.sort((e,t)=>t.score-e.score).slice(0,20)}},27914:(e,t,r)=>{"use strict";r.d(t,{A:()=>s});let s=r(60820).createPool({host:process.env.DB_HOST||"localhost",user:process.env.DB_USER||"root",password:process.env.DB_PASSWORD||"",database:process.env.DB_NAME||"youtube",waitForConnections:!0,connectionLimit:10,maxIdle:10,idleTimeout:6e4,queueLimit:0,enableKeepAlive:!0,keepAliveInitialDelay:0})},12241:(e,t,r)=>{"use strict";var s=r(27914);let o=!1;(async function(){o||(o=!0,await s.A.execute(`
        CREATE TABLE IF NOT EXISTS algo_feed_snapshots (
            id          INT AUTO_INCREMENT PRIMARY KEY,
            session_id  VARCHAR(36) NOT NULL,
            title       TEXT NOT NULL,
            channel     VARCHAR(255),
            views       VARCHAR(50),
            video_id    VARCHAR(50),
            thumbnail   TEXT,
            source      VARCHAR(100) DEFAULT 'trending',
            crawled_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_session (session_id),
            INDEX idx_crawled (crawled_at)
        )
    `),await s.A.execute(`
        CREATE TABLE IF NOT EXISTS discovered_niches (
            id              INT AUTO_INCREMENT PRIMARY KEY,
            name            VARCHAR(255) NOT NULL,
            keywords        TEXT,
            source          VARCHAR(50) DEFAULT 'algo_feed',
            session_count   INT DEFAULT 1,
            item_count      INT DEFAULT 1,
            score           FLOAT DEFAULT 0,
            sample_titles   TEXT,
            sample_channels TEXT,
            last_seen       TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_source (source),
            INDEX idx_score (score DESC),
            INDEX idx_last_seen (last_seen)
        )
    `),await s.A.execute(`
        CREATE TABLE IF NOT EXISTS channel_snapshots (
            id              INT AUTO_INCREMENT PRIMARY KEY,
            channel_id      VARCHAR(100) NOT NULL,
            channel_title   VARCHAR(255),
            subscribers     BIGINT DEFAULT 0,
            total_views     BIGINT DEFAULT 0,
            video_count     INT DEFAULT 0,
            snapped_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_channel (channel_id),
            INDEX idx_snapped (snapped_at)
        )
    `),await s.A.execute(`
        CREATE TABLE IF NOT EXISTS niche_score_history (
            id            INT AUTO_INCREMENT PRIMARY KEY,
            niche_name    VARCHAR(255) NOT NULL,
            score         FLOAT NOT NULL,
            session_count INT DEFAULT 1,
            item_count    INT DEFAULT 1,
            crawled_at    TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_name (niche_name),
            INDEX idx_crawled (crawled_at)
        )
    `),await s.A.execute(`
        CREATE TABLE IF NOT EXISTS saved_niches (
            id                INT AUTO_INCREMENT PRIMARY KEY,
            keyword           VARCHAR(255) NOT NULL UNIQUE,
            white_space_score INT DEFAULT 0,
            label             VARCHAR(100) DEFAULT '',
            notes             TEXT,
            saved_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            last_checked      TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            INDEX idx_keyword (keyword),
            INDEX idx_saved (saved_at DESC)
        )
    `))})().catch(e=>console.error("[DiscoverDB] init error:",e))},54911:(e,t,r)=>{"use strict";r.d(t,{e:()=>i});var s=r(36858);let o=process.env.GEMINI_API_KEY||"",n=new s.ij(o);async function i(e){if(!o||"your_gemini_api_key_here"===o)throw Error("GEMINI_API_KEY is not configured in your .env file.");let t=function(e="gemini-2.5-flash-lite"){return n.getGenerativeModel({model:e})}();return(await t.generateContent(e)).response.text()}},79707:(e,t,r)=>{"use strict";r.d(t,{E:()=>n});var s=r(93292);let o=0;async function n(e,t){let r;let n=[process.env.YOUTUBE_API_KEY,process.env.YOUTUBE_API_KEY_2,process.env.YOUTUBE_API_KEY_3,process.env.YOUTUBE_API_KEY_4].filter(e=>"string"==typeof e&&e.trim().length>0);if(0===n.length)throw Error("No YOUTUBE_API_KEY configured in .env");for(let i=0;i<n.length;i++){let a=(o+i)%n.length,l=n[a];try{let r=await s.A.get(`https://www.googleapis.com/youtube/v3${e}`,{params:{...t,key:l}});return o=a,r.data}catch(t){let e=t?.response?.status;if(403===e||429===e){let s=(a+1)%n.length;console.warn(`[YouTube] Key ${a+1} hit ${e}. Rotating to key ${s+1} of ${n.length}.`),r=t,o=s;continue}throw t}}let i=Error(n.length>1?`All ${n.length} YouTube API keys have hit their quota limit. Add more keys or wait for reset at midnight Pacific Time.`:"YouTube API key quota exceeded. Add YOUTUBE_API_KEY_2/3/4 in .env for automatic rotation.");throw i.originalError=r,i.quotaExhausted=!0,i}}};var t=require("../../../../webpack-runtime.js");t.C(e);var r=e=>t(t.s=e),s=t.X(0,[638,452,820,292,858],()=>r(37739));module.exports=s})();