- tests: server/tests/api_coverage2.test.mjs (23 cas offline-safe) : oauth (status/url/connections/preview), channels (validations), subscriptions batch + groupes CRUD, transcripts history, likes/history DELETE, playlists public/view/reorder, telemetry summary, downloads 401/403/400, ai 503, twitch-token, config.js, rumble 400 - mcp v1.1.0 : 4 outils authentifies (list_playlists/likes/ subscriptions/watch_history, NEWTUBE_TOKEN) + tests stub - openapi.json v1.1 : 15 chemins documentes (sante, recherche, details, trending, transcript, auth, prefs, likes, subs, downloads, oauth, playlists) ; guide maj (11 outils)
This commit is contained in:
+74
-1
@@ -27,7 +27,7 @@
|
||||
const API_BASE = (process.env.NEWTUBE_API_URL || 'http://localhost:4000/api').replace(/\/+$/, '');
|
||||
const TOKEN = (process.env.NEWTUBE_TOKEN || '').trim();
|
||||
const TIMEOUT_MS = Number(process.env.MCP_TOOL_TIMEOUT_MS || 60000);
|
||||
const SERVER_VERSION = '1.0.0';
|
||||
const SERVER_VERSION = '1.1.0';
|
||||
|
||||
const PROVIDERS = ['yt', 'dm', 'tw', 'pt', 'od', 'ru'];
|
||||
const TRANSCRIPT_PROVIDERS = ['youtube', 'yt', 'dailymotion', 'dm', 'peertube', 'pt', 'twitch', 'tw', 'odysee', 'od', 'rumble', 'ru'];
|
||||
@@ -187,8 +187,48 @@ const TOOLS = [
|
||||
description: "Santé API : mode YouTube (YT_SEARCH_MODE), binaire yt-dlp, cache, quota jour, clés. Équivalent GET /healthz.",
|
||||
inputSchema: { type: 'object', properties: {} },
|
||||
},
|
||||
{
|
||||
name: 'list_playlists',
|
||||
description: "Playlists de l'utilisateur connecté (NEWTUBE_TOKEN requis). Équivalent GET /api/playlists.",
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 200, default: 50 },
|
||||
offset: { type: 'integer', minimum: 0, default: 0 },
|
||||
q: { type: 'string', description: 'Recherche dans les titres' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'list_likes',
|
||||
description: "Vidéos likées de l'utilisateur connecté (NEWTUBE_TOKEN requis). Équivalent GET /api/user/likes.",
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 500, default: 50 },
|
||||
q: { type: 'string', description: 'Recherche serveur' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'list_subscriptions',
|
||||
description: "Abonnements aux chaînes de l'utilisateur connecté (NEWTUBE_TOKEN requis). Équivalent GET /api/subscriptions.",
|
||||
inputSchema: { type: 'object', properties: {} },
|
||||
},
|
||||
{
|
||||
name: 'list_watch_history',
|
||||
description: "Historique de visionnage de l'utilisateur connecté (NEWTUBE_TOKEN requis). Équivalent GET /api/user/history/watch.",
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { limit: { type: 'integer', minimum: 1, maximum: 200, default: 50 } },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function requireAuth() {
|
||||
if (!TOKEN) throw new Error('NEWTUBE_TOKEN manquant — connectez-vous (POST /api/auth/login) puis exportez NEWTUBE_TOKEN=<accessToken>');
|
||||
}
|
||||
|
||||
async function callTool(name, args = {}) {
|
||||
switch (name) {
|
||||
case 'search_videos': {
|
||||
@@ -265,6 +305,39 @@ async function callTool(name, args = {}) {
|
||||
const data = await apiFetch('/healthz');
|
||||
return { summary: `API ${data.status} — YT mode=${data.youtube?.mode}, yt-dlp=${data.youtube?.ytdlp?.version || 'n/a'}`, data };
|
||||
}
|
||||
case 'list_playlists': {
|
||||
requireAuth();
|
||||
const qs = new URLSearchParams({
|
||||
limit: String(args.limit ?? 50), offset: String(args.offset ?? 0),
|
||||
...(args.q ? { q: String(args.q) } : {}),
|
||||
});
|
||||
const data = await apiFetch(`/playlists?${qs}`, { auth: true });
|
||||
const n = Array.isArray(data) ? data.length : 0;
|
||||
return { summary: `${n} playlist(s)`, data };
|
||||
}
|
||||
case 'list_likes': {
|
||||
requireAuth();
|
||||
const qs = new URLSearchParams({
|
||||
limit: String(args.limit ?? 50),
|
||||
...(args.q ? { q: String(args.q) } : {}),
|
||||
});
|
||||
const data = await apiFetch(`/user/likes?${qs}`, { auth: true });
|
||||
const n = Array.isArray(data) ? data.length : 0;
|
||||
return { summary: `${n} vidéo(s) likée(s)`, data };
|
||||
}
|
||||
case 'list_subscriptions': {
|
||||
requireAuth();
|
||||
const data = await apiFetch('/subscriptions', { auth: true });
|
||||
const n = Array.isArray(data?.items) ? data.items.length : 0;
|
||||
return { summary: `${n} abonnement(s)`, data };
|
||||
}
|
||||
case 'list_watch_history': {
|
||||
requireAuth();
|
||||
const qs = new URLSearchParams({ limit: String(args.limit ?? 50) });
|
||||
const data = await apiFetch(`/user/history/watch?${qs}`, { auth: true });
|
||||
const n = Array.isArray(data) ? data.length : 0;
|
||||
return { summary: `${n} entrée(s) d'historique`, data };
|
||||
}
|
||||
default:
|
||||
throw new Error(`unknown_tool: ${name}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user