feat(route): add Niconico Mylist (#19938)

This commit is contained in:
100の人 (エスパー・イーシア)
2025-08-31 22:57:10 +08:00
committed by GitHub
parent e95d69354f
commit 2dd175c9ff
3 changed files with 93 additions and 1 deletions
+39
View File
@@ -0,0 +1,39 @@
import { DataItem, Route } from '@/types';
import { getMylist, renderVideo } from './utils';
import { parseDate } from '@/utils/parse-date';
export const route: Route = {
name: 'Mylist',
path: '/mylist/:id',
parameters: { id: 'Mylist ID' },
example: '/nicovideo/mylist/2973737',
maintainers: ['esperecyan'],
radar: [
{
source: ['www.nicovideo.jp/user/:user/mylist/:id'],
target: '/mylist/:id',
},
],
handler: async (ctx) => {
const { id } = ctx.req.param();
const mylist = await getMylist(id);
return {
title: `マイリスト ${mylist.name}‐ニコニコ動画`,
link: `https://www.nicovideo.jp/user/${mylist.owner.id}/mylist/${mylist.id}`,
language: 'ja',
item: mylist.items.map(
(item): DataItem => ({
title: item.video.title,
link: `https://www.nicovideo.jp/watch/${item.video.id}`,
pubDate: parseDate(item.addedAt),
author: [{ name: item.video.owner.name, avatar: item.video.owner.iconUrl, url: `https://www.nicovideo.jp/user/${item.video.owner.id}` }],
description: renderVideo(item.video, false),
image: item.video.thumbnail.nHdUrl ?? item.video.thumbnail.largeUrl ?? item.video.thumbnail.middleUrl ?? undefined,
})
),
};
},
};
+27
View File
@@ -52,3 +52,30 @@ export interface VideoItem {
series: null;
essential: Essential;
}
export type Mylist = {
id: number;
name: string;
description: string;
decoratedDescriptionHtml: string;
defaultSortKey: string;
defaultSortOrder: string;
items: MylistItem[];
totalItemCount: number;
hasNext: boolean;
isPublic: boolean;
owner: Owner;
hasInvisibleItems: boolean;
followerCount: number;
isFollowing: boolean;
};
type MylistItem = {
itemId: number;
watchId: string;
description: string;
decoratedDescriptionHtml: string;
addedAt: string;
status: string;
video: Essential;
};
+27 -1
View File
@@ -1,4 +1,4 @@
import { Essential, UserInfo, VideoItem } from './types';
import { Essential, Mylist, UserInfo, VideoItem } from './types';
import ofetch from '@/utils/ofetch';
import cache from '@/utils/cache';
@@ -31,4 +31,30 @@ export const getUserVideosById = (id: string) =>
false
) as Promise<VideoItem[]>;
export const getMylist = (id: string): Promise<Mylist> =>
cache.tryGet<Mylist>(
`nicovideo:mylist:${id}`,
async () => {
const { data } = await ofetch(`https://nvapi.nicovideo.jp/v2/mylists/${id}`, {
headers: {
'X-Frontend-Id': '6',
},
query: {
sortKey: 'addedAt',
sortOrder: 'desc',
/**
* @remarks
* Up to 500 items can be registered in a single mylist.
* @see https://qa.nicovideo.jp/faq/show/648?site_domain=default
*/
pageSize: 500,
page: 1,
},
});
return data.mylist;
},
config.cache.routeExpire,
false
);
export const renderVideo = (video: Essential, embed: boolean) => art(path.join(__dirname, 'templates/video.art'), { video, embed });