From 50a0f0240d7fef133eb5acc1bea2b1168b08e9db Mon Sep 17 00:00:00 2001 From: Factiven Date: Sun, 24 Dec 2023 13:03:54 +0700 Subject: migrate to typescript --- utils/appendMetaToEpisodes.js | 28 -------- utils/appendMetaToEpisodes.ts | 51 ++++++++++++++ utils/combineImages.js | 26 ------- utils/combineImages.ts | 43 ++++++++++++ utils/getFormat.js | 17 ----- utils/getFormat.ts | 17 +++++ utils/getGreetings.js | 16 ----- utils/getGreetings.ts | 16 +++++ utils/getRedisWithPrefix.js | 84 ---------------------- utils/getRedisWithPrefix.ts | 86 +++++++++++++++++++++++ utils/getTimes.js | 143 ------------------------------------- utils/getTimes.ts | 159 ++++++++++++++++++++++++++++++++++++++++++ utils/imageUtils.js | 38 ---------- utils/imageUtils.ts | 55 +++++++++++++++ utils/parseMetaData.ts | 36 ++++++++++ utils/request/index.ts | 111 +++++++++++++++++++++++++++++ utils/schedulesUtils.js | 83 ---------------------- utils/schedulesUtils.ts | 96 +++++++++++++++++++++++++ utils/useCountdownSeconds.js | 37 ---------- 19 files changed, 670 insertions(+), 472 deletions(-) delete mode 100644 utils/appendMetaToEpisodes.js create mode 100644 utils/appendMetaToEpisodes.ts delete mode 100644 utils/combineImages.js create mode 100644 utils/combineImages.ts delete mode 100644 utils/getFormat.js create mode 100644 utils/getFormat.ts delete mode 100644 utils/getGreetings.js create mode 100644 utils/getGreetings.ts delete mode 100644 utils/getRedisWithPrefix.js create mode 100644 utils/getRedisWithPrefix.ts delete mode 100644 utils/getTimes.js create mode 100644 utils/getTimes.ts delete mode 100644 utils/imageUtils.js create mode 100644 utils/imageUtils.ts create mode 100644 utils/parseMetaData.ts create mode 100644 utils/request/index.ts delete mode 100644 utils/schedulesUtils.js create mode 100644 utils/schedulesUtils.ts delete mode 100644 utils/useCountdownSeconds.js (limited to 'utils') diff --git a/utils/appendMetaToEpisodes.js b/utils/appendMetaToEpisodes.js deleted file mode 100644 index 197788b..0000000 --- a/utils/appendMetaToEpisodes.js +++ /dev/null @@ -1,28 +0,0 @@ -async function appendMetaToEpisodes(episodesData, images) { - // Create a dictionary for faster lookup of images based on episode number - const episodeImages = {}; - images.forEach((image) => { - episodeImages[image.number || image.episode] = image; - }); - - // Iterate through each provider's episodes data - for (const providerEpisodes of episodesData) { - // Iterate through each episode in the provider's episodes data - for (const episode of providerEpisodes.episodes) { - // Get the episode number - const episodeNumber = episode.number; - - // Check if there is an image available for this episode number - if (episodeImages[episodeNumber]) { - // Append the image URL to the episode data - episode.img = episodeImages[episodeNumber].img; - episode.title = episodeImages[episodeNumber].title; - episode.description = episodeImages[episodeNumber].description; - } - } - } - - return episodesData; -} - -export default appendMetaToEpisodes; diff --git a/utils/appendMetaToEpisodes.ts b/utils/appendMetaToEpisodes.ts new file mode 100644 index 0000000..5f74df3 --- /dev/null +++ b/utils/appendMetaToEpisodes.ts @@ -0,0 +1,51 @@ +type Image = { + number?: number; + episode?: number; + img: string; + title: string; + description: string; +}; + +type Episode = { + number: number; + img?: string; + title?: string; + description?: string; +}; + +type ProviderEpisodes = { + episodes: Episode[]; +}; + +async function appendMetaToEpisodes( + episodesData: ProviderEpisodes[], + images: Image[] +): Promise { + // Create a dictionary for faster lookup of images based on episode number + const episodeImages: { [key: number]: Image } = {}; + images.forEach((image) => { + image.episode && (episodeImages[image.episode] = image); + image.number && (episodeImages[image.number] = image); + }); + + // Iterate through each provider's episodes data + for (const providerEpisodes of episodesData) { + // Iterate through each episode in the provider's episodes data + for (const episode of providerEpisodes.episodes) { + // Get the episode number + const episodeNumber = episode.number; + + // Check if there is an image available for this episode number + if (episodeImages[episodeNumber]) { + // Append the image URL to the episode data + episode.img = episodeImages[episodeNumber].img; + episode.title = episodeImages[episodeNumber].title; + episode.description = episodeImages[episodeNumber].description; + } + } + } + + return episodesData; +} + +export default appendMetaToEpisodes; diff --git a/utils/combineImages.js b/utils/combineImages.js deleted file mode 100644 index abf34ed..0000000 --- a/utils/combineImages.js +++ /dev/null @@ -1,26 +0,0 @@ -async function appendImagesToEpisodes(episodesData, images) { - // Create a dictionary for faster lookup of images based on episode number - const episodeImages = {}; - images.forEach((image) => { - episodeImages[image.episode] = image.img; - }); - - // Iterate through each provider's episodes data - for (const providerEpisodes of episodesData) { - // Iterate through each episode in the provider's episodes data - for (const episode of providerEpisodes.episodes) { - // Get the episode number - const episodeNumber = episode.number; - - // Check if there is an image available for this episode number - if (episodeImages[episodeNumber]) { - // Append the image URL to the episode data - episode.img = episodeImages[episodeNumber]; - } - } - } - - return episodesData; -} - -export default appendImagesToEpisodes; diff --git a/utils/combineImages.ts b/utils/combineImages.ts new file mode 100644 index 0000000..01b7ef3 --- /dev/null +++ b/utils/combineImages.ts @@ -0,0 +1,43 @@ +interface Image { + episode: number; + img: string; +} + +interface Episode { + number: number; + img?: string; +} + +interface ProviderEpisodes { + episodes: Episode[]; +} + +async function appendImagesToEpisodes( + episodesData: ProviderEpisodes[], + images: Image[] +) { + // Create a dictionary for faster lookup of images based on episode number + const episodeImages: { [key: number]: string } = {}; + images.forEach((image) => { + episodeImages[image.episode] = image.img; + }); + + // Iterate through each provider's episodes data + for (const providerEpisodes of episodesData) { + // Iterate through each episode in the provider's episodes data + for (const episode of providerEpisodes.episodes) { + // Get the episode number + const episodeNumber = episode.number; + + // Check if there is an image available for this episode number + if (episodeImages[episodeNumber]) { + // Append the image URL to the episode data + episode.img = episodeImages[episodeNumber]; + } + } + } + + return episodesData; +} + +export default appendImagesToEpisodes; diff --git a/utils/getFormat.js b/utils/getFormat.js deleted file mode 100644 index 9a2e3e3..0000000 --- a/utils/getFormat.js +++ /dev/null @@ -1,17 +0,0 @@ -const data = [ - { name: "TV Show", value: "TV" }, - { name: "TV Short", value: "TV_SHORT" }, - { name: "Movie", value: "MOVIE" }, - { name: "Special", value: "SPECIAL" }, - { name: "OVA", value: "OVA" }, - { name: "ONA", value: "ONA" }, - { name: "Music", value: "MUSIC" }, - { name: "Manga", value: "MANGA" }, - { name: "Novel", value: "NOVEL" }, - { name: "One Shot", value: "ONE_SHOT" }, -]; - -export function getFormat(format) { - const results = data.find((item) => item.value === format); - return results?.name; -} diff --git a/utils/getFormat.ts b/utils/getFormat.ts new file mode 100644 index 0000000..7f3eece --- /dev/null +++ b/utils/getFormat.ts @@ -0,0 +1,17 @@ +const data = [ + { name: "TV Show", value: "TV" }, + { name: "TV Short", value: "TV_SHORT" }, + { name: "Movie", value: "MOVIE" }, + { name: "Special", value: "SPECIAL" }, + { name: "OVA", value: "OVA" }, + { name: "ONA", value: "ONA" }, + { name: "Music", value: "MUSIC" }, + { name: "Manga", value: "MANGA" }, + { name: "Novel", value: "NOVEL" }, + { name: "One Shot", value: "ONE_SHOT" }, +]; + +export function getFormat(format: string) { + const results = data.find((item) => item.value === format); + return results?.name; +} diff --git a/utils/getGreetings.js b/utils/getGreetings.js deleted file mode 100644 index 1dd2a53..0000000 --- a/utils/getGreetings.js +++ /dev/null @@ -1,16 +0,0 @@ -export const getGreetings = () => { - const time = new Date().getHours(); - let greeting = ""; - - if (time >= 5 && time < 12) { - greeting = "Good morning"; - } else if (time >= 12 && time < 18) { - greeting = "Good afternoon"; - } else if (time >= 18 && time < 22) { - greeting = "Good evening"; - } else if (time >= 22 || time < 5) { - greeting = "Good night"; - } - - return greeting; -}; diff --git a/utils/getGreetings.ts b/utils/getGreetings.ts new file mode 100644 index 0000000..1dd2a53 --- /dev/null +++ b/utils/getGreetings.ts @@ -0,0 +1,16 @@ +export const getGreetings = () => { + const time = new Date().getHours(); + let greeting = ""; + + if (time >= 5 && time < 12) { + greeting = "Good morning"; + } else if (time >= 12 && time < 18) { + greeting = "Good afternoon"; + } else if (time >= 18 && time < 22) { + greeting = "Good evening"; + } else if (time >= 22 || time < 5) { + greeting = "Good night"; + } + + return greeting; +}; diff --git a/utils/getRedisWithPrefix.js b/utils/getRedisWithPrefix.js deleted file mode 100644 index b85589b..0000000 --- a/utils/getRedisWithPrefix.js +++ /dev/null @@ -1,84 +0,0 @@ -import { redis } from "@/lib/redis"; - -export async function getValuesWithPrefix(prefix) { - let cursor = "0"; // Start at the beginning of the keyspace - let values = []; - - do { - const [newCursor, matchingKeys] = await redis.scan( - cursor, - "MATCH", - prefix + "*", - "COUNT", - 100 - ); - - // Retrieve values for matching keys and add them to the array - for (const key of matchingKeys) { - const value = await redis.get(key); - values.push(JSON.parse(value)); - } - - // Update the cursor for the next iteration - cursor = newCursor; - } while (cursor !== "0"); // Continue until the cursor is '0' - - return values; -} - -export async function countKeysWithPrefix(prefix) { - let cursor = "0"; // Start at the beginning of the keyspace - let count = 0; - - do { - const [newCursor, matchingKeys] = await redis.scan( - cursor, - "MATCH", - prefix + "*", - "COUNT", - 100 - ); - - // Increment the count by the number of matching keys in this iteration - count += matchingKeys.length; - - // Update the cursor for the next iteration - cursor = newCursor; - } while (cursor !== "0"); // Continue until the cursor is '0' - - return count; -} - -export async function getValuesWithNumericKeys() { - const allKeys = await redis.keys("*"); // Fetch all keys in Redis - const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers - - const values = []; - - for (const key of numericKeys) { - const value = await redis.get(key); // Retrieve the value for each numeric key - values.push(value); - } - - return values; -} - -export async function getKeysWithNumericKeys() { - const allKeys = await redis.keys("*"); // Fetch all keys in Redis - const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers - - const values = []; - - for (const key of numericKeys) { - const value = await redis.del(key); - } - - return values; -} - -export async function countNumericKeys() { - const allKeys = await redis.keys("*"); // Fetch all keys in Redis - const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers - - return numericKeys.length; // Return the count of numeric keys -} diff --git a/utils/getRedisWithPrefix.ts b/utils/getRedisWithPrefix.ts new file mode 100644 index 0000000..dacf78e --- /dev/null +++ b/utils/getRedisWithPrefix.ts @@ -0,0 +1,86 @@ +import { redis } from "@/lib/redis"; + +export async function getValuesWithPrefix(prefix: string) { + let cursor = "0"; // Start at the beginning of the keyspace + let values = []; + + do { + const [newCursor, matchingKeys] = await redis.scan( + cursor, + "MATCH", + prefix + "*", + "COUNT", + 100 + ); + + // Retrieve values for matching keys and add them to the array + for (const key of matchingKeys) { + const value = await redis.get(key); + if (value !== null) { + values.push(JSON.parse(value)); + } + } + + // Update the cursor for the next iteration + cursor = newCursor; + } while (cursor !== "0"); // Continue until the cursor is '0' + + return values; +} + +export async function countKeysWithPrefix(prefix: string) { + let cursor = "0"; // Start at the beginning of the keyspace + let count = 0; + + do { + const [newCursor, matchingKeys] = await redis.scan( + cursor, + "MATCH", + prefix + "*", + "COUNT", + 100 + ); + + // Increment the count by the number of matching keys in this iteration + count += matchingKeys.length; + + // Update the cursor for the next iteration + cursor = newCursor; + } while (cursor !== "0"); // Continue until the cursor is '0' + + return count; +} + +export async function getValuesWithNumericKeys() { + const allKeys = await redis.keys("*"); // Fetch all keys in Redis + const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers + + const values = []; + + for (const key of numericKeys) { + const value = await redis.get(key); // Retrieve the value for each numeric key + values.push(value); + } + + return values; +} + +export async function getKeysWithNumericKeys() { + const allKeys = await redis.keys("*"); // Fetch all keys in Redis + const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers + + const values: any[] = []; + + for (const key of numericKeys) { + await redis.del(key); + } + + return values; +} + +export async function countNumericKeys() { + const allKeys = await redis.keys("*"); // Fetch all keys in Redis + const numericKeys = allKeys.filter((key) => /^\d+$/.test(key)); // Filter keys that contain only numbers + + return numericKeys.length; // Return the count of numeric keys +} diff --git a/utils/getTimes.js b/utils/getTimes.js deleted file mode 100644 index 95df803..0000000 --- a/utils/getTimes.js +++ /dev/null @@ -1,143 +0,0 @@ -export function convertUnixToTime(timestamp) { - const date = new Date(timestamp); - const hours = date.getHours(); - const minutes = date.getMinutes(); - const ampm = hours >= 12 ? "PM" : "AM"; - const formattedHours = (hours % 12 || 12).toString().padStart(2, "0"); - const formattedMinutes = minutes.toString().padStart(2, "0"); - return `${formattedHours}:${formattedMinutes} ${ampm}`; -} - -export function getCurrentSeason() { - const now = new Date(); - const month = now.getMonth() + 1; // getMonth() returns 0-based index - - switch (month) { - case 12: - case 1: - case 2: - return "WINTER"; - case 3: - case 4: - case 5: - return "SPRING"; - case 6: - case 7: - case 8: - return "SUMMER"; - case 9: - case 10: - case 11: - return "FALL"; - default: - return "UNKNOWN SEASON"; - } -} - -export function convertUnixToCountdown(time) { - let date = new Date(time * 1000); - let days = date.getDay(); - let hours = date.getHours(); - let minutes = date.getMinutes(); - - let countdown = ""; - - if (days > 0) { - countdown += `${days}d `; - } - - if (hours > 0) { - countdown += `${hours}h `; - } - - if (minutes > 0) { - countdown += `${minutes}m `; - } - - return countdown.trim(); -} - -export function convertSecondsToTime(sec) { - let days = Math.floor(sec / (3600 * 24)); - let hours = Math.floor((sec % (3600 * 24)) / 3600); - let minutes = Math.floor((sec % 3600) / 60); - let seconds = Math.floor(sec % 60); - - let time = ""; - - if (days > 0) { - time += `${days}d `; - } - - if (hours > 0) { - time += `${hours}h `; - } - - if (minutes > 0) { - time += `${minutes}m `; - } - - if (days <= 0) { - time += `${seconds}s `; - } - - return time.trim(); -} - -// Function to convert timestamp to AM/PM time format -export const timeStamptoAMPM = (timestamp) => { - const date = new Date(timestamp * 1000); - const hours = date.getHours(); - const minutes = date.getMinutes(); - const ampm = hours >= 12 ? "PM" : "AM"; - const formattedHours = hours % 12 || 12; // Convert to 12-hour format - - return `${formattedHours}:${minutes.toString().padStart(2, "0")} ${ampm}`; -}; - -export const timeStamptoHour = (timestamp) => { - const options = { hour: "numeric", minute: "numeric", hour12: true }; - const currentTime = new Date().getTime() / 1000; - const formattedTime = new Date(timestamp * 1000).toLocaleTimeString( - undefined, - options - ); - const status = timestamp <= currentTime ? "aired" : "airing"; - - return `${status} at ${formattedTime}`; -}; - -export function unixTimestampToRelativeTime(unixTimestamp) { - const now = Math.floor(Date.now() / 1000); // Current Unix timestamp in seconds - let secondsDifference = now - unixTimestamp; - - const intervals = [ - { label: "year", seconds: 31536000 }, - { label: "month", seconds: 2592000 }, - { label: "week", seconds: 604800 }, - { label: "day", seconds: 86400 }, - { label: "hour", seconds: 3600 }, - { label: "minute", seconds: 60 }, - { label: "second", seconds: 1 }, - ]; - - const isFuture = secondsDifference < 0; - secondsDifference = Math.abs(secondsDifference); - - for (const interval of intervals) { - const count = Math.floor(secondsDifference / interval.seconds); - if (count >= 1) { - const label = count === 1 ? interval.label : `${interval.label}s`; - return isFuture ? `${count} ${label} from now` : `${count} ${label} ago`; - } - } - - return "just now"; -} - -export function unixToSeconds(unixTimestamp) { - const now = Math.floor(Date.now() / 1000); // Current Unix timestamp in seconds - const secondsAgo = now - unixTimestamp; - - return secondsAgo; -} diff --git a/utils/getTimes.ts b/utils/getTimes.ts new file mode 100644 index 0000000..c3fe0ad --- /dev/null +++ b/utils/getTimes.ts @@ -0,0 +1,159 @@ +export function convertUnixToTime(timestamp: number) { + const date = new Date(timestamp); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const ampm = hours >= 12 ? "PM" : "AM"; + const formattedHours = (hours % 12 || 12).toString().padStart(2, "0"); + const formattedMinutes = minutes.toString().padStart(2, "0"); + return `${formattedHours}:${formattedMinutes} ${ampm}`; +} + +export function getCurrentSeason() { + const now = new Date(); + const month = now.getMonth() + 1; // getMonth() returns 0-based index + + switch (month) { + case 12: + case 1: + case 2: + return "WINTER"; + case 3: + case 4: + case 5: + return "SPRING"; + case 6: + case 7: + case 8: + return "SUMMER"; + case 9: + case 10: + case 11: + return "FALL"; + default: + return "UNKNOWN SEASON"; + } +} + +export function convertUnixToCountdown(time: number) { + let date = new Date(time * 1000); + let days = date.getDay(); + let hours = date.getHours(); + let minutes = date.getMinutes(); + + let countdown = ""; + + if (days > 0) { + countdown += `${days}d `; + } + + if (hours > 0) { + countdown += `${hours}h `; + } + + if (minutes > 0) { + countdown += `${minutes}m `; + } + + return countdown.trim(); +} + +export function convertSecondsToTime(sec: number) { + let days = Math.floor(sec / (3600 * 24)); + let hours = Math.floor((sec % (3600 * 24)) / 3600); + let minutes = Math.floor((sec % 3600) / 60); + let seconds = Math.floor(sec % 60); + + let time = ""; + + if (days > 0) { + time += `${days}d `; + } + + if (hours > 0) { + time += `${hours}h `; + } + + if (minutes > 0) { + time += `${minutes}m `; + } + + if (days <= 0) { + time += `${seconds}s `; + } + + return time.trim(); +} + +// Function to convert timestamp to AM/PM time format +export const timeStamptoAMPM = (timestamp: number | string) => { + const date = new Date(Number(timestamp) * 1000); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const ampm = hours >= 12 ? "PM" : "AM"; + const formattedHours = hours % 12 || 12; // Convert to 12-hour format + + return `${formattedHours}:${minutes.toString().padStart(2, "0")} ${ampm}`; +}; + +export const timeStamptoHour = (timestamp: number) => { + const currentTime = new Date().getTime() / 1000; + const formattedTime = new Date(timestamp * 1000).toLocaleTimeString( + undefined, + { hour: "numeric", minute: "numeric", hour12: true } + ); + const status = timestamp <= currentTime ? "aired" : "airing"; + + return `${status} at ${formattedTime}`; +}; + +export function unixTimestampToRelativeTime(unixTimestamp: number) { + const now = Math.floor(Date.now() / 1000); // Current Unix timestamp in seconds + let secondsDifference = now - unixTimestamp; + + const intervals = [ + { label: "year", seconds: 31536000 }, + { label: "month", seconds: 2592000 }, + { label: "week", seconds: 604800 }, + { label: "day", seconds: 86400 }, + { label: "hour", seconds: 3600 }, + { label: "minute", seconds: 60 }, + { label: "second", seconds: 1 }, + ]; + + const isFuture = secondsDifference < 0; + secondsDifference = Math.abs(secondsDifference); + + for (const interval of intervals) { + const count = Math.floor(secondsDifference / interval.seconds); + if (count >= 1) { + const label = count === 1 ? interval.label : `${interval.label}s`; + return isFuture ? `${count} ${label} from now` : `${count} ${label} ago`; + } + } + + return "just now"; +} + +export function unixToSeconds(unixTimestamp: number) { + const now = Math.floor(Date.now() / 1000); // Current Unix timestamp in seconds + const secondsAgo = now - unixTimestamp; + + return secondsAgo; +} + +export function realTimeCountdown(secondsLeft: number): string { + let countdown = ""; + const intervalId = setInterval(() => { + secondsLeft--; + const hours = Math.floor(secondsLeft / 3600); + const minutes = Math.floor((secondsLeft % 3600) / 60); + const seconds = secondsLeft % 60; + countdown = `${hours.toString().padStart(2, "0")}:${minutes + .toString() + .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; + if (secondsLeft <= 0) { + clearInterval(intervalId); + } + }, 1000); + return countdown; +} diff --git a/utils/imageUtils.js b/utils/imageUtils.js deleted file mode 100644 index 8025d5b..0000000 --- a/utils/imageUtils.js +++ /dev/null @@ -1,38 +0,0 @@ -export function getHeaders(providerId) { - switch (providerId) { - case "mangahere": - return { Referer: "https://mangahere.org" }; - case "mangadex": - return { Referer: "https://mangadex.org" }; - case "mangakakalot": - return { Referer: "https://mangakakalot.com" }; - case "mangapill": - return { Referer: "https://mangapill.com" }; - case "mangasee123": - return { Referer: "https://mangasee123.com" }; - case "comick": - return { Referer: "https://comick.app" }; - default: - return null; - } -} - -export function getRandomId() { - return Math.random().toString(36).substr(2, 9); -} - -export function truncateImgUrl(url) { - // Find the index of .png if not found find the index of .jpg - let index = - url?.indexOf(".png") !== -1 ? url?.indexOf(".png") : url?.indexOf(".jpg"); - - if (index !== -1) { - // If .png or .jpg is found - url = url?.slice(0, index + 4); // Slice the string from the start to the index of .png or .jpg plus 4 (the length of .png or .jpg) - } else { - // If .png or .jpg is not found - return url; // Return the original url string - } - - return url; -} diff --git a/utils/imageUtils.ts b/utils/imageUtils.ts new file mode 100644 index 0000000..6220134 --- /dev/null +++ b/utils/imageUtils.ts @@ -0,0 +1,55 @@ +export function getHeaders(providerId: string) { + switch (providerId) { + case "mangahere": + return { Referer: "https://mangahere.org" }; + case "mangadex": + return { Referer: "https://mangadex.org" }; + case "mangakakalot": + return { Referer: "https://mangakakalot.com" }; + case "mangapill": + return { Referer: "https://mangapill.com" }; + case "mangasee123": + return { Referer: "https://mangasee123.com" }; + case "comick": + return { Referer: "https://comick.app" }; + default: + return null; + } +} + +export function getRandomId() { + return Math.random().toString(36).substr(2, 9); +} + +export function truncateImgUrl(url: string | undefined) { + if (!url) return null; + + // Find the index of .png if not found find the index of .jpg + let index = + url?.indexOf(".png") !== -1 ? url?.indexOf(".png") : url?.indexOf(".jpg"); + + if (index && index !== -1) { + // If .png or .jpg is found + url = url?.slice(0, index + 4); // Slice the string from the start to the index of .png or .jpg plus 4 (the length of .png or .jpg) + } else { + // If .png or .jpg is not found + return url; // Return the original url string + } + + return url; +} + +export function parseImageProxy( + url: string | undefined | null, + providerId: string | undefined +) { + if (!url) return; + + return providerId + ? `https://aoi.moopa.live/utils/image-proxy?url=${truncateImgUrl( + url + )}${`&headers=${encodeURIComponent( + JSON.stringify({ Referer: providerId }) + )}`}` + : url; +} diff --git a/utils/parseMetaData.ts b/utils/parseMetaData.ts new file mode 100644 index 0000000..597c21c --- /dev/null +++ b/utils/parseMetaData.ts @@ -0,0 +1,36 @@ +type Episode = { + id: string; + description: string | null; + hasDub: boolean; + img: string | null; + isFiller: boolean; + number: number; + rating: number | null; + title: string; + updatedAt: number; +}; + +type Provider = { + providerId: string; + data: Episode[]; +}; + +export function getProviderWithMostEpisodesAndImage( + data: Provider[] +): Provider | null { + let maxEpisodesProvider: Provider | null = null; + + for (const provider of data) { + if ( + !maxEpisodesProvider || + provider.data.length > maxEpisodesProvider.data.length + ) { + const hasImage = provider.data.some((episode) => episode.img !== null); + if (hasImage) { + maxEpisodesProvider = provider; + } + } + } + + return maxEpisodesProvider; +} diff --git a/utils/request/index.ts b/utils/request/index.ts new file mode 100644 index 0000000..854ef2b --- /dev/null +++ b/utils/request/index.ts @@ -0,0 +1,111 @@ +import axios, { AxiosRequestConfig } from "axios"; +import { getSession } from "next-auth/react"; +import { toast } from "sonner"; + +function isAnilist(url: string | undefined): boolean { + return url?.includes("anilist.co") ?? false; +} + +interface RequestOption extends RequestInit { + headers?: { + "Content-Type"?: string; + Authorization?: string; + }; +} + +const pls = { + // GET request handler + async get( + url: string, + options?: AxiosRequestConfig, + ctx?: any + ): Promise { + try { + const session: any | null = isAnilist(url) ? await getSession(ctx) : null; + const controller = new AbortController(); + const signal = controller.signal; + + const response = await axios.get(url, { ...options, signal }); + return response.data; + } catch (error: any) { + handleError(error); + // throw error; + } + }, + + // POST request handler + async post(url: string, options: RequestOption, ctx?: any): Promise { + try { + const session: any | null = await getSession(ctx); + const accessToken: string | undefined = session?.user?.token; + + const controller = new AbortController(); + const signal = controller.signal; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(accessToken && + isAnilist(url) && { Authorization: `Bearer ${accessToken}` }), + }, + ...options, + signal, + }); + + const data = await response.json(); + return [data, session]; + } catch (error: any) { + handleError(error); + // throw error; + } + }, +}; + +function handleError(error: { + response: { status: any; data: any }; + message: any; +}) { + console.log(error); + if (error.response) { + const { status, data } = error.response; + switch (status) { + case 400: + toast.error("400 Bad request", { + description: data?.message || error.message, + }); + break; + case 401: + toast.error("401 Unauthorized", { + description: data?.message || error.message, + }); + break; + case 403: + toast.error("403 Forbidden", { + description: data?.message || error.message, + }); + break; + case 404: + toast.error(`Resource not found - 404`, { + description: data?.message || error.message, + }); + break; + case 500: + toast.error("500 Internal server error", { + description: data?.message || error.message, + }); + break; + default: + toast.error("An error occurred", { + description: data?.message || error.message, + }); + break; + } + + if (data && data.message) { + console.error("Error message:", data.message); + } + } +} + +export default pls; diff --git a/utils/schedulesUtils.js b/utils/schedulesUtils.js deleted file mode 100644 index cb8c474..0000000 --- a/utils/schedulesUtils.js +++ /dev/null @@ -1,83 +0,0 @@ -// Function to transform the schedule data into the desired format -export const transformSchedule = (schedule) => { - const formattedSchedule = {}; - - for (const day of Object.keys(schedule)) { - formattedSchedule[day] = {}; - - for (const scheduleItem of schedule[day]) { - const time = scheduleItem.airingAt; - - if (!formattedSchedule[day][time]) { - formattedSchedule[day][time] = []; - } - - formattedSchedule[day][time].push(scheduleItem); - } - } - - return formattedSchedule; -}; - -export const sortScheduleByDay = (schedule) => { - const daysOfWeek = [ - "Saturday", - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - ]; - - // Get the current day of the week (0 = Sunday, 1 = Monday, ...) - const currentDay = new Date().getDay(); - - // Reorder days of the week to start with today - const orderedDays = [ - ...daysOfWeek.slice(currentDay), - ...daysOfWeek.slice(0, currentDay), - ]; - - // Create a new object with sorted days - const sortedSchedule = {}; - orderedDays.forEach((day) => { - if (schedule[day]) { - sortedSchedule[day] = schedule[day]; - } - }); - - return sortedSchedule; -}; - -export const filterScheduleByDay = (sortedSchedule, filterDay) => { - if (filterDay === "All") return sortedSchedule; - // Create a new object to store the filtered schedules - const filteredSchedule = {}; - - // Iterate through the keys (days) in sortedSchedule - for (const day in sortedSchedule) { - // Check if the current day matches the filterDay - if (day === filterDay) { - // If it matches, add the schedules for that day to the filteredSchedule object - filteredSchedule[day] = sortedSchedule[day]; - } - } - - // Return the filtered schedule - return filteredSchedule; -}; - -export const filterFormattedSchedule = (formattedSchedule, filterDay) => { - if (filterDay === "All") return formattedSchedule; - - // Check if the selected day exists in the formattedSchedule - if (formattedSchedule.hasOwnProperty(filterDay)) { - return { - [filterDay]: formattedSchedule[filterDay], - }; - } - - // If the selected day does not exist, return an empty object - return {}; -}; diff --git a/utils/schedulesUtils.ts b/utils/schedulesUtils.ts new file mode 100644 index 0000000..606e3fa --- /dev/null +++ b/utils/schedulesUtils.ts @@ -0,0 +1,96 @@ +interface ScheduleItem { + airingAt: string; + // Add other properties of ScheduleItem if available +} + +interface Schedule { + [day: string]: ScheduleItem[]; +} + +interface FormattedSchedule { + [day: string]: { + [time: string]: ScheduleItem[]; + }; +} + +export const transformSchedule = (schedule: Schedule): FormattedSchedule => { + const formattedSchedule: FormattedSchedule = {}; + + for (const day of Object.keys(schedule)) { + formattedSchedule[day] = {}; + + for (const scheduleItem of schedule[day]) { + const time = scheduleItem.airingAt; + + if (!formattedSchedule[day][time]) { + formattedSchedule[day][time] = []; + } + + formattedSchedule[day][time].push(scheduleItem); + } + } + + return formattedSchedule; +}; + +export const sortScheduleByDay = ( + schedule: FormattedSchedule +): FormattedSchedule => { + const daysOfWeek: string[] = [ + "Saturday", + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + ]; + + const currentDay: number = new Date().getDay(); + + const orderedDays: string[] = [ + ...daysOfWeek.slice(currentDay), + ...daysOfWeek.slice(0, currentDay), + ]; + + const sortedSchedule: FormattedSchedule = {}; + orderedDays.forEach((day) => { + if (schedule[day]) { + sortedSchedule[day] = schedule[day]; + } + }); + + return sortedSchedule; +}; + +export const filterScheduleByDay = ( + sortedSchedule: FormattedSchedule, + filterDay: string +): FormattedSchedule => { + if (filterDay === "All") return sortedSchedule; + + const filteredSchedule: FormattedSchedule = {}; + + for (const day in sortedSchedule) { + if (day === filterDay) { + filteredSchedule[day] = sortedSchedule[day]; + } + } + + return filteredSchedule; +}; + +export const filterFormattedSchedule = ( + formattedSchedule: FormattedSchedule, + filterDay: string +): FormattedSchedule => { + if (filterDay === "All") return formattedSchedule; + + if (formattedSchedule.hasOwnProperty(filterDay)) { + return { + [filterDay]: formattedSchedule[filterDay], + }; + } + + return {}; +}; diff --git a/utils/useCountdownSeconds.js b/utils/useCountdownSeconds.js deleted file mode 100644 index df3cb63..0000000 --- a/utils/useCountdownSeconds.js +++ /dev/null @@ -1,37 +0,0 @@ -import { useEffect, useState } from "react"; - -const useCountdown = (targetDate, update) => { - const countDownDate = new Date(targetDate).getTime(); - - const [countDown, setCountDown] = useState( - countDownDate - new Date().getTime() - ); - - useEffect(() => { - const interval = setInterval(() => { - const newCountDown = countDownDate - new Date().getTime(); - setCountDown(newCountDown); - if (newCountDown <= 0 && newCountDown > -1000) { - update(); - } - }, 1000); - - return () => clearInterval(interval); - }, [countDownDate, update]); - - return getReturnValues(countDown); -}; - -const getReturnValues = (countDown) => { - // calculate time left - const days = Math.floor(countDown / (1000 * 60 * 60 * 24)); - const hours = Math.floor( - (countDown % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) - ); - const minutes = Math.floor((countDown % (1000 * 60 * 60)) / (1000 * 60)); - const seconds = Math.floor((countDown % (1000 * 60)) / 1000); - - return [days, hours, minutes, seconds]; -}; - -export { useCountdown }; -- cgit v1.2.3