Initial commit v2

This commit is contained in:
0d0 2025-01-30 02:04:13 +01:00
parent 6266831532
commit c6629b387f
8 changed files with 634 additions and 40 deletions

2
.gitignore vendored
View file

@ -21,3 +21,5 @@ Thumbs.db
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
downloads

View file

@ -1,38 +0,0 @@
# sv
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npx sv create
# create a new project in my-app
npx sv create my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.

View file

@ -35,5 +35,8 @@
"typescript": "^5.0.0",
"typescript-eslint": "^8.20.0",
"vite": "^6.0.0"
},
"dependencies": {
"youtube-dl-exec": "^3.0.13"
}
}

351
pnpm-lock.yaml generated
View file

@ -7,6 +7,10 @@ settings:
importers:
.:
dependencies:
youtube-dl-exec:
specifier: ^3.0.13
version: 3.0.13
devDependencies:
'@eslint/compat':
specifier: ^1.2.5
@ -299,6 +303,10 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@jclem/logfmt2@2.4.3':
resolution: {integrity: sha512-d7zluLlx+JRtVICF0+ghcrVdXBdE3eXrpIuFdcCcWxA3ABOyemkTySG4ha2AdsWFwAnh8tkB1vtyeZsWAbLumg==}
engines: {node: '>= 14.x', npm: '>= 7.x'}
'@jridgewell/gen-mapping@0.3.8':
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
engines: {node: '>=6.0.0'}
@ -317,6 +325,10 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@kikobeats/time-span@1.0.5':
resolution: {integrity: sha512-txRAdmi35N1wnsLS1AO5mTlbY5Cv5/61WXqek2y3L9Q7u4mgdUVq819so5xe753hL5gYeLzlWoJ/VJfXg9nx8g==}
engines: {node: '>= 18'}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -591,10 +603,19 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
bin-version-check@6.0.0:
resolution: {integrity: sha512-k9TS/pADINX9UlErjAkbkxDer8C+WlguMwySI8sLMGLUMDvwuHmDx00yoHe7nxshgwtLBcMWQgrlwjzscUeQKg==}
engines: {node: '>=18'}
deprecated: 'Renamed to binary-version-check: https://www.npmjs.com/package/binary-version-check'
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
binary-version@7.1.0:
resolution: {integrity: sha512-Iy//vPc3ANPNlIWd242Npqc8MK0a/i4kVcHDlDA6HNMv5zMxz4ulIFhOSYJVKw/8AbHdHy0CnGYEt1QqSXxPsw==}
engines: {node: '>=18'}
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@ -651,6 +672,10 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
convert-hrtime@5.0.0:
resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==}
engines: {node: '>=12'}
cookie@0.6.0:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
@ -664,6 +689,22 @@ packages:
engines: {node: '>=4'}
hasBin: true
d@1.0.2:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'}
dargs@7.0.0:
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
engines: {node: '>=8'}
debug-fabulous@2.0.2:
resolution: {integrity: sha512-XfAbX8/owqC+pjIg0/+3V1gp8TugJT7StX/TE1TYedjrRf7h7SgUAL/+gKoAQGPCLbSU5L5LPvDg4/cGn1E/WA==}
engines: {node: '>= 8'}
debug-logfmt@1.2.3:
resolution: {integrity: sha512-Btc8hrSu2017BcECwhnkKtA7+9qBRv06x8igvJRRyDcZo1cmEbwp/OmLDSJFuJ/wgrdF7TbtGeVV6FCxagJoNQ==}
engines: {node: '>= 8'}
debug@4.4.0:
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
engines: {node: '>=6.0'}
@ -701,6 +742,20 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
es5-ext@0.10.64:
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
engines: {node: '>=0.10'}
es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
es6-symbol@3.1.4:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'}
es6-weak-map@2.0.3:
resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
esbuild@0.24.2:
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
engines: {node: '>=18'}
@ -765,6 +820,10 @@ packages:
esm-env@1.2.2:
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
esniff@2.0.1:
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
engines: {node: '>=0.10'}
espree@10.3.0:
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -792,6 +851,16 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@ -828,6 +897,10 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
find-versions@6.0.0:
resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==}
engines: {node: '>=18'}
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@ -850,6 +923,14 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
function-timeout@1.0.2:
resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==}
engines: {node: '>=18'}
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -881,6 +962,10 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@ -920,9 +1005,20 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-promise@2.2.2:
resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
is-reference@3.0.3:
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
is-unix@2.0.10:
resolution: {integrity: sha512-CcasZSEOQUoE7JHy56se4wyRhdJfjohuMWYmceSTaDY4naKyd1fpLiY8rJsIT6AKfVstQAhHJOfPx7jcUxK61Q==}
engines: {node: '>= 12'}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@ -990,9 +1086,19 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-queue@0.1.0:
resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
memoizee@0.4.17:
resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==}
engines: {node: '>=0.12'}
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -1001,6 +1107,10 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
mini-svg-data-uri@1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true
@ -1038,6 +1148,9 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
@ -1049,6 +1162,10 @@ packages:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
engines: {node: '>=0.10.0'}
npm-run-path@5.3.0:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@ -1057,6 +1174,10 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@ -1076,6 +1197,10 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
parse-ms@2.1.0:
resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==}
engines: {node: '>=6'}
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -1084,6 +1209,10 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-key@4.0.0:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@ -1245,6 +1374,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
pretty-ms@7.0.1:
resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==}
engines: {node: '>=10'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@ -1288,6 +1421,14 @@ packages:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
semver-regex@4.0.5:
resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==}
engines: {node: '>=12'}
semver-truncate@3.0.0:
resolution: {integrity: sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==}
engines: {node: '>=12'}
semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
@ -1332,6 +1473,10 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@ -1341,6 +1486,10 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
super-regex@1.0.0:
resolution: {integrity: sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==}
engines: {node: '>=18'}
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@ -1382,6 +1531,18 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
time-span@5.1.0:
resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==}
engines: {node: '>=12'}
timers-ext@0.1.8:
resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==}
engines: {node: '>=0.12'}
tinyspawn@1.3.3:
resolution: {integrity: sha512-CvvMFgecnQMyg59nOnAD5O4lV83cVj2ooDniJ3j2bYvMajqlK4wQ13k6OUHfA+J5nkInTxbSGJv2olUJIiAtJg==}
engines: {node: '>= 18'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@ -1403,6 +1564,9 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
type@2.7.3:
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
typescript-eslint@8.21.0:
resolution: {integrity: sha512-txEKYY4XMKwPXxNkN8+AxAdX6iIJAPiJbHE/FpQccs/sxw8Lf26kqwC3cn0xkHlW8kEbLhkhCsjWuMveaY9Rxw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1505,6 +1669,10 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
youtube-dl-exec@3.0.13:
resolution: {integrity: sha512-xMCKTHGSEDCshEIwzAGRsysBVoXsLePLvEq/oOAU5gSP1kjgyHx+fiwNqO8RJZbt4LxuJG9foT6cy7iNbTqNhg==}
engines: {node: '>= 18'}
zimmerframe@1.1.2:
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
@ -1660,6 +1828,8 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@jclem/logfmt2@2.4.3': {}
'@jridgewell/gen-mapping@0.3.8':
dependencies:
'@jridgewell/set-array': 1.2.1
@ -1677,6 +1847,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
'@kikobeats/time-span@1.0.5': {}
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@ -1945,8 +2117,19 @@ snapshots:
balanced-match@1.0.2: {}
bin-version-check@6.0.0:
dependencies:
binary-version: 7.1.0
semver: 7.6.3
semver-truncate: 3.0.0
binary-extensions@2.3.0: {}
binary-version@7.1.0:
dependencies:
execa: 8.0.1
find-versions: 6.0.0
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
@ -2006,6 +2189,8 @@ snapshots:
concat-map@0.0.1: {}
convert-hrtime@5.0.0: {}
cookie@0.6.0: {}
cross-spawn@7.0.6:
@ -2016,6 +2201,29 @@ snapshots:
cssesc@3.0.0: {}
d@1.0.2:
dependencies:
es5-ext: 0.10.64
type: 2.7.3
dargs@7.0.0: {}
debug-fabulous@2.0.2:
dependencies:
debug: 4.4.0
memoizee: 0.4.17
transitivePeerDependencies:
- supports-color
debug-logfmt@1.2.3:
dependencies:
'@jclem/logfmt2': 2.4.3
'@kikobeats/time-span': 1.0.5
debug-fabulous: 2.0.2
pretty-ms: 7.0.1
transitivePeerDependencies:
- supports-color
debug@4.4.0:
dependencies:
ms: 2.1.3
@ -2038,6 +2246,31 @@ snapshots:
emoji-regex@9.2.2: {}
es5-ext@0.10.64:
dependencies:
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esniff: 2.0.1
next-tick: 1.1.0
es6-iterator@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-symbol: 3.1.4
es6-symbol@3.1.4:
dependencies:
d: 1.0.2
ext: 1.7.0
es6-weak-map@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esbuild@0.24.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.24.2
@ -2155,6 +2388,13 @@ snapshots:
esm-env@1.2.2: {}
esniff@2.0.1:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
event-emitter: 0.3.5
type: 2.7.3
espree@10.3.0:
dependencies:
acorn: 8.14.0
@ -2183,6 +2423,27 @@ snapshots:
esutils@2.0.3: {}
event-emitter@0.3.5:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
execa@8.0.1:
dependencies:
cross-spawn: 7.0.6
get-stream: 8.0.1
human-signals: 5.0.0
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.3.0
onetime: 6.0.0
signal-exit: 4.1.0
strip-final-newline: 3.0.0
ext@1.7.0:
dependencies:
type: 2.7.3
fast-deep-equal@3.1.3: {}
fast-glob@3.3.3:
@ -2216,6 +2477,11 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
find-versions@6.0.0:
dependencies:
semver-regex: 4.0.5
super-regex: 1.0.0
flat-cache@4.0.1:
dependencies:
flatted: 3.3.2
@ -2235,6 +2501,10 @@ snapshots:
function-bind@1.1.2: {}
function-timeout@1.0.2: {}
get-stream@8.0.1: {}
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@ -2264,6 +2534,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
human-signals@5.0.0: {}
ignore@5.3.2: {}
import-fresh@3.3.0:
@ -2293,10 +2565,16 @@ snapshots:
is-number@7.0.0: {}
is-promise@2.2.2: {}
is-reference@3.0.3:
dependencies:
'@types/estree': 1.0.6
is-stream@3.0.0: {}
is-unix@2.0.10: {}
isexe@2.0.0: {}
jackspeak@3.4.3:
@ -2350,10 +2628,27 @@ snapshots:
lru-cache@10.4.3: {}
lru-queue@0.1.0:
dependencies:
es5-ext: 0.10.64
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
memoizee@0.4.17:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-weak-map: 2.0.3
event-emitter: 0.3.5
is-promise: 2.2.2
lru-queue: 0.1.0
next-tick: 1.1.0
timers-ext: 0.1.8
merge-stream@2.0.0: {}
merge2@1.4.1: {}
micromatch@4.0.8:
@ -2361,6 +2656,8 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
mimic-fn@4.0.0: {}
mini-svg-data-uri@1.4.4: {}
minimatch@3.1.2:
@ -2389,16 +2686,26 @@ snapshots:
natural-compare@1.4.0: {}
next-tick@1.1.0: {}
node-releases@2.0.19: {}
normalize-path@3.0.0: {}
normalize-range@0.1.2: {}
npm-run-path@5.3.0:
dependencies:
path-key: 4.0.0
object-assign@4.1.1: {}
object-hash@3.0.0: {}
onetime@6.0.0:
dependencies:
mimic-fn: 4.0.0
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@ -2422,10 +2729,14 @@ snapshots:
dependencies:
callsites: 3.1.0
parse-ms@2.1.0: {}
path-exists@4.0.0: {}
path-key@3.1.1: {}
path-key@4.0.0: {}
path-parse@1.0.7: {}
path-scurry@1.11.1:
@ -2513,6 +2824,10 @@ snapshots:
prettier@3.4.2: {}
pretty-ms@7.0.1:
dependencies:
parse-ms: 2.1.0
punycode@2.3.1: {}
queue-microtask@1.2.3: {}
@ -2570,6 +2885,12 @@ snapshots:
dependencies:
mri: 1.2.0
semver-regex@4.0.5: {}
semver-truncate@3.0.0:
dependencies:
semver: 7.6.3
semver@7.6.3: {}
set-cookie-parser@2.7.1: {}
@ -2610,6 +2931,8 @@ snapshots:
dependencies:
ansi-regex: 6.1.0
strip-final-newline@3.0.0: {}
strip-json-comments@3.1.1: {}
sucrase@3.35.0:
@ -2622,6 +2945,11 @@ snapshots:
pirates: 4.0.6
ts-interface-checker: 0.1.13
super-regex@1.0.0:
dependencies:
function-timeout: 1.0.2
time-span: 5.1.0
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@ -2702,6 +3030,17 @@ snapshots:
dependencies:
any-promise: 1.3.0
time-span@5.1.0:
dependencies:
convert-hrtime: 5.0.0
timers-ext@0.1.8:
dependencies:
es5-ext: 0.10.64
next-tick: 1.1.0
tinyspawn@1.3.3: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@ -2718,6 +3057,8 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
type@2.7.3: {}
typescript-eslint@8.21.0(eslint@9.18.0(jiti@1.21.7))(typescript@5.7.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.18.0(jiti@1.21.7))(typescript@5.7.3)
@ -2780,4 +3121,14 @@ snapshots:
yocto-queue@0.1.0: {}
youtube-dl-exec@3.0.13:
dependencies:
bin-version-check: 6.0.0
dargs: 7.0.0
debug-logfmt: 1.2.3
is-unix: 2.0.10
tinyspawn: 1.3.3
transitivePeerDependencies:
- supports-color
zimmerframe@1.1.2: {}

View file

@ -5,6 +5,27 @@
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
background: black; /* Fallback */
background-image: radial-gradient(circle, #37ff1456 8%, transparent 8%),
radial-gradient(circle, #37ff1456 8%, transparent 8%);
background-size:
60px 60px,
30px 30px; /* Larger grid sizes for more spacing */
background-position:
0 0,
15px 15px; /* Offset the smaller pattern slightly */
font-family: "Press Start 2P", sans-serif;
color: #37ff1456; /* Retro green text */
margin: 0;
}
</style>
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>

View file

@ -0,0 +1,6 @@
<div
class="absolute inset-0 z-10 flex items-center justify-center bg-white bg-opacity-50"
id="spinner"
>
<div class="h-20 w-20 animate-spin rounded-full border-b-2 border-t-2 border-gray-900"></div>
</div>

View file

@ -0,0 +1,42 @@
import { DOWNLOAD_PATH } from "$env/static/private";
import { redirect } from "@sveltejs/kit";
import youtubedl from "youtube-dl-exec";
export const actions = {
download: async ({ request, cookies }) => {
const data = await request.formData();
const obj = {};
for (const element of data) {
obj[element[0]] = element[1];
}
const { format, source, link } = obj;
if (!(format && source && link)) {
throw redirect(307, "/");
}
console.info(`Asked ${source} download of ${link}`);
switch (source) {
case "youtube":
const output = await youtubedl(link, {
output: `${DOWNLOAD_PATH}/%(artist)s-%(title)s.%(ext)s`,
embedThumbnail: true,
audioFormat: format
});
console.log(output);
console.info(`Downloaded ${link} to ${output}`);
break;
case "spotify":
break;
default:
console.error("ops");
}
return { success: true };
},
};

View file

@ -1,2 +1,209 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<script>
let source = $state("youtube");
let link = $state("");
let format = "mp3";
let showModal = false;
const toggleModal = () => {
showModal = !showModal;
};
const handleSubmit = (e) => {
e.preventDefault();
console.log({
source,
link,
format,
});
};
$effect(() => {
// Auto selected the radio button based on url regex
if (link.includes('spotify')) {
source = 'spotify'
} else if (link.includes('youtube')) {
source = 'youtube'
}
})
</script>
<div
class="relative sm:max-w-sm md:max-w-md lg:max-w-lg 2xl:max-w-2xl mx-auto mt-10 p-6 bg-black text-green-500 rounded-lg shadow-lg border-4 border-green-500"
>
<!-- Info Icon -->
<button
onclick={toggleModal}
class="absolute top-3 right-3 text-pink-500 hover:text-pink-300 transition"
aria-label="Open Info Modal"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
class="w-6 h-6"
viewBox="0 0 24 24"
>
<path
d="M12 0C5.373 0 0 5.373 0 12c0 6.627 5.373 12 12 12s12-5.373 12-12C24 5.373 18.627 0 12 0zm.75 18h-1.5v-6h1.5v6zm0-8h-1.5V8h1.5v2z"
/>
</svg>
</button>
<h1 class="text-xl text-center mb-6">🐙 Scaricatore 🐙</h1>
<form method="POST" action="?/download" class="space-y-6">
<!-- Source Selection -->
<fieldset class="space-y-4">
<legend class="text-green-400 text-sm">Choose Source:</legend>
<label class="flex items-center space-x-3">
<input
type="radio"
name="source"
value="youtube"
bind:group={source}
class="retro-radio"
/>
<span>YouTube</span>
</label>
<label class="flex items-center space-x-3">
<input
type="radio"
name="source"
value="spotify"
bind:group={source}
class="retro-radio"
/>
<span>Spotify</span>
</label>
<label class="flex items-center space-x-3">
<input
type="radio"
name="source"
value="other"
bind:group={source}
class="retro-radio"
/>
<span>
Other (<a
href="https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md"
target="_blank"
rel="noopener noreferrer"
class="text-pink-500 hover:underline"
>supported sites
</a>)
</span>
</label>
</fieldset>
<!-- Link Input -->
<div>
<label for="link" class="block text-green-400 text-sm mb-2">
Enter Playlist or Video Link:
</label>
<input
name="link"
type="url"
id="link"
bind:value={link}
required
placeholder="Paste your link here"
class="w-full px-4 py-3 text-black bg-green-200 border-4 border-green-500 rounded-lg focus:outline-none focus:border-pink-500"
/>
</div>
<!-- Format Selection -->
<div>
<label for="format" class="block text-green-400 text-sm mb-2">
Choose Format:
</label>
<select
id="format"
name="format"
bind:value={format}
class="w-full px-4 py-3 text-black bg-green-200 border-4 border-green-500 rounded-lg focus:outline-none focus:border-pink-500"
>
<option value="mp3">MP3</option>
<option value="ogg">OGG</option>
<option value="mp4">MP4</option>
</select>
</div>
<!-- Submit Button -->
<button
type="submit"
class="w-full px-4 py-3 text-black bg-pink-500 border-4 border-pink-700 rounded-lg hover:bg-pink-600 active:border-yellow-500 transition"
>
Start Download!
</button>
</form>
</div>
<!-- Modal -->
{#if showModal}
<div
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-80 z-50"
>
<div
class="w-4/5 max-w-lg bg-green-900 text-green-100 p-6 rounded-lg border-4 border-green-500 text-center"
>
<h2 class="text-lg mb-4"> Retro Media Downloader Info</h2>
<p class="text-sm">
This app allows you to download Spotify playlists and YouTube videos
directly. Choose your source, paste the link, and select a format to
start downloading!
</p>
<button
onclick={toggleModal}
class="mt-6 px-4 py-2 bg-pink-500 text-black border-4 border-pink-700 rounded-lg hover:bg-pink-600"
>
Close
</button>
</div>
</div>
{/if}
<!-- Footer -->
<footer
class="absolute bottom-0 w-[100dvw] mt-10 bg-black text-green-500 text-center py-4 border-t-4 border-green-500"
>
Copyleft © 2024 - Made with ❤️ by Emersa
</footer>
<style>
@import url("https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap");
* {
font-family: "Press Start 2P", sans-serif;
}
.retro-radio {
appearance: none;
background-color: #000;
border: 2px solid #39ff14;
width: 20px;
height: 20px;
cursor: pointer;
}
.retro-radio:checked {
background-color: #39ff14;
box-shadow:
0 0 4px #39ff14,
0 0 10px #39ff14;
}
input[type="url"],
select {
font-family: inherit;
}
.retro-container {
max-width: 800px;
margin: auto;
padding: 20px;
background: rgba(0, 0, 0, 0.8); /* Semi-transparent black */
border: 4px solid #39ff14;
border-radius: 8px;
box-shadow: 0 0 20px #39ff14;
}
</style>