audiobookshelf-mcp 0.1.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/LICENSE +21 -0
- package/README.md +255 -0
- package/dist/api.d.ts +38 -0
- package/dist/api.js +122 -0
- package/dist/api.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/confirm.d.ts +36 -0
- package/dist/confirm.js +72 -0
- package/dist/confirm.js.map +1 -0
- package/dist/filters.d.ts +32 -0
- package/dist/filters.js +81 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/result.d.ts +18 -0
- package/dist/result.js +71 -0
- package/dist/result.js.map +1 -0
- package/dist/schema.d.ts +12 -0
- package/dist/schema.js +36 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +43 -0
- package/dist/server.js.map +1 -0
- package/dist/shape.d.ts +72 -0
- package/dist/shape.js +397 -0
- package/dist/shape.js.map +1 -0
- package/dist/tools/collections.d.ts +5 -0
- package/dist/tools/collections.js +183 -0
- package/dist/tools/collections.js.map +1 -0
- package/dist/tools/items.d.ts +3 -0
- package/dist/tools/items.js +117 -0
- package/dist/tools/items.js.map +1 -0
- package/dist/tools/libraries.d.ts +3 -0
- package/dist/tools/libraries.js +337 -0
- package/dist/tools/libraries.js.map +1 -0
- package/dist/tools/me.d.ts +3 -0
- package/dist/tools/me.js +141 -0
- package/dist/tools/me.js.map +1 -0
- package/dist/tools/playlists.d.ts +5 -0
- package/dist/tools/playlists.js +200 -0
- package/dist/tools/playlists.js.map +1 -0
- package/dist/tools/progress.d.ts +5 -0
- package/dist/tools/progress.js +161 -0
- package/dist/tools/progress.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { assertPathSegment, query } from '../api.js';
|
|
3
|
+
import { errorResult, run, untrustedJsonResult } from '../result.js';
|
|
4
|
+
import { detailParam, libraryItemIdParam } from '../schema.js';
|
|
5
|
+
import { compactLibraryItem, compactPodcastEpisode, truncateText, } from '../shape.js';
|
|
6
|
+
export function registerItemReadTools(server, api) {
|
|
7
|
+
server.registerTool('get_library_item', {
|
|
8
|
+
title: 'Get library item',
|
|
9
|
+
description: 'Fetches one book or podcast including its metadata, tags and the ' +
|
|
10
|
+
'listening progress of the API key’s user. Chapters, audio files and ' +
|
|
11
|
+
'tracks are not part of the compact projection — use get_item_chapters ' +
|
|
12
|
+
'for chapters, or detail="full" for everything.',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
library_item_id: libraryItemIdParam,
|
|
15
|
+
detail: detailParam,
|
|
16
|
+
},
|
|
17
|
+
annotations: { readOnlyHint: true },
|
|
18
|
+
}, async ({ library_item_id, detail }) => run(async () => {
|
|
19
|
+
const data = await api.get(`/api/items/${assertPathSegment(library_item_id, 'library_item_id')}` +
|
|
20
|
+
// include=progress is only honoured together with expanded=1.
|
|
21
|
+
query({ expanded: 1, include: 'progress' }));
|
|
22
|
+
return untrustedJsonResult(detail === 'full'
|
|
23
|
+
? data
|
|
24
|
+
: compactLibraryItem(data, { includeDescription: true }));
|
|
25
|
+
}));
|
|
26
|
+
server.registerTool('get_item_chapters', {
|
|
27
|
+
title: 'Get item chapters',
|
|
28
|
+
description: 'Returns the chapter list of a book with start and end times in seconds. ' +
|
|
29
|
+
'Separate from get_library_item because long audiobooks can have hundreds ' +
|
|
30
|
+
'of chapters.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
library_item_id: libraryItemIdParam,
|
|
33
|
+
},
|
|
34
|
+
annotations: { readOnlyHint: true },
|
|
35
|
+
}, async ({ library_item_id }) => run(async () => {
|
|
36
|
+
const safeId = assertPathSegment(library_item_id, 'library_item_id');
|
|
37
|
+
const item = (await api.get(`/api/items/${safeId}` + query({ expanded: 1 })));
|
|
38
|
+
const media = (item.media ?? {});
|
|
39
|
+
const chapters = Array.isArray(media.chapters) ? media.chapters : [];
|
|
40
|
+
if (item.mediaType !== 'book') {
|
|
41
|
+
return errorResult(`Library item ${safeId} is a ${String(item.mediaType)}, not a book — ` +
|
|
42
|
+
'only books have chapters. For podcast episodes use get_podcast_episode.');
|
|
43
|
+
}
|
|
44
|
+
return untrustedJsonResult({
|
|
45
|
+
libraryItemId: safeId,
|
|
46
|
+
numChapters: chapters.length,
|
|
47
|
+
chapters,
|
|
48
|
+
});
|
|
49
|
+
}));
|
|
50
|
+
server.registerTool('get_podcast_episode', {
|
|
51
|
+
title: 'Get podcast episode',
|
|
52
|
+
description: 'Fetches one podcast episode with its publication date, duration and ' +
|
|
53
|
+
'description.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
library_item_id: z
|
|
56
|
+
.string()
|
|
57
|
+
.min(1)
|
|
58
|
+
.describe('Library item id of the podcast the episode belongs to'),
|
|
59
|
+
episode_id: z.string().min(1).describe('Podcast episode id'),
|
|
60
|
+
detail: detailParam,
|
|
61
|
+
},
|
|
62
|
+
annotations: { readOnlyHint: true },
|
|
63
|
+
}, async ({ library_item_id, episode_id, detail }) => run(async () => {
|
|
64
|
+
const data = await api.get(`/api/podcasts/${assertPathSegment(library_item_id, 'library_item_id')}` +
|
|
65
|
+
`/episode/${assertPathSegment(episode_id, 'episode_id')}`);
|
|
66
|
+
return untrustedJsonResult(detail === 'full'
|
|
67
|
+
? data
|
|
68
|
+
: compactPodcastEpisode(data, { includeDescription: true }));
|
|
69
|
+
}));
|
|
70
|
+
server.registerTool('list_recent_episodes', {
|
|
71
|
+
title: 'List recent podcast episodes',
|
|
72
|
+
description: 'Lists the most recently published episodes across a podcast library — ' +
|
|
73
|
+
'the "Newest Episodes" view. Only works on libraries with mediaType ' +
|
|
74
|
+
'"podcast".',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
library_id: z.string().min(1).describe('Id of a podcast library'),
|
|
77
|
+
page: z
|
|
78
|
+
.number()
|
|
79
|
+
.int()
|
|
80
|
+
.min(0)
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('0-based page number, default 0'),
|
|
83
|
+
limit: z
|
|
84
|
+
.number()
|
|
85
|
+
.int()
|
|
86
|
+
.min(1)
|
|
87
|
+
.max(100)
|
|
88
|
+
.optional()
|
|
89
|
+
.describe('Episodes per page, default 25, max 100'),
|
|
90
|
+
detail: detailParam,
|
|
91
|
+
},
|
|
92
|
+
annotations: { readOnlyHint: true },
|
|
93
|
+
}, async ({ library_id, page, limit, detail }) => run(async () => {
|
|
94
|
+
const data = (await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/recent-episodes` +
|
|
95
|
+
query({ limit: limit ?? 25, page: page ?? 0 })));
|
|
96
|
+
const episodes = Array.isArray(data.episodes) ? data.episodes : [];
|
|
97
|
+
return untrustedJsonResult({
|
|
98
|
+
// This endpoint reports no total, only the page it returned.
|
|
99
|
+
numReturned: episodes.length,
|
|
100
|
+
limit: data.limit,
|
|
101
|
+
page: data.page,
|
|
102
|
+
episodes: detail === 'full'
|
|
103
|
+
? episodes
|
|
104
|
+
: episodes.map((episode) => {
|
|
105
|
+
const shaped = compactPodcastEpisode(episode);
|
|
106
|
+
const podcast = episode.podcast;
|
|
107
|
+
return podcast === undefined
|
|
108
|
+
? shaped
|
|
109
|
+
: {
|
|
110
|
+
...shaped,
|
|
111
|
+
podcastTitle: truncateText(podcast.metadata?.title, 200),
|
|
112
|
+
};
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"items.js","sourceRoot":"","sources":["../../src/tools/items.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { assertPathSegment, query } from '../api.js';
|
|
3
|
+
import { describeFilterGroups, encodeFilter, FILTER_GROUPS, PROGRESS_FILTER_VALUES, } from '../filters.js';
|
|
4
|
+
import { jsonResult, run, untrustedJsonResult } from '../result.js';
|
|
5
|
+
import { detailParam, libraryIdParam, limitParam, pageParam, } from '../schema.js';
|
|
6
|
+
import { compactAuthor, compactItemPage, compactLibrary, compactLibraryItem, compactSeries, listFrom, } from '../shape.js';
|
|
7
|
+
const DEFAULT_ITEM_LIMIT = 25;
|
|
8
|
+
const DEFAULT_SEARCH_LIMIT = 12;
|
|
9
|
+
/**
|
|
10
|
+
* Sort keys Audiobookshelf understands. It ignores unknown keys silently and
|
|
11
|
+
* falls back to the default order, so the useful ones are spelled out for the
|
|
12
|
+
* model instead of being left to guesswork.
|
|
13
|
+
*/
|
|
14
|
+
const SORT_HINT = 'Sort key in dot notation. Common values: media.metadata.title, ' +
|
|
15
|
+
'media.metadata.authorName, media.metadata.publishedYear, media.duration, ' +
|
|
16
|
+
'birthtimeMs, addedAt, size, progress, random.';
|
|
17
|
+
export function registerLibraryReadTools(server, api) {
|
|
18
|
+
server.registerTool('list_libraries', {
|
|
19
|
+
title: 'List libraries',
|
|
20
|
+
description: 'Lists the Audiobookshelf libraries the API key’s user can access, with ' +
|
|
21
|
+
'their id, name and media type (book or podcast). Start here — every ' +
|
|
22
|
+
'other library tool needs a library id.',
|
|
23
|
+
inputSchema: {
|
|
24
|
+
detail: detailParam,
|
|
25
|
+
},
|
|
26
|
+
annotations: { readOnlyHint: true },
|
|
27
|
+
}, async ({ detail }) => run(async () => {
|
|
28
|
+
const libraries = listFrom(await api.get('/api/libraries'), 'libraries');
|
|
29
|
+
return jsonResult({
|
|
30
|
+
libraries: detail === 'full' ? libraries : libraries.map(compactLibrary),
|
|
31
|
+
});
|
|
32
|
+
}));
|
|
33
|
+
server.registerTool('get_library', {
|
|
34
|
+
title: 'Get library',
|
|
35
|
+
description: 'Fetches a single library including its folders and scanner settings.',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
library_id: libraryIdParam,
|
|
38
|
+
detail: detailParam,
|
|
39
|
+
},
|
|
40
|
+
annotations: { readOnlyHint: true },
|
|
41
|
+
}, async ({ library_id, detail }) => run(async () => {
|
|
42
|
+
const data = await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}`);
|
|
43
|
+
const library = data.library ?? data;
|
|
44
|
+
return jsonResult(detail === 'full' ? library : compactLibrary(library));
|
|
45
|
+
}));
|
|
46
|
+
server.registerTool('get_library_stats', {
|
|
47
|
+
title: 'Get library stats',
|
|
48
|
+
description: 'Statistics for one library: number of items, authors and genres, total ' +
|
|
49
|
+
'duration and size, longest and largest items.',
|
|
50
|
+
inputSchema: {
|
|
51
|
+
library_id: libraryIdParam,
|
|
52
|
+
},
|
|
53
|
+
annotations: { readOnlyHint: true },
|
|
54
|
+
}, async ({ library_id }) => run(async () => {
|
|
55
|
+
const data = await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/stats`);
|
|
56
|
+
return jsonResult(data);
|
|
57
|
+
}));
|
|
58
|
+
server.registerTool('get_library_filter_data', {
|
|
59
|
+
title: 'Get library filter data',
|
|
60
|
+
description: 'Returns the values that can be filtered on in this library: authors, ' +
|
|
61
|
+
'genres, tags, series, narrators, languages and publishers, each with ' +
|
|
62
|
+
'the id or name to pass to list_library_items as filter_value.',
|
|
63
|
+
inputSchema: {
|
|
64
|
+
library_id: libraryIdParam,
|
|
65
|
+
},
|
|
66
|
+
annotations: { readOnlyHint: true },
|
|
67
|
+
}, async ({ library_id }) => run(async () => {
|
|
68
|
+
const data = await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/filterdata`);
|
|
69
|
+
return untrustedJsonResult(data);
|
|
70
|
+
}));
|
|
71
|
+
server.registerTool('list_library_items', {
|
|
72
|
+
title: 'List library items',
|
|
73
|
+
description: 'Lists items (books or podcasts) of a library, paginated, sortable and ' +
|
|
74
|
+
'filterable. Use get_library_filter_data first to learn the valid ' +
|
|
75
|
+
`filter values. Filter groups — ${describeFilterGroups()}.`,
|
|
76
|
+
inputSchema: {
|
|
77
|
+
library_id: libraryIdParam,
|
|
78
|
+
page: pageParam,
|
|
79
|
+
limit: limitParam(DEFAULT_ITEM_LIMIT),
|
|
80
|
+
sort: z.string().min(1).optional().describe(SORT_HINT),
|
|
81
|
+
descending: z
|
|
82
|
+
.boolean()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('Reverse the sort order, default false'),
|
|
85
|
+
filter_group: z
|
|
86
|
+
.enum(FILTER_GROUPS)
|
|
87
|
+
.optional()
|
|
88
|
+
.describe('Filter group. The server encodes group and value into the ' +
|
|
89
|
+
'base64 form its API expects.'),
|
|
90
|
+
filter_value: z
|
|
91
|
+
.string()
|
|
92
|
+
.min(1)
|
|
93
|
+
.optional()
|
|
94
|
+
.describe('Value for filter_group: an id for authors/series, a name for ' +
|
|
95
|
+
'genres/tags/narrators/languages/publishers, one of ' +
|
|
96
|
+
`${PROGRESS_FILTER_VALUES.join('/')} for progress. Must be omitted ` +
|
|
97
|
+
'for the standalone groups.'),
|
|
98
|
+
collapse_series: z
|
|
99
|
+
.boolean()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe('Collapse books of the same series into one entry'),
|
|
102
|
+
detail: detailParam,
|
|
103
|
+
},
|
|
104
|
+
annotations: { readOnlyHint: true },
|
|
105
|
+
}, async ({ library_id, page, limit, sort, descending, filter_group, filter_value, collapse_series, detail, }) => run(async () => {
|
|
106
|
+
const effectiveLimit = limit ?? DEFAULT_ITEM_LIMIT;
|
|
107
|
+
const filter = filter_group === undefined
|
|
108
|
+
? undefined
|
|
109
|
+
: encodeFilter(filter_group, filter_value);
|
|
110
|
+
const data = await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/items` +
|
|
111
|
+
query({
|
|
112
|
+
limit: effectiveLimit,
|
|
113
|
+
page: page ?? 0,
|
|
114
|
+
sort,
|
|
115
|
+
desc: descending === true ? 1 : undefined,
|
|
116
|
+
filter,
|
|
117
|
+
// Minified items skip audio files and tracks server-side, which is
|
|
118
|
+
// both faster and much smaller than shaping the full objects here.
|
|
119
|
+
minified: 1,
|
|
120
|
+
collapseseries: collapse_series === true ? 1 : undefined,
|
|
121
|
+
}));
|
|
122
|
+
const shaped = compactItemPage(data, detail ?? 'compact');
|
|
123
|
+
const total = typeof shaped.total === 'number' ? shaped.total : 0;
|
|
124
|
+
const currentPage = page ?? 0;
|
|
125
|
+
const seen = (currentPage + 1) * effectiveLimit;
|
|
126
|
+
return untrustedJsonResult({
|
|
127
|
+
...shaped,
|
|
128
|
+
...(total > seen
|
|
129
|
+
? {
|
|
130
|
+
note: `${total} items match — call list_library_items with page=${currentPage + 1} for the next ${effectiveLimit}.`,
|
|
131
|
+
}
|
|
132
|
+
: {}),
|
|
133
|
+
});
|
|
134
|
+
}));
|
|
135
|
+
server.registerTool('search_library', {
|
|
136
|
+
title: 'Search a library',
|
|
137
|
+
description: 'Full-text search within one library. Matches books, podcasts, series, ' +
|
|
138
|
+
'authors, narrators and tags. Use this for "do I own X?" questions; use ' +
|
|
139
|
+
'list_library_items with a filter for "show me all X" questions.',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
library_id: libraryIdParam,
|
|
142
|
+
q: z.string().min(1).describe('Search query'),
|
|
143
|
+
limit: limitParam(DEFAULT_SEARCH_LIMIT),
|
|
144
|
+
detail: detailParam,
|
|
145
|
+
},
|
|
146
|
+
annotations: { readOnlyHint: true },
|
|
147
|
+
}, async ({ library_id, q, limit, detail }) => run(async () => {
|
|
148
|
+
const data = (await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/search` +
|
|
149
|
+
query({ q, limit: limit ?? DEFAULT_SEARCH_LIMIT })));
|
|
150
|
+
if (detail === 'full')
|
|
151
|
+
return untrustedJsonResult(data);
|
|
152
|
+
// The search response groups matches: book/podcast hits are wrapped in
|
|
153
|
+
// { libraryItem, matchKey, matchText }, the rest are plain entities.
|
|
154
|
+
const wrapped = (key) => Array.isArray(data[key]) ? data[key] : [];
|
|
155
|
+
return untrustedJsonResult({
|
|
156
|
+
book: wrapped('book').map((entry) => {
|
|
157
|
+
const hit = entry;
|
|
158
|
+
return {
|
|
159
|
+
matchKey: hit.matchKey,
|
|
160
|
+
matchText: hit.matchText,
|
|
161
|
+
libraryItem: compactLibraryItem(hit.libraryItem),
|
|
162
|
+
};
|
|
163
|
+
}),
|
|
164
|
+
podcast: wrapped('podcast').map((entry) => {
|
|
165
|
+
const hit = entry;
|
|
166
|
+
return {
|
|
167
|
+
matchKey: hit.matchKey,
|
|
168
|
+
matchText: hit.matchText,
|
|
169
|
+
libraryItem: compactLibraryItem(hit.libraryItem),
|
|
170
|
+
};
|
|
171
|
+
}),
|
|
172
|
+
series: wrapped('series').map((entry) => {
|
|
173
|
+
const hit = entry;
|
|
174
|
+
return compactSeries(hit.series ?? hit);
|
|
175
|
+
}),
|
|
176
|
+
authors: wrapped('authors').map((a) => compactAuthor(a)),
|
|
177
|
+
narrators: wrapped('narrators'),
|
|
178
|
+
tags: wrapped('tags'),
|
|
179
|
+
});
|
|
180
|
+
}));
|
|
181
|
+
server.registerTool('get_personalized_shelves', {
|
|
182
|
+
title: 'Get personalized shelves',
|
|
183
|
+
description: 'The shelves of the Audiobookshelf home screen for this user: Continue ' +
|
|
184
|
+
'Listening, Continue Series, Recently Added, Newest Episodes, Listen ' +
|
|
185
|
+
'Again and so on. The fastest answer to "what am I listening to right now?".',
|
|
186
|
+
inputSchema: {
|
|
187
|
+
library_id: libraryIdParam,
|
|
188
|
+
limit: limitParam(10),
|
|
189
|
+
detail: detailParam,
|
|
190
|
+
},
|
|
191
|
+
annotations: { readOnlyHint: true },
|
|
192
|
+
}, async ({ library_id, limit, detail }) => run(async () => {
|
|
193
|
+
const data = (await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/personalized` +
|
|
194
|
+
query({ limit: limit ?? 10 })));
|
|
195
|
+
if (detail === 'full')
|
|
196
|
+
return untrustedJsonResult(data);
|
|
197
|
+
const shelves = Array.isArray(data) ? data : [];
|
|
198
|
+
return untrustedJsonResult(shelves.map((entry) => {
|
|
199
|
+
const shelf = entry;
|
|
200
|
+
const entities = Array.isArray(shelf.entities)
|
|
201
|
+
? shelf.entities
|
|
202
|
+
: [];
|
|
203
|
+
return {
|
|
204
|
+
id: shelf.id,
|
|
205
|
+
label: shelf.label,
|
|
206
|
+
type: shelf.type,
|
|
207
|
+
// Shelves hold library items, episodes, series or authors
|
|
208
|
+
// depending on `type`; the item projection covers the first two
|
|
209
|
+
// and passes the rest through unchanged.
|
|
210
|
+
entities: entities.map((entity) => shelf.type === 'book' || shelf.type === 'podcast'
|
|
211
|
+
? compactLibraryItem(entity)
|
|
212
|
+
: entity),
|
|
213
|
+
};
|
|
214
|
+
}));
|
|
215
|
+
}));
|
|
216
|
+
server.registerTool('list_series', {
|
|
217
|
+
title: 'List series',
|
|
218
|
+
description: 'Lists the series of a book library with their number of books and total ' +
|
|
219
|
+
'duration. To list the books of one series, call list_library_items with ' +
|
|
220
|
+
'filter_group="series" and filter_value=<series id>.',
|
|
221
|
+
inputSchema: {
|
|
222
|
+
library_id: libraryIdParam,
|
|
223
|
+
page: pageParam,
|
|
224
|
+
limit: limitParam(DEFAULT_ITEM_LIMIT),
|
|
225
|
+
sort: z
|
|
226
|
+
.string()
|
|
227
|
+
.min(1)
|
|
228
|
+
.optional()
|
|
229
|
+
.describe('Sort key, e.g. name, numBooks, addedAt, totalDuration'),
|
|
230
|
+
descending: z.boolean().optional().describe('Reverse the sort order'),
|
|
231
|
+
detail: detailParam,
|
|
232
|
+
},
|
|
233
|
+
annotations: { readOnlyHint: true },
|
|
234
|
+
}, async ({ library_id, page, limit, sort, descending, detail }) => run(async () => {
|
|
235
|
+
const data = (await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/series` +
|
|
236
|
+
query({
|
|
237
|
+
limit: limit ?? DEFAULT_ITEM_LIMIT,
|
|
238
|
+
page: page ?? 0,
|
|
239
|
+
sort,
|
|
240
|
+
desc: descending === true ? 1 : undefined,
|
|
241
|
+
minified: 1,
|
|
242
|
+
})));
|
|
243
|
+
const results = listFrom(data, 'series');
|
|
244
|
+
return untrustedJsonResult({
|
|
245
|
+
total: data.total,
|
|
246
|
+
page: data.page,
|
|
247
|
+
limit: data.limit,
|
|
248
|
+
// Without includeBooks: the endpoint embeds every book of every series,
|
|
249
|
+
// which dwarfs the series data itself.
|
|
250
|
+
results: detail === 'full' ? results : results.map((s) => compactSeries(s)),
|
|
251
|
+
});
|
|
252
|
+
}));
|
|
253
|
+
server.registerTool('get_series', {
|
|
254
|
+
title: 'Get series',
|
|
255
|
+
description: 'Fetches a single series by id, including its books. To list the books ' +
|
|
256
|
+
'with paging and sorting, use list_library_items with ' +
|
|
257
|
+
'filter_group="series" instead.',
|
|
258
|
+
inputSchema: {
|
|
259
|
+
series_id: z.string().min(1).describe('Series id'),
|
|
260
|
+
detail: detailParam,
|
|
261
|
+
},
|
|
262
|
+
annotations: { readOnlyHint: true },
|
|
263
|
+
}, async ({ series_id, detail }) => run(async () => {
|
|
264
|
+
const data = await api.get(`/api/series/${assertPathSegment(series_id, 'series_id')}`);
|
|
265
|
+
return untrustedJsonResult(detail === 'full' ? data : compactSeries(data, { includeBooks: true }));
|
|
266
|
+
}));
|
|
267
|
+
server.registerTool('list_authors', {
|
|
268
|
+
title: 'List authors',
|
|
269
|
+
description: 'Lists all authors of a book library with their number of books. To list ' +
|
|
270
|
+
'the books of one author, call list_library_items with ' +
|
|
271
|
+
'filter_group="authors" and filter_value=<author id>.',
|
|
272
|
+
inputSchema: {
|
|
273
|
+
library_id: libraryIdParam,
|
|
274
|
+
detail: detailParam,
|
|
275
|
+
},
|
|
276
|
+
annotations: { readOnlyHint: true },
|
|
277
|
+
}, async ({ library_id, detail }) => run(async () => {
|
|
278
|
+
const authors = listFrom(await api.get(`/api/libraries/${assertPathSegment(library_id, 'library_id')}/authors`), 'authors');
|
|
279
|
+
return untrustedJsonResult({
|
|
280
|
+
numAuthors: authors.length,
|
|
281
|
+
authors: detail === 'full' ? authors : authors.map((a) => compactAuthor(a)),
|
|
282
|
+
});
|
|
283
|
+
}));
|
|
284
|
+
server.registerTool('get_author', {
|
|
285
|
+
title: 'Get author',
|
|
286
|
+
description: 'Fetches a single author, optionally with the library items attributed ' +
|
|
287
|
+
'to them.',
|
|
288
|
+
inputSchema: {
|
|
289
|
+
author_id: z.string().min(1).describe('Author id'),
|
|
290
|
+
include_items: z
|
|
291
|
+
.boolean()
|
|
292
|
+
.optional()
|
|
293
|
+
.describe('Also return the author’s library items, default false'),
|
|
294
|
+
library_id: z
|
|
295
|
+
.string()
|
|
296
|
+
.min(1)
|
|
297
|
+
.optional()
|
|
298
|
+
.describe('Restrict the returned items to this library'),
|
|
299
|
+
detail: detailParam,
|
|
300
|
+
},
|
|
301
|
+
annotations: { readOnlyHint: true },
|
|
302
|
+
}, async ({ author_id, include_items, library_id, detail }) => run(async () => {
|
|
303
|
+
const data = await api.get(`/api/authors/${assertPathSegment(author_id, 'author_id')}` +
|
|
304
|
+
query({
|
|
305
|
+
include: include_items === true ? 'items' : undefined,
|
|
306
|
+
library: library_id === undefined
|
|
307
|
+
? undefined
|
|
308
|
+
: assertPathSegment(library_id, 'library_id'),
|
|
309
|
+
}));
|
|
310
|
+
return untrustedJsonResult(detail === 'full'
|
|
311
|
+
? data
|
|
312
|
+
: compactAuthor(data, { includeDescription: true }));
|
|
313
|
+
}));
|
|
314
|
+
server.registerTool('list_tags', {
|
|
315
|
+
title: 'List tags',
|
|
316
|
+
description: 'Lists all tags used on the server, across libraries. Tags are the ' +
|
|
317
|
+
'user-defined labels on library items.',
|
|
318
|
+
inputSchema: {},
|
|
319
|
+
annotations: { readOnlyHint: true },
|
|
320
|
+
}, async () => run(async () => untrustedJsonResult(await api.get('/api/tags'))));
|
|
321
|
+
server.registerTool('list_genres', {
|
|
322
|
+
title: 'List genres',
|
|
323
|
+
description: 'Lists all genres used on the server, across libraries. Genres come from ' +
|
|
324
|
+
'the media metadata, not from the user.',
|
|
325
|
+
inputSchema: {},
|
|
326
|
+
annotations: { readOnlyHint: true },
|
|
327
|
+
}, async () => run(async () => untrustedJsonResult(await api.get('/api/genres'))));
|
|
328
|
+
server.registerTool('get_server_status', {
|
|
329
|
+
title: 'Get server status',
|
|
330
|
+
description: 'Version and initialization state of the Audiobookshelf server. Useful ' +
|
|
331
|
+
'to check connectivity and whether the server is new enough for API keys ' +
|
|
332
|
+
'(2.26.0 or later).',
|
|
333
|
+
inputSchema: {},
|
|
334
|
+
annotations: { readOnlyHint: true },
|
|
335
|
+
}, async () => run(async () => jsonResult(await api.get('/status'))));
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=libraries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"libraries.js","sourceRoot":"","sources":["../../src/tools/libraries.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/me.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { assertPathSegment, query } from '../api.js';
|
|
3
|
+
import { jsonResult, run, untrustedJsonResult } from '../result.js';
|
|
4
|
+
import { detailParam, libraryItemIdParam, limitParam, pageParam, } from '../schema.js';
|
|
5
|
+
import { compactBookmark, compactLibraryItem, compactListeningSession, compactListeningStats, compactMediaProgress, compactUser, listFrom, } from '../shape.js';
|
|
6
|
+
const EPISODE_ID_DESCRIPTION = 'Podcast episode id — required for podcast episodes, omitted for books';
|
|
7
|
+
export function registerMeReadTools(server, api) {
|
|
8
|
+
server.registerTool('get_me', {
|
|
9
|
+
title: 'Get the current user',
|
|
10
|
+
description: 'Returns the Audiobookshelf user the API key acts on behalf of, with ' +
|
|
11
|
+
'their permissions and accessible libraries. The compact projection ' +
|
|
12
|
+
'reports media progress and bookmarks as counts — the full user object ' +
|
|
13
|
+
'embeds every single one of them.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
detail: detailParam,
|
|
16
|
+
},
|
|
17
|
+
annotations: { readOnlyHint: true },
|
|
18
|
+
}, async ({ detail }) => run(async () => {
|
|
19
|
+
const data = await api.get('/api/me');
|
|
20
|
+
return jsonResult(detail === 'full' ? data : compactUser(data));
|
|
21
|
+
}));
|
|
22
|
+
server.registerTool('list_items_in_progress', {
|
|
23
|
+
title: 'List items in progress',
|
|
24
|
+
description: 'The items the user has started but not finished, newest first — the ' +
|
|
25
|
+
'"Continue Listening" list across all libraries. The entries carry ' +
|
|
26
|
+
'progressLastUpdate but not the position itself; use get_media_progress ' +
|
|
27
|
+
'for that. For podcasts, recentEpisode names the episode in progress.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
limit: limitParam(25),
|
|
30
|
+
detail: detailParam,
|
|
31
|
+
},
|
|
32
|
+
annotations: { readOnlyHint: true },
|
|
33
|
+
}, async ({ limit, detail }) => run(async () => {
|
|
34
|
+
const data = await api.get(`/api/me/items-in-progress${query({ limit: limit ?? 25 })}`);
|
|
35
|
+
const items = listFrom(data, 'libraryItems');
|
|
36
|
+
return untrustedJsonResult({
|
|
37
|
+
numReturned: items.length,
|
|
38
|
+
libraryItems: detail === 'full' ? items : items.map((i) => compactLibraryItem(i)),
|
|
39
|
+
});
|
|
40
|
+
}));
|
|
41
|
+
server.registerTool('get_media_progress', {
|
|
42
|
+
title: 'Get media progress',
|
|
43
|
+
description: 'The listening progress of the current user for one book or podcast ' +
|
|
44
|
+
'episode: position, percentage and whether it is finished. Returns a 404 ' +
|
|
45
|
+
'error when the item has never been started.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
library_item_id: libraryItemIdParam,
|
|
48
|
+
episode_id: z
|
|
49
|
+
.string()
|
|
50
|
+
.min(1)
|
|
51
|
+
.optional()
|
|
52
|
+
.describe(EPISODE_ID_DESCRIPTION),
|
|
53
|
+
detail: detailParam,
|
|
54
|
+
},
|
|
55
|
+
annotations: { readOnlyHint: true },
|
|
56
|
+
}, async ({ library_item_id, episode_id, detail }) => run(async () => {
|
|
57
|
+
const path = `/api/me/progress/${assertPathSegment(library_item_id, 'library_item_id')}` +
|
|
58
|
+
(episode_id === undefined
|
|
59
|
+
? ''
|
|
60
|
+
: `/${assertPathSegment(episode_id, 'episode_id')}`);
|
|
61
|
+
const data = await api.get(path);
|
|
62
|
+
return jsonResult(detail === 'full' ? data : compactMediaProgress(data));
|
|
63
|
+
}));
|
|
64
|
+
server.registerTool('get_listening_stats', {
|
|
65
|
+
title: 'Get listening stats',
|
|
66
|
+
description: 'Aggregated listening statistics of the current user: total time, time ' +
|
|
67
|
+
'per weekday, the last 30 days, the ten most listened items and the ten ' +
|
|
68
|
+
'most recent sessions. detail="full" returns the complete per-day history ' +
|
|
69
|
+
'and the full metadata of every item ever listened to, which is the ' +
|
|
70
|
+
'largest response this API produces.',
|
|
71
|
+
inputSchema: {
|
|
72
|
+
detail: detailParam,
|
|
73
|
+
},
|
|
74
|
+
annotations: { readOnlyHint: true },
|
|
75
|
+
}, async ({ detail }) => run(async () => {
|
|
76
|
+
const data = await api.get('/api/me/listening-stats');
|
|
77
|
+
return untrustedJsonResult(detail === 'full' ? data : compactListeningStats(data));
|
|
78
|
+
}));
|
|
79
|
+
server.registerTool('get_year_stats', {
|
|
80
|
+
title: 'Get stats for a year',
|
|
81
|
+
description: 'The "year in review" statistics of the current user for one calendar ' +
|
|
82
|
+
'year: books finished, time listened, top authors and genres.',
|
|
83
|
+
inputSchema: {
|
|
84
|
+
year: z
|
|
85
|
+
.number()
|
|
86
|
+
.int()
|
|
87
|
+
.min(2000)
|
|
88
|
+
.max(2100)
|
|
89
|
+
.describe('Calendar year, e.g. 2026'),
|
|
90
|
+
},
|
|
91
|
+
annotations: { readOnlyHint: true },
|
|
92
|
+
}, async ({ year }) => run(async () => untrustedJsonResult(await api.get(`/api/me/stats/year/${year}`))));
|
|
93
|
+
server.registerTool('list_listening_sessions', {
|
|
94
|
+
title: 'List listening sessions',
|
|
95
|
+
description: 'The playback sessions of the current user, newest first — each entry is ' +
|
|
96
|
+
'one listening stretch with device, position and time listened.',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
page: pageParam,
|
|
99
|
+
limit: limitParam(10),
|
|
100
|
+
detail: detailParam,
|
|
101
|
+
},
|
|
102
|
+
annotations: { readOnlyHint: true },
|
|
103
|
+
}, async ({ page, limit, detail }) => run(async () => {
|
|
104
|
+
const data = (await api.get('/api/me/listening-sessions' +
|
|
105
|
+
query({ page: page ?? 0, itemsPerPage: limit ?? 10 })));
|
|
106
|
+
const sessions = listFrom(data, 'sessions');
|
|
107
|
+
return untrustedJsonResult({
|
|
108
|
+
total: data.total,
|
|
109
|
+
numPages: data.numPages,
|
|
110
|
+
page: data.page,
|
|
111
|
+
sessions: detail === 'full'
|
|
112
|
+
? sessions
|
|
113
|
+
: sessions.map(compactListeningSession),
|
|
114
|
+
});
|
|
115
|
+
}));
|
|
116
|
+
server.registerTool('list_bookmarks', {
|
|
117
|
+
title: 'List bookmarks',
|
|
118
|
+
description: 'The bookmarks of the current user — either all of them, or those of one ' +
|
|
119
|
+
'library item. A bookmark is a named position in seconds.',
|
|
120
|
+
inputSchema: {
|
|
121
|
+
library_item_id: z
|
|
122
|
+
.string()
|
|
123
|
+
.min(1)
|
|
124
|
+
.optional()
|
|
125
|
+
.describe('Restrict the result to the bookmarks of this library item'),
|
|
126
|
+
detail: detailParam,
|
|
127
|
+
},
|
|
128
|
+
annotations: { readOnlyHint: true },
|
|
129
|
+
}, async ({ library_item_id, detail }) => run(async () => {
|
|
130
|
+
const path = library_item_id === undefined
|
|
131
|
+
? '/api/me/bookmarks'
|
|
132
|
+
: `/api/me/bookmarks/${assertPathSegment(library_item_id, 'library_item_id')}`;
|
|
133
|
+
const data = await api.get(path);
|
|
134
|
+
const bookmarks = listFrom(data, 'bookmarks');
|
|
135
|
+
return untrustedJsonResult({
|
|
136
|
+
numBookmarks: bookmarks.length,
|
|
137
|
+
bookmarks: detail === 'full' ? bookmarks : bookmarks.map(compactBookmark),
|
|
138
|
+
});
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=me.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.js","sourceRoot":"","sources":["../../src/tools/me.ts"],"names":[],"mappings":"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"}
|