diff options
| author | Fuwn <[email protected]> | 2023-09-17 19:58:24 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-09-17 19:58:24 -0700 |
| commit | cd49dd513c27cb8d856d822dcc778a77cf7d670e (patch) | |
| tree | df75c622e91c7f3877cb740bbcabfd2aab121f1d /src | |
| parent | feat(oauth): refresh token route (diff) | |
| download | due.moe-cd49dd513c27cb8d856d822dcc778a77cf7d670e.tar.xz due.moe-cd49dd513c27cb8d856d822dcc778a77cf7d670e.zip | |
feat(routes): rss feed git status
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/AniList/notifications.ts | 62 | ||||
| -rw-r--r-- | src/routes/feeds/notifications/+server.ts | 58 |
2 files changed, 120 insertions, 0 deletions
diff --git a/src/lib/AniList/notifications.ts b/src/lib/AniList/notifications.ts new file mode 100644 index 00000000..8640e105 --- /dev/null +++ b/src/lib/AniList/notifications.ts @@ -0,0 +1,62 @@ +export interface Notification { + user: { + name: string; + avatar: { + large: string; + }; + }; + context: string; + id: number; + createdAt: number; + type: + | 'FOLLOWING' + | 'ACTIVITY_MESSAGE' + | 'ACTIVITY_MENTION' + | 'ACTIVITY_REPLY' + | 'ACTIVITY_REPLY_SUBSCRIBED' + | 'ACTIVITY_LIKE' + | 'ACTIVITY_REPLY_LIKE' + | 'THREAD_COMMENT_MENTION' + | 'THREAD_COMMENT_REPLY' + | 'THREAD_SUBSCRIBED' + | 'THREAD_COMMENT_LIKE' + | 'THREAD_LIKE'; +} + +export const notifications = async (accessToken: string): Promise<Notification[]> => { + const activityNotification = (type: string) => `... on ${type} { + id user { name avatar { large } } context createdAt type + }`; + const threadNotification = (type: string) => `... on ${type} { + id user { name avatar { large } } context createdAt type thread { title } + }`; + + return ( + await ( + await fetch('https://graphql.anilist.co', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken}`, + Accept: 'application/json' + }, + body: JSON.stringify({ + query: `{ Page(page: 1, perPage: 50) { notifications { + ${activityNotification('FollowingNotification')} + ${activityNotification('ActivityMessageNotification')} + ${activityNotification('ActivityMentionNotification')} + ${activityNotification('ActivityReplyNotification')} + ${activityNotification('ActivityReplySubscribedNotification')} + ${activityNotification('ActivityLikeNotification')} + ${activityNotification('ActivityReplyLikeNotification')} + ${threadNotification('ThreadCommentMentionNotification')} + ${threadNotification('ThreadCommentReplyNotification')} + ${threadNotification('ThreadCommentSubscribedNotification')} + ${threadNotification('ThreadCommentLikeNotification')} + ${threadNotification('ThreadLikeNotification')} + } } }` + }) + }) + ).json() + )['data']['Page']['notifications']; +}; diff --git a/src/routes/feeds/notifications/+server.ts b/src/routes/feeds/notifications/+server.ts new file mode 100644 index 00000000..b06aa1f3 --- /dev/null +++ b/src/routes/feeds/notifications/+server.ts @@ -0,0 +1,58 @@ +import { notifications, type Notification } from '$lib/AniList/notifications'; + +export const GET = async ({ url }) => { + const data = await notifications(url.searchParams.get('token') || 'null'); + const render = (posts: Notification[]) => `<?xml version="1.0" encoding="UTF-8" ?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <atom:link href="https://due.moe/feeds/notifications" rel="self" type="application/rss+xml" /> + <title>期限 | AniList Notifications</title> + <link>https://due.moe</link> + <description>Instantly view your AniList notifications via RSS!</description> + <pubDate>${new Date().toUTCString()}</pubDate> + <lastBuildDate>${new Date().toUTCString()}</lastBuildDate> + <language>en-US</language> + <image> + <url>https://due.moe/favicon-192x192.png</url> + <link>https://due.moe</link> + <title>期限 Logo</title> + </image> + ${posts + .map((notification: Notification) => { + let title = `${notification.user.name} ${notification.context}`; + const prettyType = notification.type + .toString() + .replace(/_/g, ' ') + .toLowerCase() + .replace(/\w\S*/g, (text) => { + return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase(); + }); + + if (notification.type.toString().includes('THREAD')) { + title += `${notification.thread.title}`; + } + + return `<item> +<guid>${notification.id}</guid> +<title>${title}</title> +<link>https://anilist.co/user/${notification.user.name}</link> +<author>${notification.user.name}</author> +<enclosure url="${notification.user.avatar.large}" type="image/png" /> +<category>${prettyType}</category> +<pubDate>${new Date( + notification.createdAt * 1000 + new Date().getTimezoneOffset() + ).toUTCString()}</pubDate> +</item>`; + }) + .join('')} + </channel> +</rss> +`; + + return new Response(render(data), { + headers: { + 'Cache-Control': `max-age=0, s-max-age=${600}`, + 'Content-Type': 'application/xml' + } + }); +}; |