import { breadc } from 'breadc'; import { version, description } from '../package.json'; import type { CliOptions } from './commands/types'; import { BgmClient } from './client'; import { parseBoolean, parseJsonObject, parseNumber, printJson, requireOption, toNumber } from './commands/utils'; const cli = breadc('bgmc', { version, description, i18n: 'en' }) .option('--access-token ', 'Bangumi access token') .option('--base-url ', 'Override Bangumi API base URL') .option('--user-agent ', 'Override User-Agent header'); function createClient(options: CliOptions) { return new BgmClient({ accessToken: options.accessToken || process.env.BGM_ACCESS_TOKEN, baseURL: options.baseUrl || process.env.BGM_BASE_URL, userAgent: options.userAgent || process.env.BGM_USER_AGENT }); } cli.command('calendar', '每日放送').action(async (options) => { const client = createClient(options); printJson(await client.calendar()); }); cli .command('search-subjects ', '条目搜索') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .option('--filter ', 'JSON filter payload', { cast: (value) => parseJsonObject(value, '--filter') }) .action(async (keyword, options) => { const client = createClient(options); printJson( await client.searchSubjects({ query: { limit: options.limit, offset: options.offset }, requestBody: { keyword, ...(options.filter === undefined ? {} : { filter: options.filter }) } } as Parameters[0]) ); }); cli .command('search-characters ', '角色搜索') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .option('--filter ', 'JSON filter payload', { cast: (value) => parseJsonObject(value, '--filter') }) .action(async (keyword, options) => { const client = createClient(options); printJson( await client.searchCharacters({ query: { limit: options.limit, offset: options.offset }, requestBody: { keyword, ...(options.filter === undefined ? {} : { filter: options.filter }) } } as Parameters[0]) ); }); cli .command('search-persons ', '人物搜索') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .option('--filter ', 'JSON filter payload', { cast: (value) => parseJsonObject(value, '--filter') }) .action(async (keyword, options) => { const client = createClient(options); printJson( await client.searchPersons({ query: { limit: options.limit, offset: options.offset }, requestBody: { keyword, ...(options.filter === undefined ? {} : { filter: options.filter }) } } as Parameters[0]) ); }); cli .command('subjects ', '浏览条目') .option('--cat ', 'Subject category', { cast: parseNumber }) .option('--series ', 'Whether the subject is a series', { cast: parseBoolean }) .option('--platform ', 'Game platform') .option('--sort ', 'Sort order, e.g. date or rank') .option('--year ', 'Year', { cast: parseNumber }) .option('--month ', 'Month', { cast: parseNumber }) .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (type, options) => { const client = createClient(options); printJson( await client.subjects({ type: toNumber(type, 'type'), cat: options.cat, series: options.series, platform: options.platform, sort: options.sort, year: options.year, month: options.month, limit: options.limit, offset: options.offset } as NonNullable[0]>) ); }); cli.command('subject ', '获取条目').action(async (id, options) => { const client = createClient(options); printJson(await client.subject(toNumber(id, 'subject_id'))); }); cli.command('subject-image ', 'Get Subject Image').action(async (id, type, options) => { const client = createClient(options); printJson(await client.subjectImage(toNumber(id, 'subject_id'), { type })); }); cli.command('subject-persons ', 'Get Subject Persons').action(async (id, options) => { const client = createClient(options); printJson(await client.subjectPersons(toNumber(id, 'subject_id'))); }); cli.command('subject-characters ', 'Get Subject Characters').action(async (id, options) => { const client = createClient(options); printJson(await client.subjectCharacters(toNumber(id, 'subject_id'))); }); cli.command('subject-related ', 'Get Subject Relations').action(async (id, options) => { const client = createClient(options); printJson(await client.subjectRelated(toNumber(id, 'subject_id'))); }); cli .command('episodes ', 'Get Episodes') .option('--type ', 'Episode type', { cast: parseNumber }) .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.episodes({ subject_id: toNumber(subjectId, 'subject_id'), type: options.type, limit: options.limit, offset: options.offset } as NonNullable[0]>) ); }); cli.command('episode ', 'Get Episode').action(async (id, options) => { const client = createClient(options); printJson(await client.episode(toNumber(id, 'episode_id'))); }); cli.command('character ', 'Get Character Detail').action(async (id, options) => { const client = createClient(options); printJson(await client.character(toNumber(id, 'character_id'))); }); cli .command('character-image ', 'Get Character Image') .action(async (id, type, options) => { const client = createClient(options); printJson(await client.characterImage(toNumber(id, 'character_id'), { type })); }); cli .command('character-subjects ', 'get character related subjects') .action(async (id, options) => { const client = createClient(options); printJson(await client.characterSubjects(toNumber(id, 'character_id'))); }); cli .command('character-persons ', 'get character related persons') .action(async (id, options) => { const client = createClient(options); printJson(await client.characterPersons(toNumber(id, 'character_id'))); }); cli .command('collect-character ', 'Collect character for current user') .action(async (id, options) => { const client = createClient(options); printJson(await client.collectCharacter(toNumber(id, 'character_id'))); }); cli .command('uncollect-character ', 'Uncollect character for current user') .action(async (id, options) => { const client = createClient(options); printJson(await client.uncollectCharacter(toNumber(id, 'character_id'))); }); cli.command('person ', 'Get Person').action(async (id, options) => { const client = createClient(options); printJson(await client.person(toNumber(id, 'person_id'))); }); cli.command('person-image ', 'Get Person Image').action(async (id, type, options) => { const client = createClient(options); printJson(await client.personImage(toNumber(id, 'person_id'), { type })); }); cli.command('person-subjects ', 'get person related subjects').action(async (id, options) => { const client = createClient(options); printJson(await client.personSubjects(toNumber(id, 'person_id'))); }); cli .command('person-characters ', 'get person related characters') .action(async (id, options) => { const client = createClient(options); printJson(await client.personCharacters(toNumber(id, 'person_id'))); }); cli .command('collect-person ', 'Collect person for current user') .action(async (id, options) => { const client = createClient(options); printJson(await client.collectPerson(toNumber(id, 'person_id'))); }); cli .command('uncollect-person ', 'Uncollect person for current user') .action(async (id, options) => { const client = createClient(options); printJson(await client.uncollectPerson(toNumber(id, 'person_id'))); }); cli.command('user ', 'Get User by name').action(async (username, options) => { const client = createClient(options); printJson(await client.user(username)); }); cli .command('user-avatar ', 'Get User Avatar by name') .action(async (username, type, options) => { const client = createClient(options); printJson(await client.userAvatar(username, { type })); }); cli.command('me', 'Get User').action(async (options) => { const client = createClient(options); printJson(await client.me()); }); cli .command('collections ', '获取用户收藏') .option('--subject-type ', 'Subject type', { cast: parseNumber }) .option('--type ', 'Collection type', { cast: parseNumber }) .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (username, options) => { const client = createClient(options); printJson( await client.getCollections(username, { subject_type: options.subjectType, type: options.type, limit: options.limit, offset: options.offset } as NonNullable[1]>) ); }); cli .command('collection ', '获取用户单个条目收藏') .action(async (username, subjectId, options) => { const client = createClient(options); printJson(await client.getCollection(username, toNumber(subjectId, 'subject_id'))); }); cli .command('upsert-collection ', '新增或修改用户单个条目收藏') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.upsertCollection( toNumber(subjectId, 'subject_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('patch-collection ', '修改用户单个收藏') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.patchCollection( toNumber(subjectId, 'subject_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('collection-episodes ', '章节收藏信息') .option('--episode-type ', 'Episode type', { cast: parseNumber }) .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.getCollectionEpisodes(toNumber(subjectId, 'subject_id'), { episode_type: options.episodeType, limit: options.limit, offset: options.offset } as NonNullable[1]>) ); }); cli .command('patch-collection-episodes ', '章节收藏信息') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.patchCollectionEpisodes( toNumber(subjectId, 'subject_id'), requireOption(options.body, '--body') as never ) ); }); cli.command('episode-collection ', '章节收藏信息').action(async (episodeId, options) => { const client = createClient(options); printJson(await client.getEpisodeCollection(toNumber(episodeId, 'episode_id'))); }); cli .command('put-episode-collection ', '更新章节收藏信息') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (episodeId, options) => { const client = createClient(options); printJson( await client.putEpisodeCollection( toNumber(episodeId, 'episode_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('user-character-collections ', '获取用户角色收藏列表') .action(async (username, options) => { const client = createClient(options); printJson(await client.getCharacterCollections(username)); }); cli .command('user-character-collection ', '获取用户单个角色收藏信息') .action(async (username, characterId, options) => { const client = createClient(options); printJson(await client.getCharacterCollection(username, toNumber(characterId, 'character_id'))); }); cli .command('user-person-collections ', '获取用户人物收藏列表') .action(async (username, options) => { const client = createClient(options); printJson(await client.getPersonCollections(username)); }); cli .command('user-person-collection ', '获取用户单个人物收藏信息') .action(async (username, personId, options) => { const client = createClient(options); printJson(await client.getPersonCollection(username, toNumber(personId, 'person_id'))); }); cli .command('person-revisions ', 'Get Person Revisions') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (personId, options) => { const client = createClient(options); printJson( await client.personRevisions({ person_id: toNumber(personId, 'person_id'), limit: options.limit, offset: options.offset }) ); }); cli.command('person-revision ', 'Get Person Revision').action(async (id, options) => { const client = createClient(options); printJson(await client.personRevision(toNumber(id, 'revision_id'))); }); cli .command('character-revisions ', 'Get Character Revisions') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (characterId, options) => { const client = createClient(options); printJson( await client.characterRevisions({ character_id: toNumber(characterId, 'character_id'), limit: options.limit, offset: options.offset }) ); }); cli.command('character-revision ', 'Get Character Revision').action(async (id, options) => { const client = createClient(options); printJson(await client.characterRevision(toNumber(id, 'revision_id'))); }); cli .command('subject-revisions ', 'Get Subject Revisions') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (subjectId, options) => { const client = createClient(options); printJson( await client.subjectRevisions({ subject_id: toNumber(subjectId, 'subject_id'), limit: options.limit, offset: options.offset }) ); }); cli.command('subject-revision ', 'Get Subject Revision').action(async (id, options) => { const client = createClient(options); printJson(await client.subjectRevision(toNumber(id, 'revision_id'))); }); cli .command('episode-revisions ', 'Get Episode Revisions') .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (episodeId, options) => { const client = createClient(options); printJson( await client.episodeRevisions({ episode_id: toNumber(episodeId, 'episode_id'), limit: options.limit, offset: options.offset }) ); }); cli.command('episode-revision ', 'Get Episode Revision').action(async (id, options) => { const client = createClient(options); printJson(await client.episodeRevision(toNumber(id, 'revision_id'))); }); cli.command('create-index', 'Create a new index').action(async (options) => { const client = createClient(options); printJson(await client.createIndex()); }); cli.command('index ', 'Get Index By ID').action(async (id, options) => { const client = createClient(options); printJson(await client.index(toNumber(id, 'index_id'))); }); cli .command('edit-index ', "Edit index's information") .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (id, options) => { const client = createClient(options); printJson( await client.editIndex( toNumber(id, 'index_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('index-subjects ', 'Get Index Subjects') .option('--type ', 'Subject type', { cast: parseNumber }) .option('--limit ', 'Page size', { cast: parseNumber }) .option('--offset ', 'Page offset', { cast: parseNumber }) .action(async (id, options) => { const client = createClient(options); printJson( await client.indexSubjects(toNumber(id, 'index_id'), { type: options.type, limit: options.limit, offset: options.offset } as NonNullable[1]>) ); }); cli .command('add-index-subject ', 'Add a subject to Index') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (id, options) => { const client = createClient(options); printJson( await client.addIndexSubject( toNumber(id, 'index_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('edit-index-subject ', 'Edit subject information in a index') .option('--body ', 'JSON request body', { cast: (value) => parseJsonObject(value, '--body') }) .action(async (indexId, subjectId, options) => { const client = createClient(options); printJson( await client.editIndexSubject( toNumber(indexId, 'index_id'), toNumber(subjectId, 'subject_id'), requireOption(options.body, '--body') as never ) ); }); cli .command('delete-index-subject ', 'Delete a subject from a Index') .action(async (indexId, subjectId, options) => { const client = createClient(options); printJson( await client.deleteIndexSubject( toNumber(indexId, 'index_id'), toNumber(subjectId, 'subject_id') ) ); }); cli.command('collect-index ', 'Collect index for current user').action(async (id, options) => { const client = createClient(options); printJson(await client.collectIndex(toNumber(id, 'index_id'))); }); cli .command('uncollect-index ', 'Uncollect index for current user') .action(async (id, options) => { const client = createClient(options); printJson(await client.uncollectIndex(toNumber(id, 'index_id'))); }); cli.run(process.argv.slice(2)).catch((err) => console.error(err));