UNPKG

rsshub

Version:
153 lines (132 loc) 4.24 kB
import { config } from '@/config'; import { DataItem } from '@/types'; import cache from '@/utils/cache'; import ofetch from '@/utils/ofetch'; import { art } from '@/utils/render'; import path from 'node:path'; export const baseUrl = 'https://skeb.jp'; interface Work { path: string; private_thumbnail_image_urls: null | string; private: boolean; genre: string; tipped: boolean; creator_id: number; client_id: number; vtt_url: null | string; thumbnail_image_urls: { src: string; srcset: string; }; preview_url: null | string; duration: null | number; nsfw: boolean; hardcore: boolean; consored_thumbnail_image_urls: { src: string; srcset: string; }; body: string; nc: number; word_count: number; transcoder: string; creator_acceptable_same_genre: boolean; } interface Creator { id: number; creator: boolean; nsfw_acceptable: boolean; acceptable: boolean; name: string; screen_name: string; avatar_url: string; header_url: string | null; appeal_receivable: boolean; popular_creator_rank: number | null; request_master_rank: number | null; first_requester_rank: number | null; deleted_at: string | null; tip_acceptable_by: string; accept_expiration_days: number; skills: { genre: string }[]; nc: number; } export function processWork(work: Work): DataItem | null { if (!work || typeof work !== 'object' || work.private === true) { return null; } const imageUrl = work.thumbnail_image_urls?.srcset?.split(',').pop()?.trim().split(' ')[0] || ''; const body = work.body || ''; const audioUrl = work.genre === 'music' || work.genre === 'voice' ? work.preview_url : null; const renderedHtml = art(path.join(__dirname, 'templates/work.art'), { imageUrl, body, audioUrl, }); return { title: work.path || '', link: `${baseUrl}${work.path || ''}`, description: renderedHtml, }; } const skillMap = { art: 'Illust', voice: 'Voice', novel: 'Novel', video: 'Video', music: 'Music', correction: 'Advice', comic: 'Comic', }; export function processCreator(creator: Creator): DataItem | null { if (!creator || typeof creator !== 'object') { return null; } const avatarUrl = creator.avatar_url || ''; let renderedHtml; if (creator.creator) { const acceptingCommissions = creator.acceptable ? 'Yes' : 'No'; const nsfwAcceptable = creator.nsfw_acceptable ? 'Yes' : 'No'; let skills = ''; if (Array.isArray(creator.skills) && creator.skills.length > 0) { skills = creator.skills .map((skill) => skillMap[skill.genre] || skill.genre) .filter(Boolean) .join(', '); } renderedHtml = art(path.join(__dirname, 'templates/creator.art'), { avatarUrl, acceptingCommissions, nsfwAcceptable, skills, }); } return { title: creator.name || '', link: `${baseUrl}/@${creator.screen_name || ''}`, description: renderedHtml, }; } export async function getFollowingsItems(username: string, path: 'friend_works' | 'following_works' | 'following_creators'): Promise<DataItem[]> { const url = `${baseUrl}/api/users/${username.replace('@', '')}/followings`; const followings_data = await cache.tryGet( `skeb:followings_data:${username}`, async () => { const data = await ofetch(url, { headers: { Authorization: `Bearer ${config.skeb.bearerToken}`, }, }); return data; }, config.cache.routeExpire, false ); if (!followings_data || typeof followings_data !== 'object') { throw new Error('Failed to fetch followings data'); } if (path === 'following_creators') { return followings_data[path].map((item) => processCreator(item)).filter(Boolean) as DataItem[]; } return followings_data[path].map((item) => processWork(item)).filter(Boolean) as DataItem[]; }