From dc8fa7e754c237604d5b91e13ba3d163d942f32d Mon Sep 17 00:00:00 2001 From: oddyamill <43600905+oddyamill@users.noreply.github.com> Date: Sun, 6 Oct 2024 17:27:33 +0700 Subject: [PATCH] feat errors!! --- package-lock.json | 145 +++++++++++++++---------------- package.json | 2 +- src/command.ts | 31 +++---- src/localization/en.json | 9 +- src/localization/index.ts | 3 +- src/localization/ru.json | 13 ++- src/localization/uk.json | 11 ++- src/tiktok.ts | 24 +++-- src/utils/getTikTok.ts | 72 ++++++++++----- src/utils/index.ts | 1 + src/utils/makeAuthorComponent.ts | 22 ++--- src/utils/resolveMedia.ts | 14 +-- wrangler.toml | 3 + 13 files changed, 204 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b5b12b..3681b99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20240117.0", "typescript": "^5.0.4", - "wrangler": "^3.73.0" + "wrangler": "^3.78.12" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -31,9 +31,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240821.1.tgz", - "integrity": "sha512-CDBpfZKrSy4YrIdqS84z67r3Tzal2pOhjCsIb63IuCnvVes59/ft1qhczBzk9EffeOE2iTCrA4YBT7Sbn7USew==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240925.0.tgz", + "integrity": "sha512-KdLnSXuzB65CbqZPm+qYzk+zkQ1tUNPaaRGYVd/jPYAxwwtfTUQdQ+ahDPwVVs2tmQELKy7ZjQjf2apqSWUfjw==", "cpu": [ "x64" ], @@ -48,9 +48,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240821.1.tgz", - "integrity": "sha512-Q+9RedvNbPcEt/dKni1oN94OxbvuNAeJkgHmrLFTGF8zu21wzOhVkQeRNxcYxrMa9mfStc457NAg13OVCj2kHQ==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240925.0.tgz", + "integrity": "sha512-MiQ6uUmCXjsXgWNV+Ock2tp2/tYqNJGzjuaH6jFioeRF+//mz7Tv7J7EczOL4zq+TH8QFOh0/PUsLyazIWVGng==", "cpu": [ "arm64" ], @@ -65,9 +65,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240821.1.tgz", - "integrity": "sha512-j6z3KsPtawrscoLuP985LbqFrmsJL6q1mvSXOXTqXGODAHIzGBipHARdOjms3UQqovzvqB2lQaQsZtLBwCZxtA==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240925.0.tgz", + "integrity": "sha512-Rjix8jsJMfsInmq3Hm3fmiRQ+rwzuWRPV1pg/OWhMSfNP7Qp2RCU+RGkhgeR9Z5eNAje0Sn2BMrFq4RvF9/yRA==", "cpu": [ "x64" ], @@ -82,9 +82,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240821.1.tgz", - "integrity": "sha512-I9bHgZOxJQW0CV5gTdilyxzTG7ILzbTirehQWgfPx9X77E/7eIbR9sboOMgyeC69W4he0SKtpx0sYZuTJu4ERw==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240925.0.tgz", + "integrity": "sha512-VYIPeMHQRtbwQoIjUwS/zULlywPxyDvo46XkTpIW5MScEChfqHvAYviQ7TzYGx6Q+gmZmN+DUB2KOMx+MEpCxA==", "cpu": [ "arm64" ], @@ -99,9 +99,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240821.1.tgz", - "integrity": "sha512-keC97QPArs6LWbPejQM7/Y8Jy8QqyaZow4/ZdsGo+QjlOLiZRDpAenfZx3CBUoWwEeFwQTl2FLO+8hV1SWFFYw==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240925.0.tgz", + "integrity": "sha512-C8peGvaU5R51bIySi1VbyfRgwNSSRknqoFSnSbSBI3uTN3THTB3UnmRKy7GXJDmyjgXuT9Pcs1IgaWNubLtNtw==", "cpu": [ "x64" ], @@ -116,19 +116,23 @@ } }, "node_modules/@cloudflare/workers-shared": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.4.1.tgz", - "integrity": "sha512-nYh4r8JwOOjYIdH2zub++CmIKlkYFlpxI1nBHimoiHcytJXD/b7ldJ21TtfzUZMCgI78mxVlymMHA/ReaOxKlA==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.5.4.tgz", + "integrity": "sha512-PNL/0TjKRdUHa1kwgVdqUNJVZ9ez4kacsi8omz+gv859EvJmsVuGiMAClY2YfJnC9LVKhKCcjqmFgKNXG9/IXA==", "dev": true, "license": "MIT OR Apache-2.0", + "dependencies": { + "mime": "^3.0.0", + "zod": "^3.22.3" + }, "engines": { "node": ">=16.7.0" } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240821.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240821.1.tgz", - "integrity": "sha512-icAkbnAqgVl6ef9lgLTom8na+kj2RBw2ViPAQ586hbdj0xZcnrjK7P46Eu08OU9D/lNDgN2sKU/sxhe2iK/gIg==", + "version": "4.20240925.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240925.0.tgz", + "integrity": "sha512-KpqyRWvanEuXgBTKYFzRp4NsWOEcswxjsPRSre1zYQcODmc8PUrraVHQUmgvkJgv3FzB+vI9xm7J6oE4MmZHCA==", "dev": true, "license": "MIT OR Apache-2.0" }, @@ -597,9 +601,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -714,25 +718,14 @@ "dev": true, "license": "MIT" }, - "node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -978,9 +971,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240821.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240821.0.tgz", - "integrity": "sha512-4BhLGpssQxM/O6TZmJ10GkT3wBJK6emFkZ3V87/HyvQmVt8zMxEBvyw5uv6kdtp+7F54Nw6IKFJjPUL8rFVQrQ==", + "version": "3.20240925.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240925.0.tgz", + "integrity": "sha512-2LmQbKHf0n6ertUKhT+Iltixi53giqDH7P71+wCir3OnGyXIODqYwOECx1mSDNhYThpxM2dav8UdPn6SQiMoXw==", "dev": true, "license": "MIT", "dependencies": { @@ -992,7 +985,7 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", - "workerd": "1.20240821.1", + "workerd": "1.20240925.0", "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" @@ -1005,9 +998,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -1058,9 +1051,9 @@ } }, "node_modules/ohash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", - "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.4.tgz", + "integrity": "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==", "dev": true, "license": "MIT" }, @@ -1071,10 +1064,11 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" }, "node_modules/pathe": { "version": "1.1.2", @@ -1294,22 +1288,22 @@ }, "node_modules/unenv": { "name": "unenv-nightly", - "version": "2.0.0-1724863496.70db6f1", - "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-1724863496.70db6f1.tgz", - "integrity": "sha512-r+VIl1gnsI4WQxluruSQhy8alpAf1AsLRLm4sEKp3otCyTIVD6I6wHEYzeQnwsyWgaD4+3BD4A/eqrgOpdTzhw==", + "version": "2.0.0-20240919-125358-9a64854", + "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20240919-125358-9a64854.tgz", + "integrity": "sha512-XjsgUTrTHR7iw+k/SRTNjh6EQgwpC9voygnoCJo5kh4hKqsSDHUW84MhL9EsHTNfLctvVBHaSw8e2k3R2fKXsQ==", "dev": true, "license": "MIT", "dependencies": { "defu": "^6.1.4", - "ohash": "^1.1.3", + "ohash": "^1.1.4", "pathe": "^1.1.2", "ufo": "^1.5.4" } }, "node_modules/workerd": { - "version": "1.20240821.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240821.1.tgz", - "integrity": "sha512-y4phjCnEG96u8ZkgkkHB+gSw0i6uMNo23rBmixylWpjxDklB+LWD8dztasvsu7xGaZbLoTxQESdEw956F7VJDA==", + "version": "1.20240925.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240925.0.tgz", + "integrity": "sha512-/Jj6+yLwfieZGEt3Kx4+5MoufuC3g/8iFaIh4MPBNGJOGYmdSKXvgCqz09m2+tVCYnysRfbq2zcbVxJRBfOCqQ==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -1320,37 +1314,36 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240821.1", - "@cloudflare/workerd-darwin-arm64": "1.20240821.1", - "@cloudflare/workerd-linux-64": "1.20240821.1", - "@cloudflare/workerd-linux-arm64": "1.20240821.1", - "@cloudflare/workerd-windows-64": "1.20240821.1" + "@cloudflare/workerd-darwin-64": "1.20240925.0", + "@cloudflare/workerd-darwin-arm64": "1.20240925.0", + "@cloudflare/workerd-linux-64": "1.20240925.0", + "@cloudflare/workerd-linux-arm64": "1.20240925.0", + "@cloudflare/workerd-windows-64": "1.20240925.0" } }, "node_modules/wrangler": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.73.0.tgz", - "integrity": "sha512-VrdDR2OpvsCQp+r5Of3rDP1W64cNN/LHLVx1roULOlPS8PZiv7rUYgkwhdCQ61+HICAaeSxWYIzkL5+B9+8W3g==", + "version": "3.78.12", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.78.12.tgz", + "integrity": "sha512-a/xk/N04IvOGk9J+BLkiFg42GDyPS+0BiJimbrHsbX+CDr8Iqq3HNMEyQld+6zbmq01u/gmc8S7GKVR9vDx4+g==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", - "@cloudflare/workers-shared": "0.4.1", + "@cloudflare/workers-shared": "0.5.4", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "blake3-wasm": "^2.1.5", "chokidar": "^3.5.3", - "date-fns": "^3.6.0", "esbuild": "0.17.19", - "miniflare": "3.20240821.0", + "miniflare": "3.20240925.0", "nanoid": "^3.3.3", - "path-to-regexp": "^6.2.0", + "path-to-regexp": "^6.3.0", "resolve": "^1.22.8", "resolve.exports": "^2.0.2", "selfsigned": "^2.0.1", "source-map": "^0.6.1", - "unenv": "npm:unenv-nightly@2.0.0-1724863496.70db6f1", - "workerd": "1.20240821.1", + "unenv": "npm:unenv-nightly@2.0.0-20240919-125358-9a64854", + "workerd": "1.20240925.0", "xxhash-wasm": "^1.0.1" }, "bin": { @@ -1364,7 +1357,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20240821.1" + "@cloudflare/workers-types": "^4.20240925.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { diff --git a/package.json b/package.json index 98b821c..0c2e149 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20240117.0", "typescript": "^5.0.4", - "wrangler": "^3.73.0" + "wrangler": "^3.78.12" }, "dependencies": { "@oddyamill/discord-workers": "^1.1.5", diff --git a/src/command.ts b/src/command.ts index cbb7aed..4506fb5 100644 --- a/src/command.ts +++ b/src/command.ts @@ -1,5 +1,3 @@ -// TODO: refactoring - import { ComponentType, InteractionResponseType, @@ -17,13 +15,14 @@ import { makeMessageURL, resolveArguments, resolveId, + resolveMedia, } from './utils' export const command = async (interaction: Interaction, t: Translator, env: Env, ctx: ExecutionContext): Promise => { const { text, message } = resolveArguments(interaction) const id = await resolveId(text) - if (!id) { + if (id === undefined) { return respond(InteractionResponseType.ChannelMessageWithSource, { content: t('no_tiktok'), flags: MessageFlags.Ephemeral, @@ -32,26 +31,22 @@ export const command = async (interaction: Interaction, t: Translator, env: Env, ctx.waitUntil( (async () => { - const data = await getTikTok(id, env) + const [data, response, error] = await getTikTok(id) - if (!data) { - return editResponse(interaction, { - content: t('video_not_loading'), - }) + if (error !== null) { + return editResponse(interaction, { content: t(error) }) } - const { format, author, stream, url } = data + const media = await resolveMedia(data, response, env) - if (!stream) { - return editResponse(interaction, { - content: t('video_not_supported'), - }) + if (media === null) { + return editResponse(interaction, { content: t('video_not_supported') }) } + const { format, stream } = media + if (!stream.ok) { - return editResponse(interaction, { - content: t('tiktok_blocked'), - }) + return editResponse(interaction, { content: t('tiktok_blocked') }) } const body = new FormData(), @@ -60,8 +55,8 @@ export const command = async (interaction: Interaction, t: Translator, env: Env, { type: ComponentType.ActionRow, components: [ - makeComponent(t('open_in_tiktok'), url), - await makeAuthorComponent(author.nickname, author.id, author.uniqueId, author.avatarThumb, interaction, env, ctx), + makeComponent(t('open_in_tiktok'), response.url), + await makeAuthorComponent(data.author, interaction, env, ctx), ], }, ], diff --git a/src/localization/en.json b/src/localization/en.json index 07b2ae7..c1a77a0 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -1,7 +1,14 @@ { "cannot_process_command": "Unable to process the command.", "no_tiktok": "Unable to find the TikTok. Is the link correct?", - "video_not_loading": "The video is not loading. Please try again later.", + "video_not_found": "Video not found.", + "video_deleted": "Video deleted.", + "service_unavailable": "Service unavailable.", + "video_age_restricted": "This video has been removed due to age restrictions.", + "video_private": "This video is private.", + "video_for_friends": "This video is for friends only.", + "video_for_subscriber": "This video is for subscriber only.", + "video_for_creator": "This video is for creator only.", "video_not_supported": "This video is not supported.", "tiktok_blocked": "TikTok has blocked the bot's request. The video will not be available.", "open_in_tiktok": "Open in TikTok", diff --git a/src/localization/index.ts b/src/localization/index.ts index ba78383..a3d34df 100644 --- a/src/localization/index.ts +++ b/src/localization/index.ts @@ -11,7 +11,8 @@ export const localization = new Map() .set(Locale.Russian, ru) .set(Locale.Ukrainian, uk) -export type Translator = (key: keyof typeof defaultLocale) => string +export type TranslatorKey = keyof typeof defaultLocale +export type Translator = (key: TranslatorKey) => string export const getTranslator = (locale: LocaleString): Translator => { const translations = localization.get(locale) ?? defaultLocale diff --git a/src/localization/ru.json b/src/localization/ru.json index 6a29d3e..b808034 100644 --- a/src/localization/ru.json +++ b/src/localization/ru.json @@ -1,9 +1,16 @@ { "cannot_process_command": "Невозможно обработать данную команду.", "no_tiktok": "Невозможно обнаружить ТикТок. Ссылка правильная?", - "video_not_loading": "Видео не загружается че-то. Попробуйте позже.", - "video_not_supported": "Данное видео не поддерживается.", - "tiktok_blocked": "TikTok заблокировал запрос бота. Видео не будет.", + "video_not_found": "Видео не найдено.", + "video_deleted": "Видео удалено.", + "service_unavailable": "Сервис недоступен.", + "video_age_restricted": "Это видео удалено из-за возрастных ограничений.", + "video_private": "Это видео приватное.", + "video_for_friends": "Это видео только для друзей.", + "video_for_subscriber": "Это видео только для подписчиков.", + "video_for_creator": "Это видео только для создателя.", + "video_not_supported": "Это видео не поддерживается.", + "tiktok_blocked": "TikTok заблокировал запрос бота. Видео не будет доступно.", "open_in_tiktok": "Открыть в TikTok", "message": "Сообщение", "original": "Оригинал" diff --git a/src/localization/uk.json b/src/localization/uk.json index 1796667..9b7b480 100644 --- a/src/localization/uk.json +++ b/src/localization/uk.json @@ -1,9 +1,16 @@ { "cannot_process_command": "Неможливо обробити цю команду.", "no_tiktok": "Не вдалося знайти ТікТок. Посилання правильне?", - "video_not_loading": "Відео не завантажується. Спробуйте пізніше.", + "video_not_found": "Відео не знайдено.", + "video_deleted": "Відео видалено.", + "service_unavailable": "Сервіс недоступний.", + "video_age_restricted": "Це відео видалено через вікові обмеження.", + "video_private": "Це відео приватне.", + "video_for_friends": "Це відео тільки для друзів.", + "video_for_subscriber": "Це відео тільки для підписників.", + "video_for_creator": "Це відео тільки для творця.", "video_not_supported": "Це відео не підтримується.", - "tiktok_blocked": "TikTok заблокував запит бота. Відео не буде.", + "tiktok_blocked": "TikTok заблокував запит бота. Відео не буде доступне.", "open_in_tiktok": "Відкрити в TikTok", "message": "Повідомлення", "original": "Оригінал" diff --git a/src/tiktok.ts b/src/tiktok.ts index 7c2590b..9063974 100644 --- a/src/tiktok.ts +++ b/src/tiktok.ts @@ -1,13 +1,23 @@ -export type TikTok = { +export interface VideoDetail { + statusCode: number + statusMsg: string + itemInfo?: { + itemStruct: ItemStruct + } +} + +export interface ItemStruct { id: string video: { bitrateInfo?: { PlayAddr: { UrlList: [string] }; DataSize: number }[] } imagePost?: { images: [{ imageURL: { urlList: string } }] } - author: { - id: string - nickname: string - uniqueId: string - avatarThumb: string - } + author: Author +} + +export interface Author { + id: string + nickname: string + uniqueId: string + avatarThumb: string } diff --git a/src/utils/getTikTok.ts b/src/utils/getTikTok.ts index 5832a7c..b05d41e 100644 --- a/src/utils/getTikTok.ts +++ b/src/utils/getTikTok.ts @@ -1,36 +1,68 @@ import { TIKTOK_ENDPOINT } from '../constants' -import { resolveMedia } from './resolveMedia' -import { TikTok } from '../tiktok' -import { Env } from '../env' +import { TranslatorKey } from '../localization' +import { ItemStruct, VideoDetail } from '../tiktok' -export const getTikTok = async (id: string, env: Env) => { +// enum like +const ErrorMessage: Record = { + VideoForCreator: 'video_for_creator', + VideoForFriends: 'video_for_friends', + VideoForSubscriber: 'video_for_subscriber', + VideoPrivate: 'video_private', + VideoAgeRestricted: 'video_age_restricted', + VideoDeleted: 'video_deleted', + VideoNotFound: 'video_not_found', + ServiceUnavailable: 'service_unavailable', +} + +const resolveErrorMessage = (videoDetail: VideoDetail): TranslatorKey => { + const { statusMsg, statusCode } = videoDetail + console.log(videoDetail) + + switch (true) { + case statusMsg.includes('status_self_see'): + return ErrorMessage.VideoForCreator + case statusMsg.includes('status_friend_see'): + return ErrorMessage.VideoForFriends + case statusMsg.includes('author_secret'): + return ErrorMessage.VideoForSubscriber + case statusCode === 10222: + return ErrorMessage.VideoPrivate + case statusMsg.includes('content_classification'): + return ErrorMessage.VideoAgeRestricted + case statusMsg.includes('status_deleted'): + case statusMsg.includes('vigo'): + return ErrorMessage.VideoDeleted + case statusMsg === "item doesn't exist": + case statusCode === 10204: + return ErrorMessage.VideoNotFound + default: + return ErrorMessage.ServiceUnavailable + } +} + +export const getTikTok = async (id: string): Promise<[ItemStruct, Response, null] | [null, null, TranslatorKey]> => { const url = TIKTOK_ENDPOINT + id const response = await fetch(url) if (!response.ok) { - return + return [null, null, ErrorMessage.ServiceUnavailable] } try { - const html = await response.text() + const videoDetail = JSON.parse( + (await response.text()) + .split('')[0] + ).__DEFAULT_SCOPE__['webapp.video-detail'] as VideoDetail - if (!html.includes('__UNIVERSAL_DATA_FOR_REHYDRATION__')) { - return + if (videoDetail.itemInfo === undefined) { + return [null, null, resolveErrorMessage(videoDetail)] } - const data = JSON.parse( - html.split('')[0] - ) - - const tiktok = - data.__DEFAULT_SCOPE__['webapp.video-detail'].itemInfo.itemStruct as TikTok - - return { - url, - author: tiktok.author, - ...await resolveMedia(response, tiktok, env), - } + return [videoDetail.itemInfo.itemStruct, response, null] } catch (error) { console.error(error) } + + return [null, null, ErrorMessage.ServiceUnavailable] } diff --git a/src/utils/index.ts b/src/utils/index.ts index 7ad8c71..4ca7bb9 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -5,3 +5,4 @@ export * from './makeComponent' export * from './makeMessageURL' export * from './resolveArguments' export * from './resolveId' +export * from './resolveMedia' diff --git a/src/utils/makeAuthorComponent.ts b/src/utils/makeAuthorComponent.ts index 13ecbb3..0c11139 100644 --- a/src/utils/makeAuthorComponent.ts +++ b/src/utils/makeAuthorComponent.ts @@ -6,20 +6,20 @@ import { createApplicationEmoji } from '@oddyamill/discord-workers' import { arrayBufferToBase64 } from './arrayBufferToBase64' import { getComponentEmojiFromCache, putComponentEmojiToCache } from './emojiCache' import { TIKTOK_USER_ENDPOINT } from '../constants' +import { Author } from '../tiktok' export const makeAuthorComponent = async ( - label: string, - authorId: string, - authorUsername: string, - authorAvatar: string, + author: Author, interaction: Interaction, env: Env, ctx: ExecutionContext, ): Promise => { + const { id, nickname, uniqueId, avatarThumb } = author + const component = makeComponent( - label, - TIKTOK_USER_ENDPOINT + authorUsername, - await getComponentEmojiFromCache(env, authorId) + nickname, + TIKTOK_USER_ENDPOINT + uniqueId, + await getComponentEmojiFromCache(env, id) ) if (component.emoji !== undefined) { @@ -28,8 +28,8 @@ export const makeAuthorComponent = async ( const url = env.IMAGE_WORKER_ENDPOINT !== undefined - ? env.IMAGE_WORKER_ENDPOINT + '/circle?url=' + encodeURIComponent(authorAvatar) - : authorAvatar + ? env.IMAGE_WORKER_ENDPOINT + '/circle?url=' + encodeURIComponent(avatarThumb) + : avatarThumb const image = await fetch(url, { headers: { @@ -46,12 +46,12 @@ export const makeAuthorComponent = async ( const emoji = await createApplicationEmoji( env, interaction.application_id, - authorId, + id, 'data:image/png;base64,' + arrayBufferToBase64(await image.arrayBuffer()) ) component.emoji = { id: emoji.id!, name: emoji.name! } - ctx.waitUntil(putComponentEmojiToCache(env, authorId, component.emoji)) + ctx.waitUntil(putComponentEmojiToCache(env, id, component.emoji)) } catch (error) { console.error(error) } diff --git a/src/utils/resolveMedia.ts b/src/utils/resolveMedia.ts index 36b7c42..2f2d48d 100644 --- a/src/utils/resolveMedia.ts +++ b/src/utils/resolveMedia.ts @@ -1,4 +1,4 @@ -import { TikTok } from '../tiktok' +import { ItemStruct } from '../tiktok' import { TIKTOK_HEADERS, MAX_FILE_LENGTH, @@ -12,7 +12,7 @@ export interface Media { format: string } -export const resolveMedia = async (response: Response, tiktok: TikTok, env: Env): Promise => { +export const resolveMedia = async (tiktok: ItemStruct, response: Response, env: Env): Promise => { const init: RequestInit = { headers: { Cookie: resolveCookie(response), @@ -28,10 +28,10 @@ export const resolveMedia = async (response: Response, tiktok: TikTok, env: Env) return resolveVideo(tiktok, init) } - return {} + return null } -const resolveImage = async (tiktok: TikTok, init: RequestInit, env: Env): Promise => { +const resolveImage = async (tiktok: ItemStruct, init: RequestInit, env: Env): Promise => { const { imagePost } = tiktok if (imagePost!.images.length > 1 && env.IMAGE_WORKER_ENDPOINT !== undefined) { @@ -55,6 +55,8 @@ const resolveImage = async (tiktok: TikTok, init: RequestInit, env: Env): Promis format: 'mp4', } } + + await stream.body?.cancel() } return { @@ -63,7 +65,7 @@ const resolveImage = async (tiktok: TikTok, init: RequestInit, env: Env): Promis } } -const resolveVideo = async (tiktok: TikTok, init: RequestInit): Promise => { +const resolveVideo = async (tiktok: ItemStruct, init: RequestInit): Promise => { for (const bitrateInfo of tiktok.video.bitrateInfo!) { if (bitrateInfo.DataSize > MAX_FILE_LENGTH) { continue @@ -88,5 +90,5 @@ const resolveVideo = async (tiktok: TikTok, init: RequestInit): Promise