Test platform Rapido Code Pro
require(“dotenv”).config();
const express = require(“express”);
const axios = require(“axios”);
const cors = require(“cors”);
const rateLimit = require(“express-rate-limit”);
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.static(“public”));
/* ================= RATE LIMIT ================= */
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 60,
standardHeaders: true,
legacyHeaders: false,
});
app.use(“/api/”, limiter);
/* ================= UTIL ================= */
function extractChannelIdentifier(input) {
try {
const url = new URL(input);
if (url.pathname.includes(“/channel/”))
return url.pathname.split(“/channel/”)[1];
if (url.pathname.includes(“/@”))
return url.pathname.split(“/@”)[1];
} catch {}
return input;
}
/* ================= MAIN AUDIT ENDPOINT ================= */
app.post(“/api/audit”, async (req, res) => {
try {
const rawInput = req.body.channel;
if (!rawInput) {
return res.status(400).json({ error: “Channel input required.” });
}
const identifier = extractChannelIdentifier(rawInput);
/* STEP 1: SEARCH CHANNEL */
const search = await axios.get(
“https://www.googleapis.com/youtube/v3/search”,
{
params: {
key: process.env.YOUTUBE_API_KEY,
q: identifier,
part: “snippet”,
type: “channel”,
maxResults: 1
}
}
);
if (!search.data.items.length)
return res.status(404).json({ error: “Channel not found.” });
const channelId = search.data.items[0].snippet.channelId;
/* STEP 2: GET CHANNEL STATS */
const channelRes = await axios.get(
“https://www.googleapis.com/youtube/v3/channels”,
{
params: {
key: process.env.YOUTUBE_API_KEY,
id: channelId,
part: “snippet,statistics”
}
}
);
const channel = channelRes.data.items[0];
/* STEP 3: GET RECENT VIDEOS */
const videosRes = await axios.get(
“https://www.googleapis.com/youtube/v3/search”,
{
params: {
key: process.env.YOUTUBE_API_KEY,
channelId,
part: “snippet”,
order: “date”,
maxResults: 10
}
}
);
const videos = videosRes.data.items;
/* ================= ANALYSIS ================= */
const subs = parseInt(channel.statistics.subscriberCount);
const views = parseInt(channel.statistics.viewCount);
const videosCount = parseInt(channel.statistics.videoCount);
const avgViews = Math.floor(views / videosCount);
const titleLengths = videos.map(v => v.snippet.title.length);
const avgTitleLength = Math.floor(
titleLengths.reduce((a,b)=>a+b,0) / titleLengths.length
);
const uploadConsistency = videos.length >= 8
? “high consistency”
: “low upload frequency”;
const growthScore = Math.min(100,
Math.floor((avgViews / subs) * 100)
);
/* ================= LONG PERSONALIZED REPORT ================= */
const report = `
CHANNEL AUDIT FOR: ${channel.snippet.title}
PARAGRAPH 1 — POSITIONING
With ${subs.toLocaleString()} subscribers and ${videosCount} videos, your channel is positioned at a ${growthScore > 30 ? “growth-ready” : “early-stage”} phase. Your branding must clearly state a transformation outcome in the banner and description.
PARAGRAPH 2 — CONTENT STRATEGY
Your average title length is ${avgTitleLength} characters. Strong growth channels stay between 45–60 characters with high emotional curiosity triggers. Build 3 repeating content pillars and dominate them.
PARAGRAPH 3 — RETENTION STRATEGY
Your average view ratio suggests a ${growthScore > 30 ? “strong audience alignment” : “weak retention leverage”} phase. Open every video with a result preview within 5 seconds and eliminate slow intros immediately.
PARAGRAPH 4 — THUMBNAIL & CTR
Simplify thumbnails to one focal point and 2–3 words max. Increase contrast and facial emotion. Current scale suggests CTR could increase 2–4% with redesign alone.
PARAGRAPH 5 — MONETIZATION & SCALE
Based on current velocity, introduce backend digital products or memberships. Build email capture immediately to create owned audience leverage.
KEY METRICS:
Subscribers: ${subs.toLocaleString()}
Total Views: ${views.toLocaleString()}
Total Videos: ${videosCount}
Estimated Avg Views/Video: ${avgViews.toLocaleString()}
Upload Pattern: ${uploadConsistency}
Growth Score: ${growthScore}/100
`;
res.json({ report });
} catch (err) {
if (err.response?.status === 403) {
return res.status(429).json({ error: “API quota exceeded.” });
}
res.status(500).json({ error: “Server error.” });
}
});
/* ================= START ================= */
app.listen(process.env.PORT || 5000, () =>
console.log(“Server running…”)
);
