diff --git a/locales/en.ftl b/locales/en.ftl index 93b7ba4..09fb4d5 100644 --- a/locales/en.ftl +++ b/locales/en.ftl @@ -6,6 +6,7 @@ error-not-url = doesn't look like a url to me error-request-not-found = looks like i forgot your link, try sending it again error-not-button-owner = looks like this button is not yours (¬_¬") error-too-large = sorry, but this file is too big - telegram doesn't allow me to upload it +error-invalid-response = server response is invalid, maybe it's down or encountered an internal error error-unknown = oops, an internal error happened. i reported it to my develeoper, so they'll fix it! download-title = download from provided url diff --git a/locales/ru.ftl b/locales/ru.ftl index 241bb24..0fc08b4 100644 --- a/locales/ru.ftl +++ b/locales/ru.ftl @@ -6,6 +6,7 @@ error-not-url = не похоже на ссылку error-request-not-found = похоже я потерял твою ссылку, можешь отправить её снова? error-not-button-owner = похоже что эта кнопка не твоя (¬_¬") error-too-large = этот файл слишком большой, к сожалению тг не даёт его загрузить +error-invalid-response = сервер некорректно ответил, возможно он столкнулся с внутренней ошибкой или лежит error-unknown = ой, произошла внутреняя ошибка. я сообщил об этом моим разаработчикам, чтобы они исправили! download-title = скачать по ссылке diff --git a/src/handler.ts b/src/handler.ts index dd19a9b..ddacbfa 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -71,7 +71,7 @@ export const handleMediaDownload = async ( isAudioOnly: outputType === "audio", lang, }) - if (res.status === "error") return error(literal(res.text)) + if (res.status === "fail") return error(res.fails) if (res.status === "stream") { const data = await fetchStream(res.url) diff --git a/src/request.ts b/src/request.ts index 99633aa..a0fe1c1 100644 --- a/src/request.ts +++ b/src/request.ts @@ -1,5 +1,6 @@ import { z } from "zod" import { env } from "#env" +import { Text, literal, translatable, compound } from "#text" const genericErrorSchema = z.object({ status: z.literal("error"), @@ -30,20 +31,30 @@ const mediaResponseSchema = z.discriminatedUnion("status", [ genericErrorSchema, ]) +type FailResponse = { + status: "fail", + fails: Text, +} + +type FetchMediaResponse = + Exclude, z.infer> | FailResponse export const fetchMedia = async ( { url, lang, isAudioOnly = false, fails = [] }: { url: string, lang?: string, isAudioOnly?: boolean, - fails?: string[], + fails?: Text[], }, -): Promise> => { +): Promise => { if (fails.length >= env.API_BASE_URL.length) - throw new Error(`fetch failed with ${fails}`) + return { + status: "fail", + fails: compound(...fails), + } const currentBaseUrl = env.API_BASE_URL[fails.length] - const next = async (reason: string) => await fetchMedia( - { url, lang, isAudioOnly, fails: [...fails, `${currentBaseUrl} - ${reason}`] }, + const next = async (reason: Text) => await fetchMedia( + { url, lang, isAudioOnly, fails: [...fails, compound(literal(`\n${currentBaseUrl} - `), reason)] }, ) const res = await fetch(`${currentBaseUrl}/json`, { @@ -55,11 +66,11 @@ export const fetchMedia = async ( ], body: JSON.stringify({ url, isAudioOnly, filenamePattern: "basic", isNoTTWatermark: true }), }) - if (!res.ok) return next(`not ok (${res.status})`) const body = await res.json().catch(() => null) const data = mediaResponseSchema.safeParse(body) - if (!data.success) return next("invalid response body") + if (!data.success) return next(translatable("error-invalid-response")) + if (data.data.status === "error") return next(literal(data.data.text)) return data.data } diff --git a/src/text.ts b/src/text.ts index 30d6059..471acbc 100644 --- a/src/text.ts +++ b/src/text.ts @@ -11,18 +11,25 @@ export type TranslatableText = { key: string, } +export type CompoundText = { + type: "compound", + content: Text[], +} + export type TextFlavor = { evaluateText: (text: Text) => string, } -export type Text = LiteralText | TranslatableText +export type Text = LiteralText | TranslatableText | CompoundText export const literal = (text: string): LiteralText => ({ type: "literal", text }) export const translatable = (key: string): TranslatableText => ({ type: "translatable", key }) +export const compound = (...content: Text[]): CompoundText => ({ type: "compound", content }) export const textMiddleware: MiddlewareFn = async (ctx, next) => { ctx.evaluateText = (text: Text): string => { if (text.type === "literal") return text.text if (text.type === "translatable") return ctx.t(text.key) + if (text.type === "compound") return text.content.map(t => ctx.evaluateText(t)).join("") return "" } await next()