youtube-knowledge-mcp 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -18
- package/dist/harvest-schemas.d.ts +75 -0
- package/dist/harvest-schemas.d.ts.map +1 -0
- package/dist/harvest-schemas.js +106 -0
- package/dist/harvest-schemas.js.map +1 -0
- package/dist/registry/harvest-tools.d.ts +10 -0
- package/dist/registry/harvest-tools.d.ts.map +1 -0
- package/dist/registry/harvest-tools.js +109 -0
- package/dist/registry/harvest-tools.js.map +1 -0
- package/dist/registry/health-tools.d.ts.map +1 -1
- package/dist/registry/health-tools.js +18 -0
- package/dist/registry/health-tools.js.map +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +2 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/video-tools.js +1 -1
- package/dist/registry/video-tools.js.map +1 -1
- package/dist/schemas.d.ts +239 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +56 -0
- package/dist/schemas.js.map +1 -1
- package/dist/thumbnail-schemas.d.ts +28 -28
- package/dist/tools/ask-brain.js +1 -1
- package/dist/tools/ask-brain.js.map +1 -1
- package/dist/tools/brain-info.js +1 -1
- package/dist/tools/brain-info.js.map +1 -1
- package/dist/tools/check-health.d.ts +59 -0
- package/dist/tools/check-health.d.ts.map +1 -1
- package/dist/tools/check-health.js +85 -6
- package/dist/tools/check-health.js.map +1 -1
- package/dist/tools/fetch-channel-thumbnails.d.ts +8 -8
- package/dist/tools/fetch-videos.d.ts +15 -4
- package/dist/tools/fetch-videos.d.ts.map +1 -1
- package/dist/tools/fetch-videos.js +63 -22
- package/dist/tools/fetch-videos.js.map +1 -1
- package/dist/tools/get-comments.d.ts +238 -6
- package/dist/tools/get-comments.d.ts.map +1 -1
- package/dist/tools/get-comments.js +85 -21
- package/dist/tools/get-comments.js.map +1 -1
- package/dist/tools/get-coverage.d.ts +122 -0
- package/dist/tools/get-coverage.d.ts.map +1 -0
- package/dist/tools/get-coverage.js +105 -0
- package/dist/tools/get-coverage.js.map +1 -0
- package/dist/tools/harvest-channel.d.ts +92 -0
- package/dist/tools/harvest-channel.d.ts.map +1 -0
- package/dist/tools/harvest-channel.js +62 -0
- package/dist/tools/harvest-channel.js.map +1 -0
- package/dist/tools/harvest-comments.d.ts +81 -0
- package/dist/tools/harvest-comments.d.ts.map +1 -0
- package/dist/tools/harvest-comments.js +115 -0
- package/dist/tools/harvest-comments.js.map +1 -0
- package/dist/tools/library.js +1 -1
- package/dist/tools/library.js.map +1 -1
- package/dist/tools/list-channel-thumbnails.d.ts +10 -10
- package/dist/tools/list-channel-thumbnails.js +1 -1
- package/dist/tools/list-channel-thumbnails.js.map +1 -1
- package/dist/tools/list-library.js +1 -1
- package/dist/tools/list-library.js.map +1 -1
- package/dist/tools/prune-harvest.d.ts +59 -0
- package/dist/tools/prune-harvest.d.ts.map +1 -0
- package/dist/tools/prune-harvest.js +108 -0
- package/dist/tools/prune-harvest.js.map +1 -0
- package/dist/tools/query-comments.d.ts +125 -0
- package/dist/tools/query-comments.d.ts.map +1 -0
- package/dist/tools/query-comments.js +106 -0
- package/dist/tools/query-comments.js.map +1 -0
- package/dist/tools/query-videos.d.ts +118 -0
- package/dist/tools/query-videos.d.ts.map +1 -0
- package/dist/tools/query-videos.js +97 -0
- package/dist/tools/query-videos.js.map +1 -0
- package/dist/tools/repair-store.d.ts +34 -0
- package/dist/tools/repair-store.d.ts.map +1 -0
- package/dist/tools/repair-store.js +58 -0
- package/dist/tools/repair-store.js.map +1 -0
- package/dist/tools/search-channels.d.ts.map +1 -1
- package/dist/tools/search-channels.js +5 -1
- package/dist/tools/search-channels.js.map +1 -1
- package/dist/tools/search-videos.js +1 -1
- package/dist/tools/search-videos.js.map +1 -1
- package/dist/utils/comment-store.d.ts +71 -0
- package/dist/utils/comment-store.d.ts.map +1 -0
- package/dist/utils/comment-store.js +129 -0
- package/dist/utils/comment-store.js.map +1 -0
- package/dist/utils/comment-threads.d.ts +51 -0
- package/dist/utils/comment-threads.d.ts.map +1 -0
- package/dist/utils/comment-threads.js +76 -0
- package/dist/utils/comment-threads.js.map +1 -0
- package/dist/utils/coverage-text.d.ts +3 -0
- package/dist/utils/coverage-text.d.ts.map +1 -0
- package/dist/utils/coverage-text.js +62 -0
- package/dist/utils/coverage-text.js.map +1 -0
- package/dist/utils/coverage.d.ts +57 -0
- package/dist/utils/coverage.d.ts.map +1 -0
- package/dist/utils/coverage.js +142 -0
- package/dist/utils/coverage.js.map +1 -0
- package/dist/utils/errors.d.ts +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +9 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/format.d.ts +17 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/harvest-catalog.d.ts +44 -0
- package/dist/utils/harvest-catalog.d.ts.map +1 -0
- package/dist/utils/harvest-catalog.js +164 -0
- package/dist/utils/harvest-catalog.js.map +1 -0
- package/dist/utils/harvest-lock.d.ts +3 -0
- package/dist/utils/harvest-lock.d.ts.map +1 -0
- package/dist/utils/harvest-lock.js +26 -0
- package/dist/utils/harvest-lock.js.map +1 -0
- package/dist/utils/harvest-receipts.d.ts +14 -0
- package/dist/utils/harvest-receipts.d.ts.map +1 -0
- package/dist/utils/harvest-receipts.js +110 -0
- package/dist/utils/harvest-receipts.js.map +1 -0
- package/dist/utils/listing-cursor.d.ts +31 -0
- package/dist/utils/listing-cursor.d.ts.map +1 -0
- package/dist/utils/listing-cursor.js +39 -0
- package/dist/utils/listing-cursor.js.map +1 -0
- package/dist/utils/pot-preflight.d.ts +53 -0
- package/dist/utils/pot-preflight.d.ts.map +1 -0
- package/dist/utils/pot-preflight.js +146 -0
- package/dist/utils/pot-preflight.js.map +1 -0
- package/dist/utils/sleep.d.ts +9 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +25 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/store-health.d.ts +37 -0
- package/dist/utils/store-health.d.ts.map +1 -0
- package/dist/utils/store-health.js +92 -0
- package/dist/utils/store-health.js.map +1 -0
- package/dist/utils/store-migrations.d.ts +33 -0
- package/dist/utils/store-migrations.d.ts.map +1 -0
- package/dist/utils/store-migrations.js +41 -0
- package/dist/utils/store-migrations.js.map +1 -0
- package/dist/utils/store-paths.d.ts +33 -0
- package/dist/utils/store-paths.d.ts.map +1 -0
- package/dist/utils/store-paths.js +48 -0
- package/dist/utils/store-paths.js.map +1 -0
- package/dist/utils/store-rows.d.ts +22 -0
- package/dist/utils/store-rows.d.ts.map +1 -0
- package/dist/utils/store-rows.js +62 -0
- package/dist/utils/store-rows.js.map +1 -0
- package/dist/utils/store-schema.d.ts +16 -0
- package/dist/utils/store-schema.d.ts.map +1 -0
- package/dist/utils/store-schema.js +168 -0
- package/dist/utils/store-schema.js.map +1 -0
- package/dist/utils/store.d.ts +34 -0
- package/dist/utils/store.d.ts.map +1 -0
- package/dist/utils/store.js +157 -0
- package/dist/utils/store.js.map +1 -0
- package/dist/utils/video-stats-cache.d.ts +16 -0
- package/dist/utils/video-stats-cache.d.ts.map +1 -0
- package/dist/utils/video-stats-cache.js +81 -0
- package/dist/utils/video-stats-cache.js.map +1 -0
- package/dist/utils/video-stats.d.ts +186 -0
- package/dist/utils/video-stats.d.ts.map +1 -0
- package/dist/utils/video-stats.js +168 -0
- package/dist/utils/video-stats.js.map +1 -0
- package/dist/utils/video-store.d.ts +69 -0
- package/dist/utils/video-store.d.ts.map +1 -0
- package/dist/utils/video-store.js +77 -0
- package/dist/utils/video-store.js.map +1 -0
- package/dist/utils/youtube-channel.d.ts +9 -2
- package/dist/utils/youtube-channel.d.ts.map +1 -1
- package/dist/utils/youtube-channel.js +33 -3
- package/dist/utils/youtube-channel.js.map +1 -1
- package/dist/utils/youtube-schemas.d.ts +98 -0
- package/dist/utils/youtube-schemas.d.ts.map +1 -1
- package/dist/utils/youtube-schemas.js +30 -0
- package/dist/utils/youtube-schemas.js.map +1 -1
- package/dist/utils/youtube-video.d.ts +22 -1
- package/dist/utils/youtube-video.d.ts.map +1 -1
- package/dist/utils/youtube-video.js +40 -28
- package/dist/utils/youtube-video.js.map +1 -1
- package/dist/utils/ytdlp-limiter.d.ts +3 -0
- package/dist/utils/ytdlp-limiter.d.ts.map +1 -1
- package/dist/utils/ytdlp-limiter.js +19 -3
- package/dist/utils/ytdlp-limiter.js.map +1 -1
- package/dist/utils/ytdlp-pacer.d.ts +64 -0
- package/dist/utils/ytdlp-pacer.d.ts.map +1 -0
- package/dist/utils/ytdlp-pacer.js +165 -0
- package/dist/utils/ytdlp-pacer.js.map +1 -0
- package/dist/utils/ytdlp-stream.d.ts +32 -0
- package/dist/utils/ytdlp-stream.d.ts.map +1 -0
- package/dist/utils/ytdlp-stream.js +61 -0
- package/dist/utils/ytdlp-stream.js.map +1 -0
- package/dist/utils/ytdlp.d.ts +10 -0
- package/dist/utils/ytdlp.d.ts.map +1 -1
- package/dist/utils/ytdlp.js +36 -25
- package/dist/utils/ytdlp.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toolResult } from '../utils/format.js';
|
|
3
|
+
import { getStore, inTransaction } from '../utils/store.js';
|
|
4
|
+
import { countRows } from '../utils/store-rows.js';
|
|
5
|
+
export const pruneHarvestSchema = {
|
|
6
|
+
channel: z.string().max(64).optional().describe('Restrict to one channel id'),
|
|
7
|
+
video: z.string().max(64).optional().describe('Restrict to one video id'),
|
|
8
|
+
author: z
|
|
9
|
+
.string()
|
|
10
|
+
.max(256)
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Remove one author's comments everywhere. The erasure path for a person who asks."),
|
|
13
|
+
scope: z.enum(['comments', 'catalog', 'all']).default('comments'),
|
|
14
|
+
confirm: z
|
|
15
|
+
.literal(true)
|
|
16
|
+
.describe('Must be true. Harvested comments cost hours of network that no local cache can replay.'),
|
|
17
|
+
vacuum: z
|
|
18
|
+
.boolean()
|
|
19
|
+
.default(false)
|
|
20
|
+
.describe('Reclaim disk afterwards. Slow on a large store, and it blocks other writers.'),
|
|
21
|
+
};
|
|
22
|
+
export const pruneHarvestOutputSchema = {
|
|
23
|
+
removed: z.object({
|
|
24
|
+
comments: z.number().int(),
|
|
25
|
+
videos: z.number().int(),
|
|
26
|
+
channels: z.number().int(),
|
|
27
|
+
receipts: z.number().int(),
|
|
28
|
+
}),
|
|
29
|
+
remaining: z.object({
|
|
30
|
+
comments: z.number().int(),
|
|
31
|
+
videos: z.number().int(),
|
|
32
|
+
channels: z.number().int(),
|
|
33
|
+
}),
|
|
34
|
+
vacuumed: z.boolean(),
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Removes harvested data.
|
|
38
|
+
*
|
|
39
|
+
* The store holds personal data at scale — display names, channel ids and
|
|
40
|
+
* free-text opinions from people who never used this tool — so a way to remove
|
|
41
|
+
* it is a requirement, not a convenience. `author` is the per-person erasure
|
|
42
|
+
* path; the other scopes are for reclaiming disk.
|
|
43
|
+
*/
|
|
44
|
+
export async function pruneHarvestHandler(input) {
|
|
45
|
+
const store = await getStore();
|
|
46
|
+
const count = (sql) => countRows(store.prepare(sql));
|
|
47
|
+
const before = {
|
|
48
|
+
comments: count('SELECT COUNT(*) FROM comment'),
|
|
49
|
+
videos: count('SELECT COUNT(*) FROM video'),
|
|
50
|
+
channels: count('SELECT COUNT(*) FROM channel'),
|
|
51
|
+
receipts: count('SELECT COUNT(*) FROM harvest_receipt'),
|
|
52
|
+
};
|
|
53
|
+
inTransaction(store, () => {
|
|
54
|
+
if (input.author !== undefined) {
|
|
55
|
+
store
|
|
56
|
+
.prepare('DELETE FROM comment WHERE author_id = ? OR author = ?')
|
|
57
|
+
.run(input.author, input.author);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (input.scope !== 'catalog') {
|
|
61
|
+
if (input.video !== undefined) {
|
|
62
|
+
store.prepare('DELETE FROM comment WHERE video_id = ?').run(input.video);
|
|
63
|
+
store
|
|
64
|
+
.prepare("DELETE FROM harvest_receipt WHERE scope = 'video-comments' AND target_id = ?")
|
|
65
|
+
.run(input.video);
|
|
66
|
+
}
|
|
67
|
+
else if (input.channel !== undefined) {
|
|
68
|
+
store
|
|
69
|
+
.prepare('DELETE FROM comment WHERE video_id IN (SELECT video_id FROM video WHERE channel_id = ?)')
|
|
70
|
+
.run(input.channel);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
store.exec('DELETE FROM comment');
|
|
74
|
+
store.exec("DELETE FROM harvest_receipt WHERE scope = 'video-comments'");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (input.scope !== 'comments') {
|
|
78
|
+
// ON DELETE CASCADE takes the videos, and their comments, with the channel.
|
|
79
|
+
if (input.channel !== undefined) {
|
|
80
|
+
store.prepare('DELETE FROM channel WHERE channel_id = ?').run(input.channel);
|
|
81
|
+
store
|
|
82
|
+
.prepare("DELETE FROM harvest_receipt WHERE scope = 'channel-catalog' AND target_id = ?")
|
|
83
|
+
.run(input.channel);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
store.exec('DELETE FROM channel');
|
|
87
|
+
store.exec('DELETE FROM video');
|
|
88
|
+
store.exec('DELETE FROM harvest_receipt');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (input.vacuum)
|
|
93
|
+
store.exec('VACUUM');
|
|
94
|
+
const remaining = {
|
|
95
|
+
comments: count('SELECT COUNT(*) FROM comment'),
|
|
96
|
+
videos: count('SELECT COUNT(*) FROM video'),
|
|
97
|
+
channels: count('SELECT COUNT(*) FROM channel'),
|
|
98
|
+
};
|
|
99
|
+
const removed = {
|
|
100
|
+
comments: before.comments - remaining.comments,
|
|
101
|
+
videos: before.videos - remaining.videos,
|
|
102
|
+
channels: before.channels - remaining.channels,
|
|
103
|
+
receipts: before.receipts - count('SELECT COUNT(*) FROM harvest_receipt'),
|
|
104
|
+
};
|
|
105
|
+
return toolResult(`Removed ${String(removed.comments)} comments, ${String(removed.videos)} videos and ${String(removed.channels)} channels. ` +
|
|
106
|
+
`${String(remaining.comments)} comments remain.`, { removed, remaining, vacuumed: input.vacuum });
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=prune-harvest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune-harvest.js","sourceRoot":"","sources":["../../src/tools/prune-harvest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const queryCommentsSchema: {
|
|
4
|
+
video: z.ZodOptional<z.ZodString>;
|
|
5
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
6
|
+
match: z.ZodOptional<z.ZodString>;
|
|
7
|
+
author: z.ZodOptional<z.ZodString>;
|
|
8
|
+
minLikes: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
topLevelOnly: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
threadOf: z.ZodOptional<z.ZodString>;
|
|
11
|
+
order: z.ZodDefault<z.ZodEnum<["likes", "newest", "oldest", "relevance"]>>;
|
|
12
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
13
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
};
|
|
15
|
+
export declare const queryCommentsOutputSchema: {
|
|
16
|
+
total: z.ZodNumber;
|
|
17
|
+
count: z.ZodNumber;
|
|
18
|
+
offset: z.ZodNumber;
|
|
19
|
+
hasMore: z.ZodBoolean;
|
|
20
|
+
nextOffset: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
comments: z.ZodArray<z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
videoId: z.ZodString;
|
|
24
|
+
parentId: z.ZodNullable<z.ZodString>;
|
|
25
|
+
author: z.ZodString;
|
|
26
|
+
authorId: z.ZodOptional<z.ZodString>;
|
|
27
|
+
text: z.ZodString;
|
|
28
|
+
likeCount: z.ZodNumber;
|
|
29
|
+
isPinned: z.ZodBoolean;
|
|
30
|
+
authorIsUploader: z.ZodBoolean;
|
|
31
|
+
publishedAt: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
id: string;
|
|
34
|
+
likeCount: number;
|
|
35
|
+
author: string;
|
|
36
|
+
text: string;
|
|
37
|
+
isPinned: boolean;
|
|
38
|
+
parentId: string | null;
|
|
39
|
+
authorIsUploader: boolean;
|
|
40
|
+
videoId: string;
|
|
41
|
+
authorId?: string | undefined;
|
|
42
|
+
publishedAt?: string | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
id: string;
|
|
45
|
+
likeCount: number;
|
|
46
|
+
author: string;
|
|
47
|
+
text: string;
|
|
48
|
+
isPinned: boolean;
|
|
49
|
+
parentId: string | null;
|
|
50
|
+
authorIsUploader: boolean;
|
|
51
|
+
videoId: string;
|
|
52
|
+
authorId?: string | undefined;
|
|
53
|
+
publishedAt?: string | undefined;
|
|
54
|
+
}>, "many">;
|
|
55
|
+
coverage: z.ZodArray<z.ZodObject<{
|
|
56
|
+
scope: z.ZodEnum<["channel-catalog", "video-details", "video-comments"]>;
|
|
57
|
+
targetId: z.ZodString;
|
|
58
|
+
complete: z.ZodBoolean;
|
|
59
|
+
reason: z.ZodEnum<["COMPLETE", "CAP_REACHED", "BUDGET_SPENT", "RATE_LIMITED", "CANCELLED", "TIMEOUT", "SOURCE_REFUSED", "COMMENTS_DISABLED", "SOURCE_SILENT", "PARTIAL_ERROR", "NOT_ATTEMPTED"]>;
|
|
60
|
+
have: z.ZodNumber;
|
|
61
|
+
expected: z.ZodOptional<z.ZodNumber>;
|
|
62
|
+
expectedSource: z.ZodOptional<z.ZodEnum<["youtube:comment_count", "youtube:playlist_count", "source-exhausted"]>>;
|
|
63
|
+
ranToExhaustion: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
source: z.ZodString;
|
|
65
|
+
harvestedAt: z.ZodString;
|
|
66
|
+
staleAfter: z.ZodOptional<z.ZodString>;
|
|
67
|
+
limitApplied: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
sortApplied: z.ZodOptional<z.ZodEnum<["top", "new"]>>;
|
|
69
|
+
resumeToken: z.ZodOptional<z.ZodString>;
|
|
70
|
+
note: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
have: number;
|
|
73
|
+
scope: "channel-catalog" | "video-details" | "video-comments";
|
|
74
|
+
targetId: string;
|
|
75
|
+
complete: boolean;
|
|
76
|
+
reason: "RATE_LIMITED" | "TIMEOUT" | "CANCELLED" | "COMPLETE" | "CAP_REACHED" | "BUDGET_SPENT" | "SOURCE_REFUSED" | "COMMENTS_DISABLED" | "SOURCE_SILENT" | "PARTIAL_ERROR" | "NOT_ATTEMPTED";
|
|
77
|
+
source: string;
|
|
78
|
+
harvestedAt: string;
|
|
79
|
+
expected?: number | undefined;
|
|
80
|
+
note?: string | undefined;
|
|
81
|
+
ranToExhaustion?: boolean | undefined;
|
|
82
|
+
expectedSource?: "youtube:playlist_count" | "source-exhausted" | "youtube:comment_count" | undefined;
|
|
83
|
+
staleAfter?: string | undefined;
|
|
84
|
+
limitApplied?: number | undefined;
|
|
85
|
+
sortApplied?: "top" | "new" | undefined;
|
|
86
|
+
resumeToken?: string | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
have: number;
|
|
89
|
+
scope: "channel-catalog" | "video-details" | "video-comments";
|
|
90
|
+
targetId: string;
|
|
91
|
+
complete: boolean;
|
|
92
|
+
reason: "RATE_LIMITED" | "TIMEOUT" | "CANCELLED" | "COMPLETE" | "CAP_REACHED" | "BUDGET_SPENT" | "SOURCE_REFUSED" | "COMMENTS_DISABLED" | "SOURCE_SILENT" | "PARTIAL_ERROR" | "NOT_ATTEMPTED";
|
|
93
|
+
source: string;
|
|
94
|
+
harvestedAt: string;
|
|
95
|
+
expected?: number | undefined;
|
|
96
|
+
note?: string | undefined;
|
|
97
|
+
ranToExhaustion?: boolean | undefined;
|
|
98
|
+
expectedSource?: "youtube:playlist_count" | "source-exhausted" | "youtube:comment_count" | undefined;
|
|
99
|
+
staleAfter?: string | undefined;
|
|
100
|
+
limitApplied?: number | undefined;
|
|
101
|
+
sortApplied?: "top" | "new" | undefined;
|
|
102
|
+
resumeToken?: string | undefined;
|
|
103
|
+
}>, "many">;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Searches comments already in the store.
|
|
107
|
+
*
|
|
108
|
+
* The one place in this server where `total` is honestly a total: the dataset
|
|
109
|
+
* is local and fixed, so it is a real COUNT(*) and the offset genuinely works.
|
|
110
|
+
* It is paired with coverage so "total: 4,312" cannot be read as "the video
|
|
111
|
+
* has 4,312 comments".
|
|
112
|
+
*/
|
|
113
|
+
export declare function queryCommentsHandler(input: {
|
|
114
|
+
video?: string;
|
|
115
|
+
channel?: string;
|
|
116
|
+
match?: string;
|
|
117
|
+
author?: string;
|
|
118
|
+
minLikes: number;
|
|
119
|
+
topLevelOnly: boolean;
|
|
120
|
+
threadOf?: string;
|
|
121
|
+
order: 'likes' | 'newest' | 'oldest' | 'relevance';
|
|
122
|
+
limit: number;
|
|
123
|
+
offset: number;
|
|
124
|
+
}): Promise<CallToolResult>;
|
|
125
|
+
//# sourceMappingURL=query-comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-comments.d.ts","sourceRoot":"","sources":["../../src/tools/query-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,mBAAmB;;;;;;;;;;;CAsB/B,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsBrC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CAwD1B"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pageInfo, toolResult } from '../utils/format.js';
|
|
3
|
+
import { paginationShape } from '../schemas.js';
|
|
4
|
+
import { coverageSchema } from '../harvest-schemas.js';
|
|
5
|
+
import { getStore } from '../utils/store.js';
|
|
6
|
+
import { countComments, queryComments } from '../utils/comment-store.js';
|
|
7
|
+
import { readReceipt } from '../utils/harvest-receipts.js';
|
|
8
|
+
export const queryCommentsSchema = {
|
|
9
|
+
video: z.string().max(2048).optional().describe('Restrict to one video id'),
|
|
10
|
+
channel: z.string().max(64).optional().describe('Restrict to one channel id'),
|
|
11
|
+
match: z
|
|
12
|
+
.string()
|
|
13
|
+
.max(512)
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Full-text query over comment text, SQLite FTS5 syntax: bare words, "quoted phrases", ' +
|
|
16
|
+
'AND / OR / NOT, prefix*. Omit to browse by order instead.'),
|
|
17
|
+
author: z.string().max(256).optional().describe('Match on author id, or exact author name'),
|
|
18
|
+
minLikes: z.number().int().min(0).default(0),
|
|
19
|
+
topLevelOnly: z.boolean().default(false),
|
|
20
|
+
threadOf: z
|
|
21
|
+
.string()
|
|
22
|
+
.max(64)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('A comment id: returns that comment and its replies, in reply order'),
|
|
25
|
+
order: z.enum(['likes', 'newest', 'oldest', 'relevance']).default('likes'),
|
|
26
|
+
limit: z.number().int().min(1).max(200).default(25),
|
|
27
|
+
offset: z.number().int().min(0).default(0),
|
|
28
|
+
};
|
|
29
|
+
export const queryCommentsOutputSchema = {
|
|
30
|
+
comments: z.array(z.object({
|
|
31
|
+
id: z.string(),
|
|
32
|
+
videoId: z.string(),
|
|
33
|
+
parentId: z.string().nullable(),
|
|
34
|
+
author: z.string(),
|
|
35
|
+
authorId: z.string().optional(),
|
|
36
|
+
text: z.string(),
|
|
37
|
+
likeCount: z.number().int(),
|
|
38
|
+
isPinned: z.boolean(),
|
|
39
|
+
authorIsUploader: z.boolean(),
|
|
40
|
+
publishedAt: z.string().optional(),
|
|
41
|
+
})),
|
|
42
|
+
coverage: z
|
|
43
|
+
.array(coverageSchema)
|
|
44
|
+
.describe('Coverage of the videos these results were drawn from. `total` counts rows IN THIS STORE — ' +
|
|
45
|
+
'it is not the number of comments those videos have, and these receipts are what says so.'),
|
|
46
|
+
...paginationShape,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Searches comments already in the store.
|
|
50
|
+
*
|
|
51
|
+
* The one place in this server where `total` is honestly a total: the dataset
|
|
52
|
+
* is local and fixed, so it is a real COUNT(*) and the offset genuinely works.
|
|
53
|
+
* It is paired with coverage so "total: 4,312" cannot be read as "the video
|
|
54
|
+
* has 4,312 comments".
|
|
55
|
+
*/
|
|
56
|
+
export async function queryCommentsHandler(input) {
|
|
57
|
+
const store = await getStore();
|
|
58
|
+
const query = {
|
|
59
|
+
...(input.video === undefined ? {} : { videoId: input.video }),
|
|
60
|
+
...(input.channel === undefined ? {} : { channelId: input.channel }),
|
|
61
|
+
...(input.match === undefined ? {} : { match: input.match }),
|
|
62
|
+
...(input.author === undefined ? {} : { authorId: input.author }),
|
|
63
|
+
...(input.threadOf === undefined ? {} : { threadOf: input.threadOf }),
|
|
64
|
+
minLikes: input.minLikes,
|
|
65
|
+
topLevelOnly: input.topLevelOnly,
|
|
66
|
+
order: input.order,
|
|
67
|
+
limit: input.limit,
|
|
68
|
+
offset: input.offset,
|
|
69
|
+
};
|
|
70
|
+
const rows = queryComments(store, query);
|
|
71
|
+
const total = countComments(store, query);
|
|
72
|
+
const videoIds = [...new Set(rows.map((row) => row.video_id))];
|
|
73
|
+
const coverage = videoIds
|
|
74
|
+
.map((videoId) => readReceipt(store, 'video-comments', videoId))
|
|
75
|
+
.filter((receipt) => receipt !== undefined);
|
|
76
|
+
const incomplete = coverage.filter((receipt) => !receipt.complete).length;
|
|
77
|
+
const lines = [
|
|
78
|
+
`${String(rows.length)} of ${String(total)} matching comments in the store.`,
|
|
79
|
+
...(incomplete > 0
|
|
80
|
+
? [
|
|
81
|
+
`${String(incomplete)} of the ${String(coverage.length)} videos these came from are only partly harvested — this is a sample of their comments, not all of them.`,
|
|
82
|
+
]
|
|
83
|
+
: []),
|
|
84
|
+
'',
|
|
85
|
+
...rows.map((row) => `${row.author}${row.author_is_uploader ? ' (uploader)' : ''}: ${row.text.replace(/\s+/g, ' ').slice(0, 200)} — ${String(row.like_count)} likes`),
|
|
86
|
+
];
|
|
87
|
+
return toolResult(lines.join('\n'), {
|
|
88
|
+
comments: rows.map((row) => ({
|
|
89
|
+
id: row.comment_id,
|
|
90
|
+
videoId: row.video_id,
|
|
91
|
+
parentId: row.parent_id,
|
|
92
|
+
author: row.author,
|
|
93
|
+
...(row.author_id === null ? {} : { authorId: row.author_id }),
|
|
94
|
+
text: row.text,
|
|
95
|
+
likeCount: row.like_count,
|
|
96
|
+
isPinned: row.is_pinned,
|
|
97
|
+
authorIsUploader: row.author_is_uploader,
|
|
98
|
+
...(row.published_at === null
|
|
99
|
+
? {}
|
|
100
|
+
: { publishedAt: new Date(row.published_at * 1000).toISOString() }),
|
|
101
|
+
})),
|
|
102
|
+
coverage,
|
|
103
|
+
...pageInfo({ total, count: rows.length, offset: input.offset }),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=query-comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-comments.js","sourceRoot":"","sources":["../../src/tools/query-comments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const queryVideosSchema: {
|
|
4
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
5
|
+
match: z.ZodOptional<z.ZodString>;
|
|
6
|
+
since: z.ZodOptional<z.ZodString>;
|
|
7
|
+
until: z.ZodOptional<z.ZodString>;
|
|
8
|
+
minDurationSeconds: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
detailedOnly: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
withComments: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
+
order: z.ZodDefault<z.ZodEnum<["newest", "oldest", "views", "comments", "catalog"]>>;
|
|
12
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
13
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
};
|
|
15
|
+
export declare const queryVideosOutputSchema: {
|
|
16
|
+
total: z.ZodNumber;
|
|
17
|
+
count: z.ZodNumber;
|
|
18
|
+
offset: z.ZodNumber;
|
|
19
|
+
hasMore: z.ZodBoolean;
|
|
20
|
+
nextOffset: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
videos: z.ZodArray<z.ZodObject<{
|
|
22
|
+
videoId: z.ZodString;
|
|
23
|
+
channelId: z.ZodOptional<z.ZodString>;
|
|
24
|
+
title: z.ZodString;
|
|
25
|
+
durationSeconds: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
uploadDate: z.ZodOptional<z.ZodString>;
|
|
27
|
+
viewCount: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
tab: z.ZodOptional<z.ZodString>;
|
|
29
|
+
alsoInTabs: z.ZodArray<z.ZodString, "many">;
|
|
30
|
+
storedComments: z.ZodNumber;
|
|
31
|
+
detailed: z.ZodBoolean;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
title: string;
|
|
34
|
+
videoId: string;
|
|
35
|
+
detailed: boolean;
|
|
36
|
+
alsoInTabs: string[];
|
|
37
|
+
storedComments: number;
|
|
38
|
+
durationSeconds?: number | undefined;
|
|
39
|
+
viewCount?: number | undefined;
|
|
40
|
+
uploadDate?: string | undefined;
|
|
41
|
+
channelId?: string | undefined;
|
|
42
|
+
tab?: string | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
title: string;
|
|
45
|
+
videoId: string;
|
|
46
|
+
detailed: boolean;
|
|
47
|
+
alsoInTabs: string[];
|
|
48
|
+
storedComments: number;
|
|
49
|
+
durationSeconds?: number | undefined;
|
|
50
|
+
viewCount?: number | undefined;
|
|
51
|
+
uploadDate?: string | undefined;
|
|
52
|
+
channelId?: string | undefined;
|
|
53
|
+
tab?: string | undefined;
|
|
54
|
+
}>, "many">;
|
|
55
|
+
coverage: z.ZodArray<z.ZodObject<{
|
|
56
|
+
scope: z.ZodEnum<["channel-catalog", "video-details", "video-comments"]>;
|
|
57
|
+
targetId: z.ZodString;
|
|
58
|
+
complete: z.ZodBoolean;
|
|
59
|
+
reason: z.ZodEnum<["COMPLETE", "CAP_REACHED", "BUDGET_SPENT", "RATE_LIMITED", "CANCELLED", "TIMEOUT", "SOURCE_REFUSED", "COMMENTS_DISABLED", "SOURCE_SILENT", "PARTIAL_ERROR", "NOT_ATTEMPTED"]>;
|
|
60
|
+
have: z.ZodNumber;
|
|
61
|
+
expected: z.ZodOptional<z.ZodNumber>;
|
|
62
|
+
expectedSource: z.ZodOptional<z.ZodEnum<["youtube:comment_count", "youtube:playlist_count", "source-exhausted"]>>;
|
|
63
|
+
ranToExhaustion: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
source: z.ZodString;
|
|
65
|
+
harvestedAt: z.ZodString;
|
|
66
|
+
staleAfter: z.ZodOptional<z.ZodString>;
|
|
67
|
+
limitApplied: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
sortApplied: z.ZodOptional<z.ZodEnum<["top", "new"]>>;
|
|
69
|
+
resumeToken: z.ZodOptional<z.ZodString>;
|
|
70
|
+
note: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
have: number;
|
|
73
|
+
scope: "channel-catalog" | "video-details" | "video-comments";
|
|
74
|
+
targetId: string;
|
|
75
|
+
complete: boolean;
|
|
76
|
+
reason: "RATE_LIMITED" | "TIMEOUT" | "CANCELLED" | "COMPLETE" | "CAP_REACHED" | "BUDGET_SPENT" | "SOURCE_REFUSED" | "COMMENTS_DISABLED" | "SOURCE_SILENT" | "PARTIAL_ERROR" | "NOT_ATTEMPTED";
|
|
77
|
+
source: string;
|
|
78
|
+
harvestedAt: string;
|
|
79
|
+
expected?: number | undefined;
|
|
80
|
+
note?: string | undefined;
|
|
81
|
+
ranToExhaustion?: boolean | undefined;
|
|
82
|
+
expectedSource?: "youtube:playlist_count" | "source-exhausted" | "youtube:comment_count" | undefined;
|
|
83
|
+
staleAfter?: string | undefined;
|
|
84
|
+
limitApplied?: number | undefined;
|
|
85
|
+
sortApplied?: "top" | "new" | undefined;
|
|
86
|
+
resumeToken?: string | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
have: number;
|
|
89
|
+
scope: "channel-catalog" | "video-details" | "video-comments";
|
|
90
|
+
targetId: string;
|
|
91
|
+
complete: boolean;
|
|
92
|
+
reason: "RATE_LIMITED" | "TIMEOUT" | "CANCELLED" | "COMPLETE" | "CAP_REACHED" | "BUDGET_SPENT" | "SOURCE_REFUSED" | "COMMENTS_DISABLED" | "SOURCE_SILENT" | "PARTIAL_ERROR" | "NOT_ATTEMPTED";
|
|
93
|
+
source: string;
|
|
94
|
+
harvestedAt: string;
|
|
95
|
+
expected?: number | undefined;
|
|
96
|
+
note?: string | undefined;
|
|
97
|
+
ranToExhaustion?: boolean | undefined;
|
|
98
|
+
expectedSource?: "youtube:playlist_count" | "source-exhausted" | "youtube:comment_count" | undefined;
|
|
99
|
+
staleAfter?: string | undefined;
|
|
100
|
+
limitApplied?: number | undefined;
|
|
101
|
+
sortApplied?: "top" | "new" | undefined;
|
|
102
|
+
resumeToken?: string | undefined;
|
|
103
|
+
}>, "many">;
|
|
104
|
+
};
|
|
105
|
+
/** Searches the catalogued videos. Local only; never contacts YouTube. */
|
|
106
|
+
export declare function queryVideosHandler(input: {
|
|
107
|
+
channel?: string;
|
|
108
|
+
match?: string;
|
|
109
|
+
since?: string;
|
|
110
|
+
until?: string;
|
|
111
|
+
minDurationSeconds: number;
|
|
112
|
+
detailedOnly: boolean;
|
|
113
|
+
withComments: boolean;
|
|
114
|
+
order: 'newest' | 'oldest' | 'views' | 'comments' | 'catalog';
|
|
115
|
+
limit: number;
|
|
116
|
+
offset: number;
|
|
117
|
+
}): Promise<CallToolResult>;
|
|
118
|
+
//# sourceMappingURL=query-videos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-videos.d.ts","sourceRoot":"","sources":["../../src/tools/query-videos.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;CAiB7B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBnC,CAAC;AAQF,0EAA0E;AAC1E,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoD1B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pageInfo, toolResult } from '../utils/format.js';
|
|
3
|
+
import { paginationShape } from '../schemas.js';
|
|
4
|
+
import { coverageSchema } from '../harvest-schemas.js';
|
|
5
|
+
import { getStore } from '../utils/store.js';
|
|
6
|
+
import { countVideos, queryVideos } from '../utils/video-store.js';
|
|
7
|
+
import { readReceipt } from '../utils/harvest-receipts.js';
|
|
8
|
+
export const queryVideosSchema = {
|
|
9
|
+
channel: z.string().max(64).optional().describe('Restrict to one channel id'),
|
|
10
|
+
match: z.string().max(512).optional().describe('Substring match on the title'),
|
|
11
|
+
since: z
|
|
12
|
+
.string()
|
|
13
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
14
|
+
.optional(),
|
|
15
|
+
until: z
|
|
16
|
+
.string()
|
|
17
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
18
|
+
.optional(),
|
|
19
|
+
minDurationSeconds: z.number().int().min(0).default(0),
|
|
20
|
+
detailedOnly: z.boolean().default(false).describe('Only videos whose full metadata was read'),
|
|
21
|
+
withComments: z.boolean().default(false).describe('Only videos that have harvested comments'),
|
|
22
|
+
order: z.enum(['newest', 'oldest', 'views', 'comments', 'catalog']).default('newest'),
|
|
23
|
+
limit: z.number().int().min(1).max(200).default(25),
|
|
24
|
+
offset: z.number().int().min(0).default(0),
|
|
25
|
+
};
|
|
26
|
+
export const queryVideosOutputSchema = {
|
|
27
|
+
videos: z.array(z.object({
|
|
28
|
+
videoId: z.string(),
|
|
29
|
+
channelId: z.string().optional(),
|
|
30
|
+
title: z.string(),
|
|
31
|
+
durationSeconds: z.number().optional(),
|
|
32
|
+
uploadDate: z
|
|
33
|
+
.string()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Absent when only a flat listing has seen this video, which carries no date'),
|
|
36
|
+
viewCount: z.number().optional(),
|
|
37
|
+
tab: z.string().optional(),
|
|
38
|
+
alsoInTabs: z.array(z.string()),
|
|
39
|
+
storedComments: z.number().int().describe('Comments held locally, not the number it has'),
|
|
40
|
+
detailed: z.boolean(),
|
|
41
|
+
})),
|
|
42
|
+
coverage: z.array(coverageSchema).describe('The channel-catalogue receipts these rows came from'),
|
|
43
|
+
...paginationShape,
|
|
44
|
+
};
|
|
45
|
+
/** The column is a JSON array written by SQLite's json_insert. */
|
|
46
|
+
function parseTabs(value) {
|
|
47
|
+
const parsed = JSON.parse(value);
|
|
48
|
+
return z.array(z.string()).catch([]).parse(parsed);
|
|
49
|
+
}
|
|
50
|
+
/** Searches the catalogued videos. Local only; never contacts YouTube. */
|
|
51
|
+
export async function queryVideosHandler(input) {
|
|
52
|
+
const store = await getStore();
|
|
53
|
+
const query = {
|
|
54
|
+
...(input.channel === undefined ? {} : { channelId: input.channel }),
|
|
55
|
+
...(input.match === undefined ? {} : { match: input.match }),
|
|
56
|
+
...(input.since === undefined ? {} : { since: input.since }),
|
|
57
|
+
...(input.until === undefined ? {} : { until: input.until }),
|
|
58
|
+
minDurationSeconds: input.minDurationSeconds,
|
|
59
|
+
detailedOnly: input.detailedOnly,
|
|
60
|
+
withComments: input.withComments,
|
|
61
|
+
order: input.order,
|
|
62
|
+
limit: input.limit,
|
|
63
|
+
offset: input.offset,
|
|
64
|
+
};
|
|
65
|
+
const rows = queryVideos(store, query);
|
|
66
|
+
const total = countVideos(store, query);
|
|
67
|
+
const channelIds = [...new Set(rows.map((row) => row.channel_id).filter((id) => id !== null))];
|
|
68
|
+
const coverage = channelIds
|
|
69
|
+
.map((channelId) => readReceipt(store, 'channel-catalog', channelId))
|
|
70
|
+
.filter((receipt) => receipt !== undefined);
|
|
71
|
+
const incomplete = coverage.filter((receipt) => !receipt.complete).length;
|
|
72
|
+
const lines = [
|
|
73
|
+
`${String(rows.length)} of ${String(total)} videos in the store.`,
|
|
74
|
+
...(incomplete > 0
|
|
75
|
+
? ['At least one channel here is only partly catalogued, so this is not its full video list.']
|
|
76
|
+
: []),
|
|
77
|
+
'',
|
|
78
|
+
...rows.map((row) => `${row.upload_date ?? '(no date)'} ${row.title} — ${String(row.stored_comments)} comments held`),
|
|
79
|
+
];
|
|
80
|
+
return toolResult(lines.join('\n'), {
|
|
81
|
+
videos: rows.map((row) => ({
|
|
82
|
+
videoId: row.video_id,
|
|
83
|
+
...(row.channel_id === null ? {} : { channelId: row.channel_id }),
|
|
84
|
+
title: row.title,
|
|
85
|
+
...(row.duration_s === null ? {} : { durationSeconds: row.duration_s }),
|
|
86
|
+
...(row.upload_date === null ? {} : { uploadDate: row.upload_date }),
|
|
87
|
+
...(row.view_count === null ? {} : { viewCount: row.view_count }),
|
|
88
|
+
...(row.tab === null ? {} : { tab: row.tab }),
|
|
89
|
+
alsoInTabs: parseTabs(row.also_in_tabs),
|
|
90
|
+
storedComments: row.stored_comments,
|
|
91
|
+
detailed: row.detail_at !== null,
|
|
92
|
+
})),
|
|
93
|
+
coverage,
|
|
94
|
+
...pageInfo({ total, count: rows.length, offset: input.offset }),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=query-videos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-videos.js","sourceRoot":"","sources":["../../src/tools/query-videos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const repairStoreSchema: {
|
|
4
|
+
confirm: z.ZodLiteral<true>;
|
|
5
|
+
};
|
|
6
|
+
export declare const repairStoreOutputSchema: {
|
|
7
|
+
wasCorrupt: z.ZodBoolean;
|
|
8
|
+
integrity: z.ZodEnum<["ok", "failed", "unchecked"]>;
|
|
9
|
+
movedTo: z.ZodOptional<z.ZodString>;
|
|
10
|
+
lost: z.ZodObject<{
|
|
11
|
+
channels: z.ZodNumber;
|
|
12
|
+
videos: z.ZodNumber;
|
|
13
|
+
comments: z.ZodNumber;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
videos: number;
|
|
16
|
+
comments: number;
|
|
17
|
+
channels: number;
|
|
18
|
+
}, {
|
|
19
|
+
videos: number;
|
|
20
|
+
comments: number;
|
|
21
|
+
channels: number;
|
|
22
|
+
}>;
|
|
23
|
+
storePath: z.ZodString;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Moves a damaged store aside and starts a fresh one.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately not automatic. `search-index.json` is rebuilt from disk without
|
|
29
|
+
* asking because it is derivable; this is not — it is the only copy of data
|
|
30
|
+
* that took hours of network to collect. So the damaged file is renamed rather
|
|
31
|
+
* than deleted, and the report says what was in it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function repairStoreHandler(): Promise<CallToolResult>;
|
|
34
|
+
//# sourceMappingURL=repair-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair-store.d.ts","sourceRoot":"","sources":["../../src/tools/repair-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,iBAAiB;;CAO7B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;CAanC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC,CAkClE"}
|