import {
type Notification,
notifications,
} from "$lib/Data/AniList/notifications";
import { refreshAniListToken } from "$lib/Utility/anilistOauth";
import { siteUrl } from "$lib/Utility/appOrigin";
import { decryptFeedToken } from "$lib/Utility/feedToken";
const htmlEncode = (input: string) => {
return input.replace(/[\u00A0-\u9999<>&]/g, (i) => `${i.charCodeAt(0)};`);
};
const channel = (items: string) => `
AniList Notifications • due.moe
${siteUrl("/")}
Instantly view your AniList notifications via RSS!
${new Date().toUTCString()}
${new Date().toUTCString()}
en-US
${siteUrl("/favicon-196x196.png")}
${items}
`;
const render = (posts: Notification[] = []) =>
channel(
posts
.filter((notification: Notification) => notification.type !== undefined)
.map((notification: Notification) => {
let title = `${notification.user.name}${notification.context}`;
let link = `https://anilist.co/user/${notification.user.name}`;
const prettyType = notification.type
.toString()
.replace(/_/g, " ")
.toLowerCase()
.replace(/\w\S*/g, (text) => {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
try {
if (
!["FOLLOWING", "ACTIVITY_MESSAGE"].includes(
notification.type.toString(),
) &&
!notification.type.toString().includes("THREAD")
) {
link = `https://anilist.co/activity/${notification.activity.id}`;
} else if (notification.type.toString().includes("THREAD")) {
title += `${notification.thread.title}`;
link = `https://anilist.co/forum/thread/${notification.thread.id}`;
}
} catch {
return "";
}
return `-
${notification.id}
${htmlEncode(title)}
${link}
${notification.user.name}
${prettyType}
${new Date(notification.createdAt * 1000).toUTCString()}
`;
})
.join(""),
);
// Old feed URLs carried the tokens in clear (?token=&refresh=); they no longer
// resolve, so degrade to a single item nudging the user to re-copy the link
// instead of silently going empty.
const staleNotice = () =>
channel(`-
due-moe-feed-url-outdated
${htmlEncode("Your due.moe RSS feed URL is outdated — re-copy it from Settings")}
${siteUrl("/settings#feeds")}
${htmlEncode("This feed link no longer works. Open due.moe → Settings → RSS Feeds and copy the new URL into your reader.")}
${new Date().toUTCString()}
`);
const feed = (body: string) =>
new Response(body, {
headers: {
"Cache-Control": "max-age=0",
"Content-Type": "application/xml",
},
});
export const GET = async ({ url }) => {
const sealed = url.searchParams.get("feed");
const refreshToken = sealed ? await decryptFeedToken(sealed) : null;
if (!refreshToken) return feed(staleNotice());
const accessToken = await refreshAniListToken(refreshToken);
if (!accessToken) return feed(render());
const notification = await notifications(accessToken);
return feed(render(notification || []));
};