diff options
| author | Factiven <[email protected]> | 2023-12-24 13:03:54 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-12-24 13:03:54 +0700 |
| commit | 50a0f0240d7fef133eb5acc1bea2b1168b08e9db (patch) | |
| tree | 307e09e505580415a58d64b5fc3580e9235869f1 /utils | |
| parent | Update README.md (#104) (diff) | |
| download | moopa-50a0f0240d7fef133eb5acc1bea2b1168b08e9db.tar.xz moopa-50a0f0240d7fef133eb5acc1bea2b1168b08e9db.zip | |
migrate to typescript
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/appendMetaToEpisodes.ts (renamed from utils/appendMetaToEpisodes.js) | 29 | ||||
| -rw-r--r-- | utils/combineImages.ts (renamed from utils/combineImages.js) | 21 | ||||
| -rw-r--r-- | utils/getFormat.ts (renamed from utils/getFormat.js) | 2 | ||||
| -rw-r--r-- | utils/getGreetings.ts (renamed from utils/getGreetings.js) | 0 | ||||
| -rw-r--r-- | utils/getRedisWithPrefix.ts (renamed from utils/getRedisWithPrefix.js) | 12 | ||||
| -rw-r--r-- | utils/getTimes.ts (renamed from utils/getTimes.js) | 36 | ||||
| -rw-r--r-- | utils/imageUtils.ts (renamed from utils/imageUtils.js) | 23 | ||||
| -rw-r--r-- | utils/parseMetaData.ts | 36 | ||||
| -rw-r--r-- | utils/request/index.ts | 111 | ||||
| -rw-r--r-- | utils/schedulesUtils.ts (renamed from utils/schedulesUtils.js) | 55 | ||||
| -rw-r--r-- | utils/useCountdownSeconds.js | 37 |
11 files changed, 280 insertions, 82 deletions
diff --git a/utils/appendMetaToEpisodes.js b/utils/appendMetaToEpisodes.ts index 197788b..5f74df3 100644 --- a/utils/appendMetaToEpisodes.js +++ b/utils/appendMetaToEpisodes.ts @@ -1,8 +1,31 @@ -async function appendMetaToEpisodes(episodesData, images) { +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<ProviderEpisodes[]> { // Create a dictionary for faster lookup of images based on episode number - const episodeImages = {}; + const episodeImages: { [key: number]: Image } = {}; images.forEach((image) => { - episodeImages[image.number || image.episode] = image; + image.episode && (episodeImages[image.episode] = image); + image.number && (episodeImages[image.number] = image); }); // Iterate through each provider's episodes data diff --git a/utils/combineImages.js b/utils/combineImages.ts index abf34ed..01b7ef3 100644 --- a/utils/combineImages.js +++ b/utils/combineImages.ts @@ -1,6 +1,23 @@ -async function appendImagesToEpisodes(episodesData, images) { +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 = {}; + const episodeImages: { [key: number]: string } = {}; images.forEach((image) => { episodeImages[image.episode] = image.img; }); diff --git a/utils/getFormat.js b/utils/getFormat.ts index 9a2e3e3..7f3eece 100644 --- a/utils/getFormat.js +++ b/utils/getFormat.ts @@ -11,7 +11,7 @@ const data = [ { name: "One Shot", value: "ONE_SHOT" }, ]; -export function getFormat(format) { +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.ts index 1dd2a53..1dd2a53 100644 --- a/utils/getGreetings.js +++ b/utils/getGreetings.ts diff --git a/utils/getRedisWithPrefix.js b/utils/getRedisWithPrefix.ts index b85589b..dacf78e 100644 --- a/utils/getRedisWithPrefix.js +++ b/utils/getRedisWithPrefix.ts @@ -1,6 +1,6 @@ import { redis } from "@/lib/redis"; -export async function getValuesWithPrefix(prefix) { +export async function getValuesWithPrefix(prefix: string) { let cursor = "0"; // Start at the beginning of the keyspace let values = []; @@ -16,7 +16,9 @@ export async function getValuesWithPrefix(prefix) { // 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)); + if (value !== null) { + values.push(JSON.parse(value)); + } } // Update the cursor for the next iteration @@ -26,7 +28,7 @@ export async function getValuesWithPrefix(prefix) { return values; } -export async function countKeysWithPrefix(prefix) { +export async function countKeysWithPrefix(prefix: string) { let cursor = "0"; // Start at the beginning of the keyspace let count = 0; @@ -67,10 +69,10 @@ 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 = []; + const values: any[] = []; for (const key of numericKeys) { - const value = await redis.del(key); + await redis.del(key); } return values; diff --git a/utils/getTimes.js b/utils/getTimes.ts index 95df803..c3fe0ad 100644 --- a/utils/getTimes.js +++ b/utils/getTimes.ts @@ -1,4 +1,4 @@ -export function convertUnixToTime(timestamp) { +export function convertUnixToTime(timestamp: number) { const date = new Date(timestamp); const hours = date.getHours(); const minutes = date.getMinutes(); @@ -34,7 +34,7 @@ export function getCurrentSeason() { } } -export function convertUnixToCountdown(time) { +export function convertUnixToCountdown(time: number) { let date = new Date(time * 1000); let days = date.getDay(); let hours = date.getHours(); @@ -57,7 +57,7 @@ export function convertUnixToCountdown(time) { return countdown.trim(); } -export function convertSecondsToTime(sec) { +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); @@ -85,8 +85,8 @@ export function convertSecondsToTime(sec) { } // Function to convert timestamp to AM/PM time format -export const timeStamptoAMPM = (timestamp) => { - const date = new Date(timestamp * 1000); +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"; @@ -95,19 +95,18 @@ export const timeStamptoAMPM = (timestamp) => { return `${formattedHours}:${minutes.toString().padStart(2, "0")} ${ampm}`; }; -export const timeStamptoHour = (timestamp) => { - const options = { hour: "numeric", minute: "numeric", hour12: true }; +export const timeStamptoHour = (timestamp: number) => { const currentTime = new Date().getTime() / 1000; const formattedTime = new Date(timestamp * 1000).toLocaleTimeString( undefined, - options + { hour: "numeric", minute: "numeric", hour12: true } ); const status = timestamp <= currentTime ? "aired" : "airing"; return `${status} at ${formattedTime}`; }; -export function unixTimestampToRelativeTime(unixTimestamp) { +export function unixTimestampToRelativeTime(unixTimestamp: number) { const now = Math.floor(Date.now() / 1000); // Current Unix timestamp in seconds let secondsDifference = now - unixTimestamp; @@ -135,9 +134,26 @@ export function unixTimestampToRelativeTime(unixTimestamp) { return "just now"; } -export function unixToSeconds(unixTimestamp) { +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.ts index 8025d5b..6220134 100644 --- a/utils/imageUtils.js +++ b/utils/imageUtils.ts @@ -1,4 +1,4 @@ -export function getHeaders(providerId) { +export function getHeaders(providerId: string) { switch (providerId) { case "mangahere": return { Referer: "https://mangahere.org" }; @@ -21,12 +21,14 @@ export function getRandomId() { return Math.random().toString(36).substr(2, 9); } -export function truncateImgUrl(url) { +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 !== -1) { + 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 { @@ -36,3 +38,18 @@ export function truncateImgUrl(url) { 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<any> { + 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<any> { + 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.ts index cb8c474..606e3fa 100644 --- a/utils/schedulesUtils.js +++ b/utils/schedulesUtils.ts @@ -1,6 +1,20 @@ -// Function to transform the schedule data into the desired format -export const transformSchedule = (schedule) => { - const formattedSchedule = {}; +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] = {}; @@ -19,8 +33,10 @@ export const transformSchedule = (schedule) => { return formattedSchedule; }; -export const sortScheduleByDay = (schedule) => { - const daysOfWeek = [ +export const sortScheduleByDay = ( + schedule: FormattedSchedule +): FormattedSchedule => { + const daysOfWeek: string[] = [ "Saturday", "Sunday", "Monday", @@ -30,17 +46,14 @@ export const sortScheduleByDay = (schedule) => { "Friday", ]; - // Get the current day of the week (0 = Sunday, 1 = Monday, ...) - const currentDay = new Date().getDay(); + const currentDay: number = new Date().getDay(); - // Reorder days of the week to start with today - const orderedDays = [ + const orderedDays: string[] = [ ...daysOfWeek.slice(currentDay), ...daysOfWeek.slice(0, currentDay), ]; - // Create a new object with sorted days - const sortedSchedule = {}; + const sortedSchedule: FormattedSchedule = {}; orderedDays.forEach((day) => { if (schedule[day]) { sortedSchedule[day] = schedule[day]; @@ -50,34 +63,34 @@ export const sortScheduleByDay = (schedule) => { return sortedSchedule; }; -export const filterScheduleByDay = (sortedSchedule, filterDay) => { +export const filterScheduleByDay = ( + sortedSchedule: FormattedSchedule, + filterDay: string +): FormattedSchedule => { if (filterDay === "All") return sortedSchedule; - // Create a new object to store the filtered schedules - const filteredSchedule = {}; - // Iterate through the keys (days) in sortedSchedule + const filteredSchedule: FormattedSchedule = {}; + 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) => { +export const filterFormattedSchedule = ( + formattedSchedule: FormattedSchedule, + filterDay: string +): FormattedSchedule => { 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/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 }; |