Docs/Skills and code/Top-level code
test-channel-response.js
import { Innertube } from "youtubei.js";
import { inspect } from "node:util";
// ============================================================
// HARDCODED TEST TARGET
// ============================================================
const CHANNEL_URL = "https://www.youtube.com/@DoctorWho";
// ============================================================
// LOGGING HELPERS
// ============================================================
const inspected = new WeakSet();
function section(title) {
console.log("\n" + "=".repeat(80));
console.log(title);
console.log("=".repeat(80));
}
function log(label, value, options = {}) {
console.log(`\n--- ${label} ---`);
console.log(
inspect(value, {
depth: options.depth ?? 5,
colors: false,
compact: false,
maxArrayLength: options.maxArrayLength ?? 100,
maxStringLength: options.maxStringLength ?? 5000,
breakLength: 120,
})
);
}
function safeKeys(value) {
if (value == null) return [];
try {
return Reflect.ownKeys(value).map(String);
} catch (error) {
return [`<keys failed: ${error.message}>`];
}
}
function prototypeChain(value) {
const result = [];
let current = value;
let level = 0;
while (current && level < 8) {
result.push({
level,
constructor: current?.constructor?.name ?? "unknown",
keys: safeKeys(current),
});
current = Object.getPrototypeOf(current);
level++;
}
return result;
}
function describeObject(value, label) {
if (value == null) {
console.log(`\n[describe] ${label}: null/undefined`);
return;
}
console.log(`\n[describe] ${label}`);
console.log("constructor:", value?.constructor?.name);
console.log("type:", value?.type);
console.log("own keys:", safeKeys(value));
console.log("prototype chain:", prototypeChain(value));
}
// ============================================================
// RECURSIVE SEARCH
// ============================================================
const interestingKeyPattern =
/subscriber|subscribers|video.?count|keyword|title|description|metadata|header|content|author|channel/i;
function findInterestingPaths(
value,
path = "$",
depth = 0,
maxDepth = 8,
results = []
) {
if (value == null || depth > maxDepth) {
return results;
}
const valueType = typeof value;
if (valueType !== "object" && valueType !== "function") {
return results;
}
if (inspected.has(value)) {
return results;
}
inspected.add(value);
let keys;
try {
keys = Reflect.ownKeys(value);
} catch {
return results;
}
for (const rawKey of keys) {
const key = String(rawKey);
const childPath = `${path}.${key}`;
if (interestingKeyPattern.test(key)) {
let child;
try {
child = value[rawKey];
} catch (error) {
child = `<getter threw: ${error.message}>`;
}
results.push({
path: childPath,
type: typeof child,
constructor: child?.constructor?.name ?? null,
value: child,
});
}
let child;
try {
child = value[rawKey];
} catch {
continue;
}
findInterestingPaths(
child,
childPath,
depth + 1,
maxDepth,
results
);
}
return results;
}
function printInterestingPaths(value) {
section("RECURSIVE SEARCH: INTERESTING FIELDS");
const results = findInterestingPaths(value);
console.log(`Found ${results.length} interesting field paths.`);
for (const [index, result] of results.entries()) {
console.log(`\n[${index + 1}] ${result.path}`);
console.log("type:", result.type);
console.log("constructor:", result.constructor);
console.log(
"value:",
inspect(result.value, {
depth: 3,
colors: false,
compact: false,
maxArrayLength: 20,
maxStringLength: 1000,
breakLength: 120,
})
);
}
}
// ============================================================
// MAIN TEST
// ============================================================
async function main() {
section("CHANNEL RESPONSE MICROSCOPE");
console.log("Hardcoded channel:", CHANNEL_URL);
console.log("youtubei.js package will be queried directly.");
console.log("NO application extractor is being used.");
// ----------------------------------------------------------
// 1. CREATE CLIENT
// ----------------------------------------------------------
section("1. CREATE YOUTUBE CLIENT");
const youtube = await Innertube.create();
console.log("Client created.");
console.log("Client constructor:", youtube?.constructor?.name);
console.log("Client own keys:", safeKeys(youtube));
// ----------------------------------------------------------
// 2. RESOLVE CHANNEL
// ----------------------------------------------------------
section("2. RESOLVE CHANNEL URL");
console.log("Calling youtube.resolveURL()...");
const endpoint = await youtube.resolveURL(CHANNEL_URL);
console.log("resolveURL() succeeded.");
describeObject(endpoint, "Resolved endpoint");
log("Resolved endpoint", endpoint, {
depth: 8,
});
const channelId =
endpoint?.payload?.browseId ??
endpoint?.payload?.browse_id ??
null;
console.log("\nExtracted channel ID:", channelId);
if (!channelId) {
throw new Error(
"Could not extract channel ID from resolveURL response."
);
}
// ----------------------------------------------------------
// 3. GET CHANNEL
// ----------------------------------------------------------
section("3. GET CHANNEL");
console.log(`Calling youtube.getChannel(${channelId})...`);
const channel = await youtube.getChannel(channelId);
console.log("getChannel() succeeded.");
// ----------------------------------------------------------
// 4. CHANNEL OBJECT
// ----------------------------------------------------------
section("4. CHANNEL OBJECT SHAPE");
describeObject(channel, "Channel");
log("Channel object — depth 4", channel, {
depth: 4,
maxArrayLength: 50,
maxStringLength: 3000,
});
// ----------------------------------------------------------
// 5. PROTOTYPE
// ----------------------------------------------------------
section("5. PROTOTYPE CHAIN");
log(
"Channel prototype chain",
prototypeChain(channel),
{
depth: 6,
maxArrayLength: 50,
}
);
// ----------------------------------------------------------
// 6. HEADER
// ----------------------------------------------------------
section("6. HEADER");
console.log(
"channel.header exists:",
Boolean(channel?.header)
);
if (channel?.header) {
describeObject(channel.header, "channel.header");
log("channel.header", channel.header, {
depth: 8,
maxArrayLength: 50,
maxStringLength: 5000,
});
}
// ----------------------------------------------------------
// 7. HEADER CONTENT
// ----------------------------------------------------------
section("7. HEADER.CONTENT");
const headerContent = channel?.header?.content;
console.log(
"channel.header.content exists:",
Boolean(headerContent)
);
if (headerContent) {
describeObject(
headerContent,
"channel.header.content"
);
log(
"channel.header.content",
headerContent,
{
depth: 8,
maxArrayLength: 50,
maxStringLength: 5000,
}
);
}
// ----------------------------------------------------------
// 8. KNOWN CANDIDATE PATHS
// ----------------------------------------------------------
section("8. KNOWN CANDIDATE PATHS");
const candidates = {
"channel.metadata": channel?.metadata,
"channel.metadata.title": channel?.metadata?.title,
"channel.metadata.external_id":
channel?.metadata?.external_id,
"channel.author": channel?.author,
"channel.subscriber_count":
channel?.subscriber_count,
"channel.video_count":
channel?.video_count,
"channel.keywords":
channel?.keywords,
"channel.header.content.title":
channel?.header?.content?.title,
"channel.header.content.description":
channel?.header?.content?.description,
"channel.header.content.metadata":
channel?.header?.content?.metadata,
"channel.header.content.actions":
channel?.header?.content?.actions,
"channel.header.content.attributation":
channel?.header?.content?.attributation,
};
for (const [path, value] of Object.entries(candidates)) {
console.log(`\n${path}`);
console.log(
inspect(value, {
depth: 8,
colors: false,
compact: false,
maxArrayLength: 50,
maxStringLength: 5000,
breakLength: 120,
})
);
}
// ----------------------------------------------------------
// 9. RECURSIVE SEARCH
// ----------------------------------------------------------
printInterestingPaths(channel);
// ----------------------------------------------------------
// 10. PROPERTY ACCESS TEST
// ----------------------------------------------------------
section("10. GETTERS / PROPERTY ACCESS TEST");
const propertiesToTest = [
"subscriber_count",
"video_count",
"keywords",
"author",
"metadata",
"header",
"thumbnails",
"is_verified",
"verified",
"is_artist",
];
for (const property of propertiesToTest) {
try {
const value = channel?.[property];
console.log(`\nchannel.${property}`);
console.log(
"value:",
inspect(value, {
depth: 6,
colors: false,
compact: false,
maxArrayLength: 30,
maxStringLength: 3000,
})
);
console.log("typeof:", typeof value);
console.log(
"constructor:",
value?.constructor?.name ?? null
);
} catch (error) {
console.log(`\nchannel.${property}`);
console.log("ACCESS THREW:", error.message);
}
}
// ----------------------------------------------------------
// 11. FINAL SUMMARY
// ----------------------------------------------------------
section("11. FINAL RAW SUMMARY");
console.log({
channel_url: CHANNEL_URL,
channel_id: channelId,
constructor: channel?.constructor?.name,
own_keys: safeKeys(channel),
header_keys: safeKeys(channel?.header),
header_content_keys: safeKeys(
channel?.header?.content
),
metadata_keys: safeKeys(channel?.metadata),
});
console.log("\nDONE.");
console.log(
"Do not modify the production extractor yet."
);
console.log(
"Use this output to determine the actual response shape first."
);
}
main().catch((error) => {
console.error(
"\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
);
console.error("TEST FAILED");
console.error(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
);
console.error(error);
process.exitCode = 1;
});
Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.