commit e23fb5ff0e6e34000e342b08768bb3290ac71bc8 Author: snusxd Date: Fri Apr 10 00:42:01 2026 +0300 init: backend diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cd68f14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + +.eslintcache + +# Cypress +/cypress/videos/ +/cypress/screenshots/ + +# Vitest +__screenshots__/ + +# Vite +*.timestamp-*-*.mjs diff --git a/package.json b/package.json new file mode 100644 index 0000000..1e20743 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "type": "module", + "dependencies": { + "@elysiajs/cors": "^1.4.1", + "@elysiajs/node": "^1.4.5", + "@sinclair/typebox": "^0.34.49", + "axios": "^1.15.0", + "elysia": "^1.4.28", + "node": "^25.9.0", + "openapi-types": "^12.1.3" + }, + "scripts": { + "dev": "tsx watch src/index.ts", + "build": "tsc src/index.ts --outDir dist", + "start": "NODE_ENV=production node dist/index.js" + }, + "devDependencies": { + "@types/node": "^25.5.2", + "tsx": "^4.21.0", + "typescript": "^6.0.2" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..c5ab675 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,749 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@elysiajs/cors': + specifier: ^1.4.1 + version: 1.4.1(elysia@1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2)) + '@elysiajs/node': + specifier: ^1.4.5 + version: 1.4.5(elysia@1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2)) + '@sinclair/typebox': + specifier: ^0.34.49 + version: 0.34.49 + axios: + specifier: ^1.15.0 + version: 1.15.0 + elysia: + specifier: ^1.4.28 + version: 1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2) + node: + specifier: ^25.9.0 + version: 25.9.0 + openapi-types: + specifier: ^12.1.3 + version: 12.1.3 + devDependencies: + '@types/node': + specifier: ^25.5.2 + version: 25.5.2 + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^6.0.2 + version: 6.0.2 + +packages: + + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@elysiajs/cors@1.4.1': + resolution: {integrity: sha512-lQfad+F3r4mNwsxRKbXyJB8Jg43oAOXjRwn7sKUL6bcOW3KjUqUimTS+woNpO97efpzjtDE0tEjGk9DTw8lqTQ==} + peerDependencies: + elysia: '>= 1.4.0' + + '@elysiajs/node@1.4.5': + resolution: {integrity: sha512-K58HEre7RQWZOkLcMNl2RFnuZFzmUUyxHRBSfC2XaJz4j2AjrpHKu/f26tN9LRi3nx1L0PbH22vgZ4O2Fqppbw==} + peerDependencies: + elysia: '>= 1.4.0' + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@sinclair/typebox@0.34.49': + resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@types/node@25.5.2': + resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.15.0: + resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + crossws@0.4.4: + resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==} + peerDependencies: + srvx: '>=0.7.1' + peerDependenciesMeta: + srvx: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + elysia@1.4.28: + resolution: {integrity: sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg==} + peerDependencies: + '@sinclair/typebox': '>= 0.34.0 < 1' + '@types/bun': '>= 1.2.0' + exact-mirror: '>= 0.0.9' + file-type: '>= 20.0.0' + openapi-types: '>= 12.0.0' + typescript: '>= 5.0.0' + peerDependenciesMeta: + '@types/bun': + optional: true + typescript: + optional: true + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + exact-mirror@1.0.0: + resolution: {integrity: sha512-tB6QSwlyUDZh22vS4ytBjmTvpMJ7eNNqSUtH4w7TpQsE7//V+MsdWUhO0B1UptzStDFHQBCxfJPtDDiVaFfRyQ==} + peerDependencies: + typebox: '>= 1.1.0' + peerDependenciesMeta: + typebox: + optional: true + + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + + file-type@22.0.0: + resolution: {integrity: sha512-cmBmnYo8Zymabm2+qAP7jTFbKF10bQpYmxoGfuZbRFRcq00BRddJdGNH/P7GA1EMpJy5yQbqa9B7yROb3z8Ziw==} + engines: {node: '>=22'} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.7: + resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + memoirist@0.4.0: + resolution: {integrity: sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + node-bin-setup@1.1.4: + resolution: {integrity: sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA==} + + node@25.9.0: + resolution: {integrity: sha512-tfIfIRJVc32gUI+cQrxwAGWLwTy/EENnB3vF95RuAFosqBGjMTY+o0/3T4oPOipUFrsebQ5WDMsRyAqn65RMFQ==} + engines: {npm: '>=5.0.0'} + hasBin: true + + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + srvx@0.11.15: + resolution: {integrity: sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==} + engines: {node: '>=20.16.0'} + hasBin: true + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + +snapshots: + + '@borewit/text-codec@0.2.2': {} + + '@elysiajs/cors@1.4.1(elysia@1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2))': + dependencies: + elysia: 1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2) + + '@elysiajs/node@1.4.5(elysia@1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2))': + dependencies: + crossws: 0.4.4(srvx@0.11.15) + elysia: 1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2) + srvx: 0.11.15 + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@sinclair/typebox@0.34.49': {} + + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@types/node@25.5.2': + dependencies: + undici-types: 7.18.2 + + asynckit@0.4.0: {} + + axios@1.15.0: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + cookie@1.1.1: {} + + crossws@0.4.4(srvx@0.11.15): + optionalDependencies: + srvx: 0.11.15 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + delayed-stream@1.0.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + elysia@1.4.28(@sinclair/typebox@0.34.49)(exact-mirror@1.0.0)(file-type@22.0.0)(openapi-types@12.1.3)(typescript@6.0.2): + dependencies: + '@sinclair/typebox': 0.34.49 + cookie: 1.1.1 + exact-mirror: 1.0.0 + fast-decode-uri-component: 1.0.1 + file-type: 22.0.0 + memoirist: 0.4.0 + openapi-types: 12.1.3 + optionalDependencies: + typescript: 6.0.2 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + exact-mirror@1.0.0: {} + + fast-decode-uri-component@1.0.1: {} + + file-type@22.0.0: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + + follow-redirects@1.15.11: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.13.7: + dependencies: + resolve-pkg-maps: 1.0.0 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + ieee754@1.2.1: {} + + math-intrinsics@1.1.0: {} + + memoirist@0.4.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + ms@2.1.3: {} + + node-bin-setup@1.1.4: {} + + node@25.9.0: + dependencies: + node-bin-setup: 1.1.4 + + openapi-types@12.1.3: {} + + proxy-from-env@2.1.0: {} + + resolve-pkg-maps@1.0.0: {} + + srvx@0.11.15: {} + + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tsx@4.21.0: + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.13.7 + optionalDependencies: + fsevents: 2.3.3 + + typescript@6.0.2: {} + + uint8array-extras@1.5.0: {} + + undici-types@7.18.2: {} diff --git a/public/covers/0.png b/public/covers/0.png new file mode 100644 index 0000000..6b3f772 Binary files /dev/null and b/public/covers/0.png differ diff --git a/public/covers/itunes/Caravan Palace/<|°_°|>.png b/public/covers/itunes/Caravan Palace/<|°_°|>.png new file mode 100644 index 0000000..ffbf9de Binary files /dev/null and b/public/covers/itunes/Caravan Palace/<|°_°|>.png differ diff --git a/public/covers/itunes/DNCE Feat. Kent Jones/DNCE.png b/public/covers/itunes/DNCE Feat. Kent Jones/DNCE.png new file mode 100644 index 0000000..553bf57 Binary files /dev/null and b/public/covers/itunes/DNCE Feat. Kent Jones/DNCE.png differ diff --git a/public/covers/itunes/MM44 TURBO SHITPOST MACHINE/ВЕДЬМА.png b/public/covers/itunes/MM44 TURBO SHITPOST MACHINE/ВЕДЬМА.png new file mode 100644 index 0000000..3350e68 Binary files /dev/null and b/public/covers/itunes/MM44 TURBO SHITPOST MACHINE/ВЕДЬМА.png differ diff --git a/public/covers/itunes/Shadrow/Never Be Alone.png b/public/covers/itunes/Shadrow/Never Be Alone.png new file mode 100644 index 0000000..f936dea Binary files /dev/null and b/public/covers/itunes/Shadrow/Never Be Alone.png differ diff --git a/public/covers/itunes/The Electric Swing Circus/It Flew By.png b/public/covers/itunes/The Electric Swing Circus/It Flew By.png new file mode 100644 index 0000000..87b40dd Binary files /dev/null and b/public/covers/itunes/The Electric Swing Circus/It Flew By.png differ diff --git a/public/covers/itunes/Toby Fox/DELTARUNE Chapters 3+4: Original Game Soundtrack.png b/public/covers/itunes/Toby Fox/DELTARUNE Chapters 3+4: Original Game Soundtrack.png new file mode 100644 index 0000000..ab1ff20 Binary files /dev/null and b/public/covers/itunes/Toby Fox/DELTARUNE Chapters 3+4: Original Game Soundtrack.png differ diff --git a/public/covers/itunes/kmoe/K1.png b/public/covers/itunes/kmoe/K1.png new file mode 100644 index 0000000..cd20768 Binary files /dev/null and b/public/covers/itunes/kmoe/K1.png differ diff --git a/public/covers/itunes/usedcvnt w Iwakura/ultraviolet.png b/public/covers/itunes/usedcvnt w Iwakura/ultraviolet.png new file mode 100644 index 0000000..74067a5 Binary files /dev/null and b/public/covers/itunes/usedcvnt w Iwakura/ultraviolet.png differ diff --git a/public/covers/itunes/usedcvnt/ultraviolet.png b/public/covers/itunes/usedcvnt/ultraviolet.png new file mode 100644 index 0000000..74067a5 Binary files /dev/null and b/public/covers/itunes/usedcvnt/ultraviolet.png differ diff --git a/public/covers/mb/0abb7c31-4168-4b00-8834-d3e93b6362d7.png b/public/covers/mb/0abb7c31-4168-4b00-8834-d3e93b6362d7.png new file mode 100644 index 0000000..8d72404 Binary files /dev/null and b/public/covers/mb/0abb7c31-4168-4b00-8834-d3e93b6362d7.png differ diff --git a/public/covers/mb/0b5cd086-3bed-4e4d-bc9f-5199994f3b28.png b/public/covers/mb/0b5cd086-3bed-4e4d-bc9f-5199994f3b28.png new file mode 100644 index 0000000..409f03f Binary files /dev/null and b/public/covers/mb/0b5cd086-3bed-4e4d-bc9f-5199994f3b28.png differ diff --git a/public/covers/mb/145331f6-e796-422d-96c5-b8e0ca2331f0.png b/public/covers/mb/145331f6-e796-422d-96c5-b8e0ca2331f0.png new file mode 100644 index 0000000..272aafb Binary files /dev/null and b/public/covers/mb/145331f6-e796-422d-96c5-b8e0ca2331f0.png differ diff --git a/public/covers/mb/20f66e94-dd14-4cb8-8416-15244e7f7333.png b/public/covers/mb/20f66e94-dd14-4cb8-8416-15244e7f7333.png new file mode 100644 index 0000000..841c636 Binary files /dev/null and b/public/covers/mb/20f66e94-dd14-4cb8-8416-15244e7f7333.png differ diff --git a/public/covers/mb/3cb60ded-4641-4c43-93d4-a7aa8a914538.png b/public/covers/mb/3cb60ded-4641-4c43-93d4-a7aa8a914538.png new file mode 100644 index 0000000..c5c34d7 Binary files /dev/null and b/public/covers/mb/3cb60ded-4641-4c43-93d4-a7aa8a914538.png differ diff --git a/public/covers/mb/3e4c7143-2524-4dfd-bc7d-e9bf06ecfd56.png b/public/covers/mb/3e4c7143-2524-4dfd-bc7d-e9bf06ecfd56.png new file mode 100644 index 0000000..dc53433 Binary files /dev/null and b/public/covers/mb/3e4c7143-2524-4dfd-bc7d-e9bf06ecfd56.png differ diff --git a/public/covers/mb/4bc42971-4559-445f-80c6-5ae523591451.png b/public/covers/mb/4bc42971-4559-445f-80c6-5ae523591451.png new file mode 100644 index 0000000..0d13b96 Binary files /dev/null and b/public/covers/mb/4bc42971-4559-445f-80c6-5ae523591451.png differ diff --git a/public/covers/mb/5310bf5c-59ec-4a0c-9ed1-e32bcb563042.png b/public/covers/mb/5310bf5c-59ec-4a0c-9ed1-e32bcb563042.png new file mode 100644 index 0000000..aa1d3fa Binary files /dev/null and b/public/covers/mb/5310bf5c-59ec-4a0c-9ed1-e32bcb563042.png differ diff --git a/public/covers/mb/67c12991-8604-4dda-93c5-50dbf71443c7.png b/public/covers/mb/67c12991-8604-4dda-93c5-50dbf71443c7.png new file mode 100644 index 0000000..f16708e Binary files /dev/null and b/public/covers/mb/67c12991-8604-4dda-93c5-50dbf71443c7.png differ diff --git a/public/covers/mb/757d2620-e635-4178-a35c-2ff983b038e5.png b/public/covers/mb/757d2620-e635-4178-a35c-2ff983b038e5.png new file mode 100644 index 0000000..869ad64 Binary files /dev/null and b/public/covers/mb/757d2620-e635-4178-a35c-2ff983b038e5.png differ diff --git a/public/covers/mb/9e3e27f7-cda8-4f1d-90fb-318dfe464bcd.png b/public/covers/mb/9e3e27f7-cda8-4f1d-90fb-318dfe464bcd.png new file mode 100644 index 0000000..a5ff7a0 Binary files /dev/null and b/public/covers/mb/9e3e27f7-cda8-4f1d-90fb-318dfe464bcd.png differ diff --git a/public/covers/mb/aa771a7d-8ac3-485c-8f10-6a7d52046fce.png b/public/covers/mb/aa771a7d-8ac3-485c-8f10-6a7d52046fce.png new file mode 100644 index 0000000..657e34c Binary files /dev/null and b/public/covers/mb/aa771a7d-8ac3-485c-8f10-6a7d52046fce.png differ diff --git a/public/covers/mb/aab00c2a-fff5-475d-97a7-b518c222d416.png b/public/covers/mb/aab00c2a-fff5-475d-97a7-b518c222d416.png new file mode 100644 index 0000000..e13999c Binary files /dev/null and b/public/covers/mb/aab00c2a-fff5-475d-97a7-b518c222d416.png differ diff --git a/public/covers/mb/af260870-9807-4802-a57b-cc17b81a07af.png b/public/covers/mb/af260870-9807-4802-a57b-cc17b81a07af.png new file mode 100644 index 0000000..92424e8 Binary files /dev/null and b/public/covers/mb/af260870-9807-4802-a57b-cc17b81a07af.png differ diff --git a/public/covers/mb/bb08dc6c-7697-475e-bb7a-be4a85703b20.png b/public/covers/mb/bb08dc6c-7697-475e-bb7a-be4a85703b20.png new file mode 100644 index 0000000..d5fcb81 Binary files /dev/null and b/public/covers/mb/bb08dc6c-7697-475e-bb7a-be4a85703b20.png differ diff --git a/public/covers/mb/dbb447f8-8d3a-4dd1-a6ac-03dac2e0d859.png b/public/covers/mb/dbb447f8-8d3a-4dd1-a6ac-03dac2e0d859.png new file mode 100644 index 0000000..4af3b26 Binary files /dev/null and b/public/covers/mb/dbb447f8-8d3a-4dd1-a6ac-03dac2e0d859.png differ diff --git a/public/covers/mb/f4b76ce1-6b47-4be8-a4e4-7b4acd63a3ac.png b/public/covers/mb/f4b76ce1-6b47-4be8-a4e4-7b4acd63a3ac.png new file mode 100644 index 0000000..f31a0e3 Binary files /dev/null and b/public/covers/mb/f4b76ce1-6b47-4be8-a4e4-7b4acd63a3ac.png differ diff --git a/src/download_cover.ts b/src/download_cover.ts new file mode 100644 index 0000000..b92abf8 --- /dev/null +++ b/src/download_cover.ts @@ -0,0 +1,77 @@ +import axios from "axios"; +import fs from "node:fs"; + +export async function download_image_from_caa(mbid: string) { + console.log("[DEBUG]: download_image_from_caa:", mbid); + try { + const response = await axios.get( + `http://coverartarchive.org/release/${mbid}`, + ); + const img_response = await axios.get( + response.data.images[0].thumbnails["250"], + { + responseType: "arraybuffer", + }, + ); + + fs.writeFileSync(`public/covers/mb/${mbid}.png`, img_response.data); + } catch (error) { + console.error("Error fetching data:", error); + throw error; + } +} + +export async function itunes_cover_url(artist: string, album: string) { + artist = ( + artist.toLowerCase().split(/\s+feat\.?|\s+w\s*|\s+&\s+/)[0] || artist + ).trim(); + + let query = `${artist} ${album}` + .replace(/\([^)]*\)/g, "") + .replace(/\[[^\]]*\]/g, "") + .replace(/[-_,"':;|]/g, " ") + .toLowerCase(); + + const apple_music_results = await fetch("https://itunes.apple.com/search", { + body: new URLSearchParams({ + term: query, + entity: "song", + limit: "10", + }), + method: "POST", + }).then((res) => res.json()); + + for (let result of apple_music_results.results) { + if (artist == result.artistName.toLowerCase()) { + return result.artworkUrl100.replace("100x100bb.jpg", "200x200bb.png"); + } + } +} + +export async function download_image_from_itunes( + artist: string, + album: string, +) { + console.log("[DEBUG]: download_image_from_itunes:", artist, album); + try { + const itunes_url = await itunes_cover_url(artist, album); + + if (!itunes_url) { + throw new Error(`iTunes URL not found for ${artist} - ${album}`); + } + + const artist_dir = `public/covers/itunes/${artist}`; + if (!fs.existsSync(artist_dir)) { + fs.mkdirSync(artist_dir, { recursive: true }); + } + + const img_response = await axios.get(itunes_url, { + responseType: "arraybuffer", + }); + + fs.writeFileSync(`${artist_dir}/${album}.png`, img_response.data); + } catch (error) { + console.error("Error fetching data:", error); + throw error; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..3907f94 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,63 @@ +import { Elysia } from "elysia"; +import { cors } from "@elysiajs/cors"; +import { node } from "@elysiajs/node"; + +import fs from "node:fs"; + +import { + download_image_from_caa, + download_image_from_itunes, +} from "./download_cover.js"; + +export const app = new Elysia({ adapter: node() }); + +app.use(cors()); + +app.get("/", () => "snusxd-api"); +app.get("/cover/:artist/:album/:id", ({ params: { artist, album, id } }) => + get_image_from_server(artist, album, id), +); + +app.listen(3000, ({ hostname, port }) => { + console.log(`🦊 Elysia is running at ${hostname}:${port}`); +}); + +async function get_image_from_server( + artist: string, + album: string, + mbid: string, +) { + const MBFilePath = `public/covers/mb/${mbid}.png`; + const iTunesFilePath = `public/covers/itunes/${artist}/${album}.png`; + + let resultFilePath = MBFilePath; + + if (fs.existsSync(MBFilePath) || fs.existsSync(iTunesFilePath)) { + if (fs.existsSync(MBFilePath)) resultFilePath = MBFilePath; + else resultFilePath = iTunesFilePath; + console.log("[DEBUG]: cover found on server"); + } else { + try { + await download_image_from_itunes(artist, album); + resultFilePath = iTunesFilePath; + } catch (first_error) { + try { + await download_image_from_caa(mbid); + resultFilePath = MBFilePath; + } catch (secong_error) { + console.error( + "There's two errors while searching covers:", + first_error, + secong_error, + ); + resultFilePath = "public/covers/0.png"; + } + } + } + + return new Response(fs.createReadStream(resultFilePath) as any, { + headers: { + "Content-Type": "image/png", + }, + }); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3757a92 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,42 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + // "outDir": "./dist", + // Environment Settings + // See also https://aka.ms/tsconfig/module + "target": "esnext", + "types": [ + "node" + ], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + "module": "NodeNext", // or "ESNext" + "moduleResolution": "NodeNext", // or "Bundler" + } +} \ No newline at end of file