aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Data/hololive.ts
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-10-09 00:41:20 -0700
committerFuwn <[email protected]>2024-10-09 00:41:43 -0700
commit998b63a35256ac985a5a2714dd1ca451af4dfd8a (patch)
tree50796121a9d5ab0330fdc5d7e098bda2860d9726 /src/lib/Data/hololive.ts
parentfeat(graphql): add badgeCount field (diff)
downloaddue.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.tar.xz
due.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.zip
chore(prettier): use spaces instead of tabs
Diffstat (limited to 'src/lib/Data/hololive.ts')
-rw-r--r--src/lib/Data/hololive.ts216
1 files changed, 108 insertions, 108 deletions
diff --git a/src/lib/Data/hololive.ts b/src/lib/Data/hololive.ts
index d389cff2..1617d6d8 100644
--- a/src/lib/Data/hololive.ts
+++ b/src/lib/Data/hololive.ts
@@ -1,130 +1,130 @@
// https://github.com/wabilin/holo-schedule
function mapNodeList<E extends Element, T>(list: NodeListOf<E>, mapper: (ele: E) => T): T[] {
- const ary: T[] = [];
- list.forEach((node) => {
- ary.push(mapper(node));
- });
+ const ary: T[] = [];
+ list.forEach((node) => {
+ ary.push(mapper(node));
+ });
- return ary;
+ return ary;
}
function selectTrimTextContent(ele: Element, selector: string): string {
- return ele.querySelector(selector)?.textContent?.trim() || '';
+ return ele.querySelector(selector)?.textContent?.trim() || '';
}
const livePreviewImageHosts: readonly string[] = [
- 'img.youtube.com',
- 'schedule-static.hololive.tv'
+ 'img.youtube.com',
+ 'schedule-static.hololive.tv'
] as const;
function hostOf(src: string) {
- return new URL(src).host;
+ return new URL(src).host;
}
function dataFromAThumbnail(thumb: Element) {
- const time = selectTrimTextContent(thumb, '.datetime');
- const name = selectTrimTextContent(thumb, '.name');
+ const time = selectTrimTextContent(thumb, '.datetime');
+ const name = selectTrimTextContent(thumb, '.name');
- const images = mapNodeList(thumb.querySelectorAll('img'), (img) => img.src);
+ const images = mapNodeList(thumb.querySelectorAll('img'), (img) => img.src);
- const avatarImages = images.filter((src) => hostOf(src) === 'yt3.ggpht.com');
- const livePreviewImage = images.find((src) => livePreviewImageHosts.includes(hostOf(src))) || '';
+ const avatarImages = images.filter((src) => hostOf(src) === 'yt3.ggpht.com');
+ const livePreviewImage = images.find((src) => livePreviewImageHosts.includes(hostOf(src))) || '';
- return {
- time,
- name,
- avatarImages,
- livePreviewImage
- };
+ return {
+ time,
+ name,
+ avatarImages,
+ livePreviewImage
+ };
}
interface LiveBlock {
- time: Date;
- streamer: string;
- avatarImages: string[];
- livePreviewImage: string;
- link: string;
- streaming: boolean;
+ time: Date;
+ streamer: string;
+ avatarImages: string[];
+ livePreviewImage: string;
+ link: string;
+ streaming: boolean;
}
function parseToLiveBlocks(html: string): LiveBlock[] {
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, 'text/html');
- const year = new Date().getFullYear().toString();
-
- const rows = doc.querySelectorAll('#all > .container > .row');
-
- let date = '';
- const lives: LiveBlock[] = [];
-
- rows.forEach((row) => {
- const dateDiv = row.querySelector('.holodule');
- if (dateDiv) {
- date = dateDiv.textContent?.replace(/\s+/g, '') || '';
- date = date.match(/\d+\/\d+/)![0].replace('/', '-');
- }
-
- const allThumbnail = row.querySelectorAll('a.thumbnail');
- allThumbnail.forEach((t) => {
- const thumbnail = t as HTMLAnchorElement;
- const link = thumbnail.href;
- const streaming = thumbnail.style.borderColor === 'red';
- // The dataFromAThumbnail function needs to be adjusted to work with the parsed document.
- const { time, name, avatarImages, livePreviewImage } = dataFromAThumbnail(thumbnail);
-
- lives.push({
- link,
- avatarImages,
- livePreviewImage,
- time: new Date(`${year}-${date}T${time}:00+09:00`),
- streamer: name,
- streaming
- });
- });
- });
-
- return lives;
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(html, 'text/html');
+ const year = new Date().getFullYear().toString();
+
+ const rows = doc.querySelectorAll('#all > .container > .row');
+
+ let date = '';
+ const lives: LiveBlock[] = [];
+
+ rows.forEach((row) => {
+ const dateDiv = row.querySelector('.holodule');
+ if (dateDiv) {
+ date = dateDiv.textContent?.replace(/\s+/g, '') || '';
+ date = date.match(/\d+\/\d+/)![0].replace('/', '-');
+ }
+
+ const allThumbnail = row.querySelectorAll('a.thumbnail');
+ allThumbnail.forEach((t) => {
+ const thumbnail = t as HTMLAnchorElement;
+ const link = thumbnail.href;
+ const streaming = thumbnail.style.borderColor === 'red';
+ // The dataFromAThumbnail function needs to be adjusted to work with the parsed document.
+ const { time, name, avatarImages, livePreviewImage } = dataFromAThumbnail(thumbnail);
+
+ lives.push({
+ link,
+ avatarImages,
+ livePreviewImage,
+ time: new Date(`${year}-${date}T${time}:00+09:00`),
+ streamer: name,
+ streaming
+ });
+ });
+ });
+
+ return lives;
}
export type StreamerImageDict = Record<string, string>;
type ImageStreamerDict = Record<string, string>;
function nextStreamerImageDict(liveBlocks: LiveBlock[], oldDict: StreamerImageDict) {
- const dict = { ...oldDict };
- liveBlocks.forEach(({ avatarImages: images, streamer }) => {
- dict[streamer] = images[0];
- });
+ const dict = { ...oldDict };
+ liveBlocks.forEach(({ avatarImages: images, streamer }) => {
+ dict[streamer] = images[0];
+ });
- return dict;
+ return dict;
}
function reverseDict(dict: StreamerImageDict): ImageStreamerDict {
- const reversed: ImageStreamerDict = {};
- Object.entries(dict).forEach(([streamer, img]) => {
- reversed[img] = streamer;
- });
+ const reversed: ImageStreamerDict = {};
+ Object.entries(dict).forEach(([streamer, img]) => {
+ reversed[img] = streamer;
+ });
- return reversed;
+ return reversed;
}
export interface LiveInfo {
- time: Date;
- link: string;
- videoId: string;
- streamer: string;
- livePreviewImage: string;
- guests: string[];
- streaming: boolean;
+ time: Date;
+ link: string;
+ videoId: string;
+ streamer: string;
+ livePreviewImage: string;
+ guests: string[];
+ streaming: boolean;
}
interface ParseResult {
- lives: LiveInfo[];
- dict: StreamerImageDict;
+ lives: LiveInfo[];
+ dict: StreamerImageDict;
}
function getVideoId(link: string): string {
- return link.replace('https://www.youtube.com/watch?v=', '');
+ return link.replace('https://www.youtube.com/watch?v=', '');
}
/**
@@ -133,30 +133,30 @@ function getVideoId(link: string): string {
* @returns - Lives schedule and updated dict
*/
export function parseScheduleHtml(html: string, storedDict: StreamerImageDict = {}): ParseResult {
- const liveBlocks = parseToLiveBlocks(html);
- const streamerImageDict = nextStreamerImageDict(liveBlocks, storedDict);
-
- const dict = reverseDict(streamerImageDict);
-
- const lives = liveBlocks.map((liveBlocks) => {
- const { streamer, avatarImages, time, link, livePreviewImage, streaming } = liveBlocks;
-
- const guests = avatarImages
- .splice(1)
- .map((x) => dict[x])
- .filter(Boolean);
- const videoId = getVideoId(link);
-
- return {
- time,
- streamer,
- guests,
- link,
- videoId,
- livePreviewImage,
- streaming
- };
- });
-
- return { lives, dict: streamerImageDict };
+ const liveBlocks = parseToLiveBlocks(html);
+ const streamerImageDict = nextStreamerImageDict(liveBlocks, storedDict);
+
+ const dict = reverseDict(streamerImageDict);
+
+ const lives = liveBlocks.map((liveBlocks) => {
+ const { streamer, avatarImages, time, link, livePreviewImage, streaming } = liveBlocks;
+
+ const guests = avatarImages
+ .splice(1)
+ .map((x) => dict[x])
+ .filter(Boolean);
+ const videoId = getVideoId(link);
+
+ return {
+ time,
+ streamer,
+ guests,
+ link,
+ videoId,
+ livePreviewImage,
+ streaming
+ };
+ });
+
+ return { lives, dict: streamerImageDict };
}