diff --git a/.github/test.sh b/.github/test.sh new file mode 100755 index 00000000..85683b91 --- /dev/null +++ b/.github/test.sh @@ -0,0 +1,73 @@ +#!/bin/bash +set -e + +# thx: https://stackoverflow.com/a/27601038 +waitport() { + ATTEMPTS=50 + while [ $((ATTEMPTS-=1)) -gt 0 ] && ! nc -z localhost $1; do + sleep 0.1 + done + + [ "$ATTEMPTS" != 0 ] || exit 1 +} + +test_api() { + waitport 3000 + curl -m 3 http://localhost:3000/api/serverInfo + API_RESPONSE=$(curl -m 3 http://localhost:3000/api/json \ + -X POST \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + -d '{"url":"https://www.youtube.com/watch?v=jNQXAC9IVRw"}') + + echo "$API_RESPONSE" + STATUS=$(echo "$API_RESPONSE" | jq -r .status) + STREAM_URL=$(echo "$API_RESPONSE" | jq -r .url) + [ "$STATUS" = stream ] || exit 1; + + CONTENT_LENGTH=$(curl -I -m 3 "$STREAM_URL" \ + | grep -i content-length \ + | cut -d' ' -f2 \ + | tr -d '\r') + + echo "$CONTENT_LENGTH" + [ "$CONTENT_LENGTH" = 0 ] && exit 1 + if [ "$CONTENT_LENGTH" -lt 512 ]; then + exit 1 + fi +} + +test_web() { + waitport 3001 + curl -m 3 http://127.0.0.1:3001/onDemand?blockId=0 \ + | grep -q '"status":"success"' +} + +setup_api() { + export API_PORT=3000 + export API_URL=http://localhost:3000 + timeout 10 npm run start +} + +setup_web() { + export WEB_PORT=3001 + export WEB_URL=http://localhost:3001 + export API_URL=http://localhost:3000 + timeout 5 npm run start +} + +cd "$(git rev-parse --show-toplevel)" +npm i + +if [ "$1" = "api" ]; then + setup_api & + test_api +elif [ "$1" = "web" ]; then + setup_web & + test_web +else + echo "usage: $0 " >&2 + exit 1 +fi + +wait || exit $? \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0d166c74..ee3d757b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -55,3 +55,5 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..1a02c125 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Run tests + +on: + pull_request: + push: + branches: [ current ] + +jobs: + test-web: + name: web sanity check + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run test script + run: .github/test.sh web + + test-api: + name: api sanity check + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run test script + run: .github/test.sh api \ No newline at end of file diff --git a/.gitignore b/.gitignore index a21273d6..a7c47612 100644 --- a/.gitignore +++ b/.gitignore @@ -4,18 +4,10 @@ desktop.ini # npm node_modules -package-lock.json # secrets .env -# page build -min -build - -# stuff i already made but delayed -future - # docker docker-compose.yml @@ -24,3 +16,6 @@ docker-compose.yml # cookie file cookies.json + +# page build +build diff --git a/Dockerfile b/Dockerfile index c98785d9..0896c116 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,10 @@ WORKDIR /app COPY package*.json ./ -RUN apt-get update && \ - apt-get install -y git python3 build-essential && \ - npm install && \ +RUN apt-get update && \ + apt-get install -y git python3 build-essential && \ + npm ci && \ + npm cache clean --force && \ apt purge --autoremove -y python3 build-essential && \ rm -rf ~/.cache/ /var/lib/apt/lists/* diff --git a/LICENSE b/LICENSE index f79473af..7d1945a3 100644 --- a/LICENSE +++ b/LICENSE @@ -629,8 +629,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - cobalt is possibly the nicest social media downloader out there. - Copyright (C) 2022 wukko + save what you love with cobalt. + Copyright (C) 2024 imput This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by diff --git a/README.md b/README.md index 8beeb3ea..b95d55e5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ best way to save what you love: [cobalt.tools](https://cobalt.tools/) ![cobalt logo with repeated logo (double arrow) pattern background](/src/front/icons/pattern.png "cobalt logo with repeated logo (double arrow) pattern background") +[💬 community discord server](https://discord.gg/pQPt8HBUPu) +[🐦 twitter/x](https://x.com/justusecobalt) + ## what's cobalt? cobalt is a media downloader that doesn't piss you off. it's fast, friendly, and doesn't have any bullshit that modern web is filled with: ***no ads, trackers, or invasive analytics***. @@ -15,8 +18,7 @@ this list is not final and keeps expanding over time. if support for a service y | :-------- | :-----------: | :--------: | :--------: | :------: | :-------------: | | bilibili.com & bilibili.tv | ✅ | ✅ | ✅ | ➖ | ➖ | | dailymotion | ✅ | ✅ | ✅ | ✅ | ✅ | -| instagram posts & stories | ✅ | ✅ | ✅ | ➖ | ➖ | -| instagram reels | ✅ | ✅ | ✅ | ➖ | ➖ | +| instagram posts & reels | ✅ | ✅ | ✅ | ➖ | ➖ | | ok video | ✅ | ❌ | ❌ | ✅ | ✅ | | pinterest | ✅ | ✅ | ✅ | ➖ | ➖ | | reddit | ✅ | ✅ | ✅ | ❌ | ❌ | @@ -42,7 +44,7 @@ this list is not final and keeps expanding over time. if support for a service y ### additional notes or features (per service) | service | notes or features | | :-------- | :----- | -| instagram | supports photos, videos, and stories. lets you pick what to save from multi-media posts. | +| instagram | supports reels, photos, and videos. lets you pick what to save from multi-media posts. | | pinterest | supports photos, gifs, videos and stories. | | reddit | supports gifs and videos. | | snapchat | supports spotlights and stories. lets you pick what to save from stories. | @@ -55,7 +57,7 @@ this list is not final and keeps expanding over time. if support for a service y ## cobalt api cobalt has an open api that you can use in your projects *for free~*. it's easy and straightforward to use, [check out the docs](/docs/api.md) to learn how to use it. -✅ you can use the main api instance ([co.wuk.sh](https://co.wuk.sh/)) in your **personal** projects. +✅ you can use the main api instance ([api.cobalt.tools](https://api.cobalt.tools/)) in your **personal** projects. ❌ you cannot use the free api commercially (anywhere that's gated behind paywalls or ads). host your own instance for this. we reserve the right to restrict abusive/excessive access to the main instance api. @@ -64,8 +66,8 @@ we reserve the right to restrict abusive/excessive access to the main instance a if you want to run your own instance for whatever purpose, [follow this guide](/docs/run-an-instance.md). it's *highly* recommended to use a docker compose method unless you run for developing/debugging purposes. -## sponsors -cobalt is sponsored by [royalehosting.net](https://royalehosting.net/), all main instances are currently hosted on their network :) +## partners +cobalt is sponsored by [royalehosting.net](https://royalehosting.net/?partner=cobalt), all main instances are currently hosted on their network :) ## ethics and disclaimer cobalt is a tool for easing content downloads from internet and takes ***zero liability***. you are responsible for what you download, how you use and distribute that content. please be mindful when using content of others and always credit original creators. fair use and credits benefit everyone. diff --git a/docs/api.md b/docs/api.md index 57509669..87ef2489 100644 --- a/docs/api.md +++ b/docs/api.md @@ -2,7 +2,7 @@ this document provides info about methods and acceptable variables for all cobalt api requests. ``` -👍 you can use co.wuk.sh instance in your projects for free, just don't be an asshole. +👍 you can use api.cobalt.tools in your projects for free, just don't be an asshole. ``` ## POST: `/api/json` diff --git a/docs/examples/docker-compose.example.yml b/docs/examples/docker-compose.example.yml index 24212ae4..fcbcfc63 100644 --- a/docs/examples/docker-compose.example.yml +++ b/docs/examples/docker-compose.example.yml @@ -17,8 +17,8 @@ services: #- 127.0.0.1:9000:9000 environment: - # replace https://co.wuk.sh/ with your instance's target url in same format - API_URL: "https://co.wuk.sh/" + # replace https://api.cobalt.tools/ with your instance's target url in same format + API_URL: "https://api.cobalt.tools/" # replace eu-nl with your instance's distinctive name API_NAME: "eu-nl" # if you want to use cookies when fetching data from services, uncomment the next line and the lines under volume @@ -49,8 +49,8 @@ services: environment: # replace https://cobalt.tools/ with your instance's target url in same format WEB_URL: "https://cobalt.tools/" - # replace https://co.wuk.sh/ with preferred api instance url - API_URL: "https://co.wuk.sh/" + # replace https://api.cobalt.tools/ with preferred api instance url + API_URL: "https://api.cobalt.tools/" labels: - com.centurylinklabs.watchtower.scope=cobalt @@ -59,6 +59,6 @@ services: watchtower: image: ghcr.io/containrrr/watchtower restart: unless-stopped - command: --cleanup --scope cobalt --interval 900 + command: --cleanup --scope cobalt --interval 900 --include-restarting volumes: - /var/run/docker.sock:/var/run/docker.sock diff --git a/docs/run-an-instance.md b/docs/run-an-instance.md index 25145224..a440d11d 100644 --- a/docs/run-an-instance.md +++ b/docs/run-an-instance.md @@ -35,13 +35,13 @@ it's highly recommended to use a reverse proxy (such as nginx) if you want your ## using regular node.js (useful for local development) setup script installs all needed `npm` dependencies, but you have to install `node.js` *(version 18 or above)* and `git` yourself. -1. clone the repo: `git clone https://github.com/wukko/cobalt`. +1. clone the repo: `git clone https://github.com/imputnet/cobalt`. 2. run setup script and follow instructions: `npm run setup`. you need to host api and web instances separately, so pick whichever applies. 3. run cobalt via `npm start`. 4. done. ### ubuntu 22.04 workaround -`nscd` needs to be installed and running so that the `ffmpeg-static` binary can resolve DNS ([#101](https://github.com/wukko/cobalt/issues/101#issuecomment-1494822258)): +`nscd` needs to be installed and running so that the `ffmpeg-static` binary can resolve DNS ([#101](https://github.com/imputnet/cobalt/issues/101#issuecomment-1494822258)): ```bash sudo apt install nscd @@ -52,41 +52,21 @@ sudo service nscd start ### variables for api | variable name | default | example | description | |:----------------------|:----------|:------------------------|:------------| -| `API_PORT` | `9000` | `9000` | changes port from which api server is accessible. | -| `API_LISTEN_ADDRESS` | `0.0.0.0` | `127.0.0.1` | changes address from which api server is accessible. **if you are using docker, you usually don't need to configure this.** | -| `API_URL` | ➖ | `https://co.wuk.sh/` | changes url from which api server is accessible.
***REQUIRED TO RUN API***. | +| `API_PORT` | `9000` | `9000` | changes port from which api server is accessible. | +| `API_LISTEN_ADDRESS` | `0.0.0.0` | `127.0.0.1` | changes address from which api server is accessible. **if you are using docker, you usually don't need to configure this.** | +| `API_URL` | ➖ | `https://api.cobalt.tools/` | changes url from which api server is accessible.
***REQUIRED TO RUN THE API***. | | `API_NAME` | `unknown` | `ams-1` | api server name that is shown in `/api/serverInfo`. | | `CORS_WILDCARD` | `1` | `0` | toggles cross-origin resource sharing.
`0`: disabled. `1`: enabled. | | `CORS_URL` | not used | `https://cobalt.tools/` | cross-origin resource sharing url. api will be available only from this url if `CORS_WILDCARD` is set to `0`. | | `COOKIE_PATH` | not used | `/cookies.json` | path for cookie file relative to main folder. | | `PROCESSING_PRIORITY` | not used | `10` | changes `nice` value* for ffmpeg subprocess. available only on unix systems. | -| `TIKTOK_DEVICE_INFO` | ➖ | *see below* | device info (including `iid` and `device_id`) for tiktok functionality. required for tiktok to work. | -| `FREEBIND_CIDR` | ➖ | `2001:db8::/32` | IPv6 prefix used for randomly assigning addresses to cobalt requests. only supported on linux systems. for more info, see below. | +| `FREEBIND_CIDR` | ➖ | `2001:db8::/32` | IPv6 prefix used for randomly assigning addresses to cobalt requests. only supported on linux systems. see below for more info. | +| `RATELIMIT_WINDOW` | `60` | `120` | rate limit time window in **seconds**. | +| `RATELIMIT_MAX` | `20` | `30` | max requests per time window. requests above this amount will be blocked for the rate limit window duration. | +| `DURATION_LIMIT` | `10800` | `18000` | max allowed video duration in **seconds**. | \* the higher the nice value, the lower the priority. [read more here](https://en.wikipedia.org/wiki/Nice_(Unix)). -#### TIKTOK_DEVICE_INFO -you need to get your own device info for tiktok functionality to work. this can be done by proxying the app through any request-intercepting proxy (such as [mitmproxy](https://mitmproxy.org)). you need to disable ssl pinning to see requests. there will be no assistance provided by cobalt for this. - -example config (replace **ALL** values with ones you got from mitm): -``` -'{ - "iid": "", - "device_id": "", - "channel": "googleplay", - "app_name": "musical_ly", - "version_code": "310503", - "device_platform": "android", - "device_type": "Redmi+7", - "os_version": "13" -}' -``` - -you can compress the json to save space. if you're using a `.env` file then the line would would look like this (***note the quotes***): -``` -TIKTOK_DEVICE_INFO='{"iid":"","device_id":"","channel":"googleplay","app_name":"musical_ly","version_code":"310503","device_platform":"android","device_type":"Redmi+7","os_version":"13"}' -``` - #### FREEBIND_CIDR setting a `FREEBIND_CIDR` allows cobalt to pick a random IP for every download and use it for all requests it makes for that particular download. to use freebind in cobalt, you need to follow its [setup instructions](https://github.com/imputnet/freebind.js?tab=readme-ov-file#setup) first. if you configure this option while running cobalt @@ -94,13 +74,13 @@ in a docker container, you also need to set the `API_LISTEN_ADDRESS` env to `127 `network_mode` for the container to `host`. ### variables for web -| variable name | default | example | description | -|:---------------------|:---------------------|:------------------------|:--------------------------------------------------------------------------------------| -| `WEB_PORT` | `9001` | `9001` | changes port from which frontend server is accessible. | -| `WEB_URL` | ➖ | `https://cobalt.tools/` | changes url from which frontend server is accessible.
***REQUIRED TO RUN WEB***. | -| `API_URL` | `https://co.wuk.sh/` | `https://co.wuk.sh/` | changes url which is used for api requests by frontend clients. | -| `SHOW_SPONSORS` | `0` | `1` | toggles sponsor list in about popup.
`0`: disabled. `1`: enabled. | -| `IS_BETA` | `0` | `1` | toggles beta tag next to cobalt logo.
`0`: disabled. `1`: enabled. | -| `PLAUSIBLE_HOSTNAME` | ➖ | `plausible.io`* | enables plausible analytics with provided hostname as receiver backend. | +| variable name | default | example | description | +|:---------------------|:----------------------------|:----------------------------|:--------------------------------------------------------------------------------------| +| `WEB_PORT` | `9001` | `9001` | changes port from which frontend server is accessible. | +| `WEB_URL` | ➖ | `https://cobalt.tools/` | changes url from which frontend server is accessible.
***REQUIRED TO RUN WEB***. | +| `API_URL` | `https://api.cobalt.tools/` | `https://api.cobalt.tools/` | changes url which is used for api requests by frontend clients. | +| `SHOW_SPONSORS` | `0` | `1` | toggles sponsor list in about popup.
`0`: disabled. `1`: enabled. | +| `IS_BETA` | `0` | `1` | toggles beta tag next to cobalt logo.
`0`: disabled. `1`: enabled. | +| `PLAUSIBLE_HOSTNAME` | ➖ | `plausible.io`* | enables plausible analytics with provided hostname as receiver backend. | \* don't use plausible.io as receiver backend unless you paid for their cloud service. use your own domain when hosting community edition of plausible. refer to their [docs](https://plausible.io/docs) when needed. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..9052067e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1139 @@ +{ + "name": "cobalt", + "version": "7.14.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cobalt", + "version": "7.14.1", + "license": "AGPL-3.0", + "dependencies": { + "content-disposition-header": "0.6.0", + "cors": "^2.8.5", + "dotenv": "^16.0.1", + "esbuild": "^0.14.51", + "express": "^4.18.1", + "express-rate-limit": "^6.3.0", + "ffmpeg-static": "^5.1.0", + "hls-parser": "^0.10.7", + "ipaddr.js": "2.1.0", + "nanoid": "^4.0.2", + "node-cache": "^5.1.2", + "psl": "1.9.0", + "set-cookie-parser": "2.6.0", + "undici": "^5.19.1", + "url-pattern": "1.0.3", + "youtubei.js": "^9.3.0" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "freebind": "^0.2.2" + } + }, + "node_modules/@derhuerst/http-basic": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz", + "integrity": "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==", + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^2.0.0", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/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==" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition-header": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/content-disposition-header/-/content-disposition-header-0.6.0.tgz", + "integrity": "sha512-+PKF6Y7JHgwD2Dld48L5jozC6pGDdnioJHfM7VyfF92pAU6wDF/N8K/cfecoq7b19KnelOnjntkVyN5hMm2F+w==" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-rate-limit": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.11.2.tgz", + "integrity": "sha512-a7uwwfNTh1U60ssiIkuLFWHt4hAC5yxlLGU2VP0X4YNlyEDZAqF4tK3GD3NSitVBrCQmQ0++0uOyFOgC2y4DDw==", + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "express": "^4 || ^5" + } + }, + "node_modules/ffmpeg-static": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz", + "integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==", + "hasInstallScript": true, + "dependencies": { + "@derhuerst/http-basic": "^8.2.0", + "env-paths": "^2.2.0", + "https-proxy-agent": "^5.0.0", + "progress": "^2.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/freebind": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/freebind/-/freebind-0.2.2.tgz", + "integrity": "sha512-H3PdpY9gMa46ra2CkDLZxAqvJiiazb5ZpQcvmOriB0cPVRzFSi+pXY/m3mN31tkZhE/0D4O+pCGTMezh/jwLnw==", + "optional": true, + "dependencies": { + "ipaddr.js": "2.1.0", + "syscall-napi": "0.0.6", + "undici": "^5.27.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hls-parser": { + "version": "0.10.9", + "resolved": "https://registry.npmjs.org/hls-parser/-/hls-parser-0.10.9.tgz", + "integrity": "sha512-BGtoMd3sbhndHYKVQEoEmpuRe6++iWQc38x84x5uqitYmP6V5opKHWaYJT4GAwhnVRaNhMTuZbS0AruzPw4qgw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/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==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/jintr": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jintr/-/jintr-1.1.0.tgz", + "integrity": "sha512-Tu9wk3BpN2v+kb8yT6YBtue+/nbjeLFv4vvVC4PJ7oCidHKbifWhvORrAbQfxVIQZG+67am/mDagpiGSVtvrZg==", + "funding": [ + "https://github.com/sponsors/LuanRT" + ], + "dependencies": { + "acorn": "^8.8.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/nanoid": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", + "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/syscall-napi": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/syscall-napi/-/syscall-napi-0.0.6.tgz", + "integrity": "sha512-qHbwjyFXAAekKUXxl70lhDiBYJ3e7XM7kQwu7LV3F0pHMenKox+VcZPZkRkhdmL/wNJD3NmrMGnL7161kdecUQ==", + "hasInstallScript": true, + "optional": true + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/url-pattern": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/url-pattern/-/url-pattern-1.0.3.tgz", + "integrity": "sha512-uQcEj/2puA4aq1R3A2+VNVBgaWYR24FdWjl7VNW83rnWftlhyzOZ/tBjezRiC2UkIzuxC8Top3IekN3vUf1WxA==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/youtubei.js": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-9.4.0.tgz", + "integrity": "sha512-8plCOZD2WabqWSEgZU3RjzigIIeR7sF028EERJENYrC9xO/6awpLMZfeoE1gNrNEbKcA+bzbMvonqlvBdxGdKg==", + "funding": [ + "https://github.com/sponsors/LuanRT" + ], + "dependencies": { + "jintr": "^1.1.0", + "tslib": "^2.5.0", + "undici": "^5.19.1" + } + } + } +} diff --git a/package.json b/package.json index 2daa403c..f5e17282 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", "description": "save what you love", - "version": "7.13.3", + "version": "7.14.1", "author": "imput", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/config.json b/src/config.json index 0a32d220..640fb2f5 100644 --- a/src/config.json +++ b/src/config.json @@ -1,6 +1,4 @@ { - "streamLifespan": 90000, - "maxVideoDuration": 10800000, "genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", "authorInfo": { "support": { @@ -54,7 +52,7 @@ "saveToGalleryShortcut": "https://www.icloud.com/shortcuts/14e9aebf04b24156acc34ceccf7e6fcd", "saveToFilesShortcut": "https://www.icloud.com/shortcuts/2134cd9d4d6b41448b2201f933542b2e", "statusPage": "https://status.cobalt.tools/", - "troubleshootingGuide": "https://github.com/wukko/cobalt/blob/current/docs/troubleshooting.md" + "troubleshootingGuide": "https://github.com/imputnet/cobalt/blob/current/docs/troubleshooting.md" }, "celebrations": { "01-01": "🎄", @@ -95,7 +93,7 @@ "sponsors": [{ "name": "royale", "fullName": "RoyaleHosting", - "url": "https://royalehosting.net/", + "url": "https://royalehosting.net/?partner=cobalt", "logo": { "width": 605, "height": 136, diff --git a/src/core/api.js b/src/core/api.js index 31ed7dd5..04e190cd 100644 --- a/src/core/api.js +++ b/src/core/api.js @@ -1,89 +1,109 @@ import cors from "cors"; import rateLimit from "express-rate-limit"; -import { randomBytes } from "crypto"; - -const ipSalt = randomBytes(64).toString('hex'); import { env, version } from "../modules/config.js"; -import { getJSON } from "../modules/api.js"; -import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js"; + +import { generateHmac, generateSalt } from "../modules/sub/crypto.js"; import { Bright, Cyan } from "../modules/sub/consoleText.js"; -import stream from "../modules/stream/stream.js"; +import { languageCode } from "../modules/sub/utils.js"; import loc from "../localization/manager.js"; -import { generateHmac } from "../modules/sub/crypto.js"; + +import { createResponse, normalizeRequest, getIP } from "../modules/processing/request.js"; import { verifyStream, getInternalStream } from "../modules/stream/manage.js"; +import { extract } from "../modules/processing/url.js"; +import match from "../modules/processing/match.js"; +import stream from "../modules/stream/stream.js"; + +const acceptRegex = /^application\/json(; charset=utf-8)?$/; + +const ipSalt = generateSalt(); +const corsConfig = env.corsWildcard ? {} : { + origin: env.corsURL, + optionsSuccessStatus: 200 +} export function runAPI(express, app, gitCommit, gitBranch, __dirname) { - const corsConfig = !env.corsWildcard ? { - origin: env.corsURL, - optionsSuccessStatus: 200 - } : {}; - - const apiLimiter = rateLimit({ - windowMs: 60000, - max: 20, - standardHeaders: true, - legacyHeaders: false, - keyGenerator: req => generateHmac(getIP(req), ipSalt), - handler: (req, res) => { - return res.status(429).json({ - "status": "rate-limit", - "text": loc(languageCode(req), 'ErrorRateLimit') - }); - } - }); - const apiLimiterStream = rateLimit({ - windowMs: 60000, - max: 25, - standardHeaders: true, - legacyHeaders: false, - keyGenerator: req => generateHmac(getIP(req), ipSalt), - handler: (req, res) => { - return res.status(429).json({ - "status": "rate-limit", - "text": loc(languageCode(req), 'ErrorRateLimit') - }); - } - }); - const startTime = new Date(); const startTimestamp = startTime.getTime(); + + const serverInfo = { + version: version, + commit: gitCommit, + branch: gitBranch, + name: env.apiName, + url: env.apiURL, + cors: Number(env.corsWildcard), + startTime: `${startTimestamp}` + } + + const apiLimiter = rateLimit({ + windowMs: env.rateLimitWindow * 1000, + max: env.rateLimitMax, + standardHeaders: true, + legacyHeaders: false, + keyGenerator: req => generateHmac(getIP(req), ipSalt), + handler: (req, res) => { + return res.status(429).json({ + "status": "rate-limit", + "text": loc(languageCode(req), 'ErrorRateLimit', env.rateLimitWindow) + }); + } + }) + + const apiLimiterStream = rateLimit({ + windowMs: env.rateLimitWindow * 1000, + max: env.rateLimitMax, + standardHeaders: true, + legacyHeaders: false, + keyGenerator: req => generateHmac(getIP(req), ipSalt), + handler: (req, res) => { + return res.sendStatus(429) + } + }) app.set('trust proxy', ['loopback', 'uniquelocal']); - app.use('/api/:type', cors({ + app.use('/api', cors({ methods: ['GET', 'POST'], - ...corsConfig - })); + exposedHeaders: [ + 'Ratelimit-Limit', + 'Ratelimit-Policy', + 'Ratelimit-Remaining', + 'Ratelimit-Reset' + ], + ...corsConfig, + })) app.use('/api/json', apiLimiter); app.use('/api/stream', apiLimiterStream); - app.use('/api/onDemand', apiLimiter); app.use((req, res, next) => { - try { decodeURIComponent(req.path) } catch (e) { return res.redirect('/') } + try { + decodeURIComponent(req.path) + } catch { + return res.redirect('/') + } next(); - }); + }) app.use('/api/json', express.json({ verify: (req, res, buf) => { - let acceptCon = String(req.header('Accept')) === "application/json"; - if (acceptCon) { + if (String(req.header('Accept')) === "application/json") { if (buf.length > 720) throw new Error(); JSON.parse(buf); } else { throw new Error(); } } - })); + })) // handle express.json errors properly (https://github.com/expressjs/express/issues/4065) app.use('/api/json', (err, req, res, next) => { let errorText = "invalid json body"; - let acceptCon = String(req.header('Accept')) !== "application/json"; + const acceptHeader = String(req.header('Accept')) !== "application/json"; - if (err || acceptCon) { - if (acceptCon) errorText = "invalid accept header"; + if (err || acceptHeader) { + if (acceptHeader) errorText = "invalid accept header"; return res.status(400).json({ status: "error", text: errorText @@ -91,108 +111,110 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { } else { next(); } - }); + }) app.post('/api/json', async (req, res) => { + const request = req.body; + const lang = languageCode(req); + + const fail = (t) => { + const { status, body } = createResponse("error", { t: loc(lang, t) }); + res.status(status).json(body); + } + + if (!acceptRegex.test(req.header('Content-Type'))) { + return fail('ErrorInvalidContentType'); + } + + if (!request.url) { + return fail('ErrorNoLink'); + } + + request.dubLang = request.dubLang ? lang : false; + const normalizedRequest = normalizeRequest(request); + if (!normalizedRequest) { + return fail('ErrorCantProcess'); + } + + const parsed = extract(normalizedRequest.url); + if (parsed === null) { + return fail('ErrorUnsupported'); + } + try { - let lang = languageCode(req); - let j = apiJSON(0, { t: "bad request" }); - try { - let contentCon = String(req.header('Content-Type')) === "application/json"; - let request = req.body; - if (contentCon && request.url) { - request.dubLang = request.dubLang ? lang : false; - - let chck = checkJSONPost(request); - if (!chck) throw new Error(); - - j = await getJSON(chck.url, lang, chck); - } else { - j = apiJSON(0, { - t: !contentCon ? "invalid content type header" : loc(lang, 'ErrorNoLink') - }); - } - } catch (e) { - j = apiJSON(0, { t: loc(lang, 'ErrorCantProcess') }); + const result = await match( + parsed.host, parsed.patternMatch, lang, normalizedRequest + ); + + res.status(result.status).json(result.body); + } catch { + fail('ErrorSomethingWentWrong'); + } + }) + + app.get('/api/stream', (req, res) => { + const id = String(req.query.id); + const exp = String(req.query.exp); + const sig = String(req.query.sig); + const sec = String(req.query.sec); + const iv = String(req.query.iv); + + const checkQueries = id && exp && sig && sec && iv; + const checkBaseLength = id.length === 21 && exp.length === 13; + const checkSafeLength = sig.length === 43 && sec.length === 43 && iv.length === 22; + + if (checkQueries && checkBaseLength && checkSafeLength) { + // rate limit probe, will not return json after 8.0 + if (req.query.p) { + return res.status(200).json({ + status: "continue" + }) } - return res.status(j.status).json(j.body); - } catch (e) { + try { + const streamInfo = verifyStream(id, sig, exp, sec, iv); + if (!streamInfo?.service) { + return res.sendStatus(streamInfo.status); + } + return stream(res, streamInfo); + } catch { + return res.destroy(); + } + } + return res.sendStatus(400); + }) + + app.get('/api/istream', (req, res) => { + try { + if (!req.ip.endsWith('127.0.0.1')) + return res.sendStatus(403); + if (String(req.query.id).length !== 21) + return res.sendStatus(400); + + const streamInfo = getInternalStream(req.query.id); + if (!streamInfo) return res.sendStatus(404); + streamInfo.headers = req.headers; + + return stream(res, { type: 'internal', ...streamInfo }); + } catch { return res.destroy(); } - }); + }) - app.get('/api/:type', (req, res) => { + app.get('/api/serverInfo', (req, res) => { try { - let j; - switch (req.params.type) { - case 'stream': - const q = req.query; - const checkQueries = q.t && q.e && q.h && q.s && q.i; - const checkBaseLength = q.t.length === 21 && q.e.length === 13; - const checkSafeLength = q.h.length === 43 && q.s.length === 43 && q.i.length === 22; - if (checkQueries && checkBaseLength && checkSafeLength) { - if (q.p) { - return res.status(200).json({ - status: "continue" - }) - } - let streamInfo = verifyStream(q.t, q.h, q.e, q.s, q.i); - if (streamInfo.error) { - return res.status(streamInfo.status).json(apiJSON(0, { t: streamInfo.error }).body); - } - return stream(res, streamInfo); - } - - j = apiJSON(0, { - t: "bad request. stream link may be incomplete or corrupted." - }) - return res.status(j.status).json(j.body); - case 'istream': - if (!req.ip.endsWith('127.0.0.1')) - return res.sendStatus(403); - if (('' + req.query.t).length !== 21) - return res.sendStatus(400); - - let streamInfo = getInternalStream(req.query.t); - if (!streamInfo) return res.sendStatus(404); - streamInfo.headers = req.headers; - - return stream(res, { type: 'internal', ...streamInfo }); - case 'serverInfo': - return res.status(200).json({ - version: version, - commit: gitCommit, - branch: gitBranch, - name: env.apiName, - url: env.apiURL, - cors: Number(env.corsWildcard), - startTime: `${startTimestamp}` - }); - default: - j = apiJSON(0, { - t: "unknown response type" - }) - return res.status(j.status).json(j.body); - } - } catch (e) { - return res.status(500).json({ - status: "error", - text: loc(languageCode(req), 'ErrorCantProcess') - }); + return res.status(200).json(serverInfo); + } catch { + return res.destroy(); } - }); - - app.get('/api/status', (req, res) => { - res.status(200).end() - }); + }) app.get('/favicon.ico', (req, res) => { res.sendFile(`${__dirname}/src/front/icons/favicon.ico`) - }); + }) app.get('/*', (req, res) => { - res.redirect('/api/json') - }); + res.redirect('/api/serverInfo') + }) app.listen(env.apiPort, env.listenAddress, () => { console.log(`\n` + @@ -201,5 +223,5 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { `URL: ${Cyan(`${env.apiURL}`)}\n` + `Port: ${env.apiPort}\n` ) - }); + }) } diff --git a/src/core/web.js b/src/core/web.js index 4c1b1999..9a281c47 100644 --- a/src/core/web.js +++ b/src/core/web.js @@ -1,12 +1,14 @@ -import { version, env } from "../modules/config.js"; -import { apiJSON, languageCode } from "../modules/sub/utils.js"; + import { Bright, Cyan } from "../modules/sub/consoleText.js"; +import { languageCode } from "../modules/sub/utils.js"; +import { version, env } from "../modules/config.js"; import { buildFront } from "../modules/build.js"; import findRendered from "../modules/pageRender/findRendered.js"; import { celebrationsEmoji } from "../modules/pageRender/elements.js"; import { changelogHistory } from "../modules/pageRender/onDemand.js"; +import { createResponse } from "../modules/processing/request.js"; export async function runWeb(express, app, gitCommit, gitBranch, __dirname) { const startTime = new Date(); @@ -20,33 +22,40 @@ export async function runWeb(express, app, gitCommit, gitBranch, __dirname) { app.use((req, res, next) => { try { decodeURIComponent(req.path) } catch (e) { return res.redirect('/') } next(); - }); + }) + app.get('/onDemand', (req, res) => { try { if (req.query.blockId) { let blockId = req.query.blockId.slice(0, 3); - let r, j; + let blockData; switch(blockId) { // changelog history case "0": - r = changelogHistory(); - j = r ? apiJSON(3, { t: r }) : apiJSON(0, { - t: "couldn't render this block, please try again!" - }) + let history = changelogHistory(); + if (history) { + blockData = createResponse("success", { t: history }) + } else { + blockData = createResponse("error", { + t: "couldn't render this block, please try again!" + }) + } break; // celebrations emoji case "1": - r = celebrationsEmoji(); - j = r ? apiJSON(3, { t: r }) : false + let celebration = celebrationsEmoji(); + if (celebration) { + blockData = createResponse("success", { t: celebration }) + } break; default: - j = apiJSON(0, { + blockData = createResponse("error", { t: "couldn't find a block with this id" }) break; } - if (j.body) { - return res.status(j.status).json(j.body); + if (blockData?.body) { + return res.status(blockData.status).json(blockData.body); } else { return res.status(204).end(); } @@ -56,25 +65,25 @@ export async function runWeb(express, app, gitCommit, gitBranch, __dirname) { text: "couldn't render this block, please try again!" }); } - } catch (e) { + } catch { return res.status(400).json({ status: "error", text: "couldn't render this block, please try again!" }) } - }); - app.get("/status", (req, res) => { - return res.status(200).end() - }); + }) + app.get("/", (req, res) => { return res.sendFile(`${__dirname}/${findRendered(languageCode(req))}`) - }); + }) + app.get("/favicon.ico", (req, res) => { return res.sendFile(`${__dirname}/src/front/icons/favicon.ico`) - }); + }) + app.get("/*", (req, res) => { return res.redirect('/') - }); + }) app.listen(env.webPort, () => { console.log(`\n` + diff --git a/src/front/cobalt.css b/src/front/cobalt.css index 668d0eae..ab8c5e3b 100644 --- a/src/front/cobalt.css +++ b/src/front/cobalt.css @@ -252,7 +252,7 @@ button:active, flex-direction: row; } #cobalt-main-box #bottom { - padding-top: 1rem; + padding-top: calc(1rem - var(--padding-small)); display: flex; flex-direction: row; justify-content: space-between; @@ -610,7 +610,7 @@ button:active, margin-top: 0.5rem; } .explanation { - margin-top: 0.8rem; + margin-top: var(--padding); width: 100%; font-size: 0.8rem; text-align: left; diff --git a/src/front/cobalt.js b/src/front/cobalt.js index ef5b448c..1efe64be 100644 --- a/src/front/cobalt.js +++ b/src/front/cobalt.js @@ -563,16 +563,9 @@ const loadCelebrationsEmoji = async() => { let aboutButtonBackup = eid("about-footer").innerHTML; try { let j = await fetch(`/onDemand?blockId=1`).then(r => r.json()).catch(() => {}); - if (j && j.status === "success" && j.text) { eid("about-footer").innerHTML = eid("about-footer").innerHTML.replace( - ``, + `${aboutButtonBackup.split('> ')[0]}>`, j.text ) } diff --git a/src/front/updateBanners/millionusers.webp b/src/front/updateBanners/millionusers.webp new file mode 100644 index 00000000..fcbc5819 Binary files /dev/null and b/src/front/updateBanners/millionusers.webp differ diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index b0987337..1c1b857f 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -24,7 +24,7 @@ "ErrorBrokenLink": "{s} is supported, but something is wrong with your link. maybe you didn't copy it fully?", "ErrorNoLink": "i can't guess what you want to download! please give me a link :(", "ErrorPageRenderFail": "if you're reading this, then there's something wrong with the page renderer. please {ContactLink}. make sure to provide the domain this error is present on and current commit hash ({s}). thank you in advance :D", - "ErrorRateLimit": "you're making too many requests. try again in a minute!", + "ErrorRateLimit": "you're making too many requests. try again in {s} seconds!", "ErrorCouldntFetch": "i couldn't find anything about this link. check if it works and try again! some content may be region restricted, so keep that in mind.", "ErrorLengthLimit": "i can't process videos longer than {s} minutes, so pick something shorter instead!", "ErrorBadFetch": "something went wrong when i tried getting info about your link. are you sure it works? check if it does, and try again.", @@ -155,6 +155,7 @@ "SettingsTikTokH265Description": "download 1080p videos from tiktok in h265/hevc format when available.", "SettingsYoutubeDub": "use browser language", "SettingsYoutubeDubDescription": "uses your browser's default language for youtube dubbed audio tracks. works even if cobalt ui isn't translated to your language.", - "UpdateIstream": "better service support and ux" + "ErrorInvalidContentType": "invalid content type header", + "UpdateOneMillion": "1 million users and blazing speed" } } diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json index 9ba1643b..eeb663e1 100644 --- a/src/localization/languages/ru.json +++ b/src/localization/languages/ru.json @@ -24,7 +24,7 @@ "ErrorBrokenLink": "{s} поддерживается, но с твоей ссылкой что-то не так. может быть, ты её не полностью скопировал?", "ErrorNoLink": "пока что я не умею угадывать, что ты хочешь скачать. дай мне, пожалуйста, ссылку :(", "ErrorPageRenderFail": "если ты видишь этот текст, значит что-то не так с рендером страницы. пожалуйста, {ContactLink}. также приложи домен, на котором присутсвует эта ошибка, и хэш коммита ({s}). спасибо :)", - "ErrorRateLimit": "ты делаешь слишком много запросов. попробуй ещё раз через минуту!", + "ErrorRateLimit": "ты делаешь слишком много запросов. попробуй ещё раз через {s} секунд!", "ErrorCouldntFetch": "у меня не получилось ничего найти по этой ссылке. убедись, что она работает, и попробуй ещё раз. некоторый контент может быть залочен на регион.", "ErrorLengthLimit": "я не могу обрабатывать видео длиннее чем {s} минут(ы), так что скачай что-нибудь покороче!", "ErrorBadFetch": "произошла какая-то ошибка при получении данных по твоей ссылке. убедись, что она работает, и попробуй ещё раз.", @@ -157,6 +157,6 @@ "SettingsTikTokH265Description": "скачивает видео с tiktok в 1080p и h265/hevc, когда это возможно.", "SettingsYoutubeDub": "использовать язык браузера", "SettingsYoutubeDubDescription": "использует главный язык браузера для аудиодорожек на youtube. работает даже если кобальт не переведён в твой язык.", - "UpdateIstream": "быстрые загрузки и приятный интерфейс" + "UpdateOneMillion": "миллион и невероятная скорость" } } diff --git a/src/modules/api.js b/src/modules/api.js deleted file mode 100644 index c3549bb3..00000000 --- a/src/modules/api.js +++ /dev/null @@ -1,33 +0,0 @@ -import { services } from "./config.js"; - -import { apiJSON } from "./sub/utils.js"; -import { errorUnsupported } from "./sub/errors.js"; -import loc from "../localization/manager.js"; -import match from "./processing/match.js"; -import { getHostIfValid } from "./processing/url.js"; - -export async function getJSON(url, lang, obj) { - try { - const host = getHostIfValid(url); - - if (!host || !services[host].enabled) { - return apiJSON(0, { t: errorUnsupported(lang) }); - } - - let patternMatch; - for (const pattern of services[host].patterns) { - patternMatch = pattern.match( - url.pathname.substring(1) + url.search - ); - if (patternMatch) break; - } - - if (!patternMatch) { - return apiJSON(0, { t: errorUnsupported(lang) }); - } - - return await match(host, patternMatch, url, lang, obj) - } catch (e) { - return apiJSON(0, { t: loc(lang, 'ErrorSomethingWentWrong') }) - } -} diff --git a/src/modules/changelog/changelog.json b/src/modules/changelog/changelog.json index 94569ec0..e90a1a33 100644 --- a/src/modules/changelog/changelog.json +++ b/src/modules/changelog/changelog.json @@ -1,5 +1,17 @@ { "current": { + "version": "7.14", + "date": "May 17, 2024", + "title": "now helping over 1 million people monthly", + "banner": { + "file": "millionusers.webp", + "alt": "collage of two photos, side by side. left photo: brown cake with 7 lit candles forming 1000000 and one ferrero rocher candy in the middle with cobalt (double greater than symbol) logo on it. right photo: chocolate cake with 7 lit candles forming 1000000 and cobalt logo formed with whipped cream on the cake. two plushes of meowth and pompompurin in party hats are seen behind the cake.", + "width": 1736, + "height": 1440 + }, + "content": "yesterday, cobalt hit 1 million users around the world! it's an absolutely insane milestone for us and we're incredibly grateful to everyone saving and creating what they love with help of cobalt. thank you for being our friends.\n\nin anticipation of 7 figure user count, we've revamped the cobalt codebase and infrastructure to be faster and more reliable than ever. a combination of many changes has resulted into incredible download speeds (up to 30 MB/s, as tested by both developers in europe).\n\nnote: there's no backend instance in asia just yet, so if you're there, you might experience average speeds *for now*. you can help us afford a dedicated server in asia by donating to cobalt in the \"donate\" menu.\n\nchanges since the last major update\n\nservice improvements:\n*; youtube music support on the main instance is back!\n*; added support for pinterest images and gifs.\n*; cobalt will now use original soundcloud mp3 file when available.\n*; fixed a youtube bug that prevented some videos from downloading.\n\nui/ux improvements:\n*; cobalt web app is now fully optimized for ipad. you can add it to home screen from share menu to make it act like a native app!\n*; majorly reduced vertical padding when viewing cobalt in mobile web browser, allowing for more content at once. most noticeable on smaller screens.\n*; status bar color is now dynamic in the web browser on ios and web app on android.\n*; web app on android feels way more native than before.\n*; filename style icons are no longer blurry in safari.\n*; changelog notification no longer overlaps with dynamic island on newer iphones when cobalt is installed as a web app.\n*; fixed safe area padding.\n\nother changes:\n*; added support for freebind, made by one of the cobalt developers.\n*; rate limit and max video length limits are now customizable through environment variables.\n*; cobalt api now returns rate limit headers at all times.\n*; majorly cleaned up the codebase: removed unnecessary functions, rewrote those that were cryptic and confusing. it's way more comprehensible and contribution-friendly than ever before.\n*; moved the cobalt repo to our organization on github. everything stayed the same and all old links link back to it.\n\nnote for instance hosters:\nalong with cobalt repo, the docker image also moved! please update the url for it in your config along with watchtower args to include restarting containers (just in case) as seen in updated docker compose example. we're mirroring packages to old url for now, but it won't last forever.\n\nthat's it for now! hope you have an amazing day and share the 1 million celebration with us :)\n\njoin our discord server to discuss everything cobalt there" + }, + "history": [{ "version": "7.13", "date": "May 5, 2024", "title": "better ux, improvements for youtube, twitter, tiktok, instagram, and more!", @@ -10,8 +22,7 @@ "height": 960 }, "content": "long time no see! well, actually, you've been using the latest version for some time now. we've moved to a rolling release scheme, allowing for speedy update rollouts :)\n\nsince 7.11, there has been a ton of changes. here are the most notable of them:\n*; youtube downloads are now faster and more reliable than ever.\n*; all posts from twitter are now downloadable, including sensitive ones.\n*; you now can download tiktok videos in 1080p h265! just enable h265 support in settings > video.\n*; added support for sharing links directly to the cobalt web app on android.\n*; added 240p and 144p quality options to the quality picker in settings (for some reason, many of you wanted this).\n*; pasting a link with additional text around it will now work; cobalt will extract the link for you (works only via the paste button).\n*; added anonymous traffic analytics by plausible. we're using a selfhosted instance and don't collect any identifiable information about you. you can learn more in about > privacy policy. you can also opt out of anonymous analytics in settings > other.\n\nservice support improvements:\n*; implemented internal streams functionality, allowing for more fine-grained file streaming and therefore proper youtube support.\n*; added fallback to m4a if opus isn't available for youtube.\n*; added a total of 7 ways to get instagram post info, including mobile api, embed, and graphql api. absolute torture.\n*; added support for reddit user posts.\n*; updated the way tiktok downloads are handled for better reliability and 1080p support.\n*; added tiktok author's username to filename.\n*; added support for rutube shorts and yappy videos.\n*; added support for m.soundcloud.com links.\n*; added support for new post and reel links from instagram.\n*; added support for photo twitter links, only used for gifs.\n*; added support for m.bilibili.com links.\n*; added support for new type of vimeo links.\n*; added support for ddinstagram.com links.\n*; updated youtube codec info in settings to display the fact that av1 is a better choice now.\n*; updated best audio picking for tiktok and soundcloud.\n*; changed the youtube client to web, since android client no longer works.\n*; removed the vimeo download type switcher, as it should've always been automatic instead.\n*; removed an ability to enable the tiktok watermark, as it no longer includes the author's username.\n\nui & ux improvements:\n*; youtube audio dub switcher is now a toggle with a much easier to understand description.\n*; meowbalt now sticks out on the left side of download popup on desktop.\n*; updated \"made with love\" text to include the research & dev team behind cobalt, imput.\n*; fixed grammar of russian localization.\n*; rounded corners are now correctly rendered across all browsers.\n*; various minor improvements, including smaller button padding.\n*; removed the notification (red dot) functionality as the most recent changelog is already always on screen.\n*; removed settings migration from the old domain.\n\nother changes:\n*; various docs updates in github repo, making sure they're functional across branches and forks.\n*; major codebase cleanup.\n\nthank you for using cobalt, and thank you for being one of our 900k friends! i hope you like this update as much as we liked making it.\n\nwe're committed to keeping cobalt the best way to save what you love without ads or invasion of your privacy. there's a ton of cool stuff to come soon; stay tuned and have an amazing rest of your day <3\n\nif you want to help our goal of a better internet for everyone, just share cobalt with a friend!\n\n(original photo of a man in a suit by benzoix on freepik)" - }, - "history": [{ + }, { "version": "7.11", "date": "March 6, 2024", "title": "cache encryption, meowbalt, dailymotion, bilibili, and much more!", diff --git a/src/modules/config.js b/src/modules/config.js index c66521e1..67114b56 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -28,26 +28,33 @@ const // API mode related environment variables apiEnvs = { + apiURL, apiPort: process.env.API_PORT || 9000, apiName: process.env.API_NAME || 'unknown', + listenAddress: process.env.API_LISTEN_ADDRESS, + freebindCIDR: process.platform === 'linux' && process.env.FREEBIND_CIDR, + corsWildcard: process.env.CORS_WILDCARD !== '0', corsURL: process.env.CORS_URL, + cookiePath: process.env.COOKIE_PATH, + + rateLimitWindow: (process.env.RATELIMIT_WINDOW && parseInt(process.env.RATELIMIT_WINDOW)) || 60, + rateLimitMax: (process.env.RATELIMIT_MAX && parseInt(process.env.RATELIMIT_MAX)) || 20, + + durationLimit: (process.env.DURATION_LIMIT && parseInt(process.env.DURATION_LIMIT)) || 10800, + streamLifespan: 90, + processingPriority: process.platform !== 'win32' && process.env.PROCESSING_PRIORITY - && parseInt(process.env.PROCESSING_PRIORITY), - tiktokDeviceInfo: process.env.TIKTOK_DEVICE_INFO && JSON.parse(process.env.TIKTOK_DEVICE_INFO), - freebindCIDR: process.platform === 'linux' && process.env.FREEBIND_CIDR, - apiURL + && parseInt(process.env.PROCESSING_PRIORITY) } export const services = servicesConfigJson.config, audioIgnore = servicesConfigJson.audioIgnore, version = packageJson.version, - streamLifespan = config.streamLifespan, - maxVideoDuration = config.maxVideoDuration, genericUserAgent = config.genericUserAgent, repo = packageJson.bugs.url.replace('/issues', ''), authorInfo = config.authorInfo, diff --git a/src/modules/pageRender/page.js b/src/modules/pageRender/page.js index 17643958..19e08b50 100644 --- a/src/modules/pageRender/page.js +++ b/src/modules/pageRender/page.js @@ -584,8 +584,8 @@ export default function(obj) {