diff --git a/api/src/core/api.js b/api/src/core/api.js index 51ec1697..fdd13ce1 100644 --- a/api/src/core/api.js +++ b/api/src/core/api.js @@ -105,6 +105,18 @@ export const runAPI = (express, app, __dirname) => { app.post('/', apiLimiter); app.use('/tunnel', apiLimiterStream); + app.post('/', (req, res, next) => { + if (!acceptRegex.test(req.header('Accept'))) { + return fail(res, "error.api.header.accept"); + } + + if (!acceptRegex.test(req.header('Content-Type'))) { + return fail(res, "error.api.header.content_type"); + } + + next(); + }); + app.post('/', (req, res, next) => { if (!env.turnstileSecret || !env.jwtSecret) { return next(); @@ -128,14 +140,6 @@ export const runAPI = (express, app, __dirname) => { return fail(res, "error.api.auth.jwt.invalid"); } - if (!acceptRegex.test(req.header('Accept'))) { - return fail(res, "error.api.header.accept"); - } - - if (!acceptRegex.test(req.header('Content-Type'))) { - return fail(res, "error.api.header.content_type"); - } - req.authorized = true; } catch { return fail(res, "error.api.generic"); diff --git a/api/src/misc/utils.js b/api/src/misc/utils.js index 05192d97..34666d1c 100644 --- a/api/src/misc/utils.js +++ b/api/src/misc/utils.js @@ -65,3 +65,14 @@ export function merge(a, b) { return a; } + +export function splitFilenameExtension(filename) { + const parts = filename.split('.'); + const ext = parts.pop(); + + if (!parts.length) { + return [ ext, "" ] + } else { + return [ parts.join('.'), ext ] + } +} diff --git a/api/src/processing/match-action.js b/api/src/processing/match-action.js index 6b5395d4..4fdb24f6 100644 --- a/api/src/processing/match-action.js +++ b/api/src/processing/match-action.js @@ -3,6 +3,7 @@ import createFilename from "./create-filename.js"; import { createResponse } from "./request.js"; import { audioIgnore } from "./service-config.js"; import { createStream } from "../stream/manage.js"; +import { splitFilenameExtension } from "../misc/utils.js"; export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disableMetadata, filenameStyle, twitterGif, requestIP, audioBitrate, alwaysProxy }) { let action, @@ -32,10 +33,11 @@ export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disab } if (action === "muteVideo" && isAudioMuted && !r.filenameAttributes) { - const parts = r.filename.split("."); - const ext = parts.pop(); - - defaultParams.filename = `${parts.join(".")}_mute.${ext}`; + const [ name, ext ] = splitFilenameExtension(r.filename); + defaultParams.filename = `${name}_mute.${ext}`; + } else if (action === "gif") { + const [ name ] = splitFilenameExtension(r.filename); + defaultParams.filename = `${name}.gif`; } switch (action) { diff --git a/api/src/processing/service-config.js b/api/src/processing/service-config.js index 67542e97..f091d448 100644 --- a/api/src/processing/service-config.js +++ b/api/src/processing/service-config.js @@ -176,7 +176,7 @@ export const services = { Object.values(services).forEach(service => { service.patterns = service.patterns.map( pattern => new UrlPattern(pattern, { - segmentValueCharset: UrlPattern.defaultOptions.segmentValueCharset + '@\\.' + segmentValueCharset: UrlPattern.defaultOptions.segmentValueCharset + '@\\.:' }) ) }) diff --git a/api/src/stream/types.js b/api/src/stream/types.js index aa9becf2..184af873 100644 --- a/api/src/stream/types.js +++ b/api/src/stream/types.js @@ -291,7 +291,7 @@ const convertGif = (streamInfo, res) => { const [,,, muxOutput] = process.stdio; res.setHeader('Connection', 'keep-alive'); - res.setHeader('Content-Disposition', contentDisposition(streamInfo.filename.split('.')[0] + ".gif")); + res.setHeader('Content-Disposition', contentDisposition(streamInfo.filename)); pipe(muxOutput, res, shutdown); diff --git a/api/src/util/setup.js b/api/src/util/setup.js index 7796ea22..e9d1beae 100644 --- a/api/src/util/setup.js +++ b/api/src/util/setup.js @@ -1,7 +1,7 @@ import { existsSync, unlinkSync, appendFileSync } from "fs"; import { createInterface } from "readline"; -import { Cyan, Bright } from "./misc/console-text.js"; -import { loadJSON } from "./misc/load-from-fs.js"; +import { Cyan, Bright } from "../misc/console-text.js"; +import { loadJSON } from "../misc/load-from-fs.js"; import { execSync } from "child_process"; const { version } = loadJSON("./package.json"); diff --git a/api/src/util/tests.json b/api/src/util/tests.json index dee2f291..17952595 100644 --- a/api/src/util/tests.json +++ b/api/src/util/tests.json @@ -1401,7 +1401,7 @@ "bsky": [ { "name": "horizontal video", - "url": "https://bsky.app/profile/haileyok.com/post/3l3giwtwp222m", + "url": "https://bsky.app/profile/did:plc:oisofpd7lj26yvgiivf3lxsi/post/3l3giwtwp222m", "params": {}, "expected": { "code": 200, @@ -1410,7 +1410,7 @@ }, { "name": "horizontal video, recordWithMedia", - "url": "https://bsky.app/profile/juicysteak117.gay/post/3l3wonhk23g2i", + "url": "https://bsky.app/profile/did:plc:ywbm3iywnhzep3ckt6efhoh7/post/3l3wonhk23g2i", "params": {}, "expected": { "code": 200, @@ -1419,7 +1419,7 @@ }, { "name": "vertical video", - "url": "https://bsky.app/profile/haileyok.com/post/3l3jhpomhjk2m", + "url": "https://bsky.app/profile/did:plc:oisofpd7lj26yvgiivf3lxsi/post/3l3jhpomhjk2m", "params": {}, "expected": { "code": 200, @@ -1428,7 +1428,7 @@ }, { "name": "vertical video (muted)", - "url": "https://bsky.app/profile/haileyok.com/post/3l3jhpomhjk2m", + "url": "https://bsky.app/profile/did:plc:oisofpd7lj26yvgiivf3lxsi/post/3l3jhpomhjk2m", "params": { "downloadMode": "mute" }, @@ -1439,7 +1439,7 @@ }, { "name": "vertical video (audio)", - "url": "https://bsky.app/profile/haileyok.com/post/3l3jhpomhjk2m", + "url": "https://bsky.app/profile/did:plc:oisofpd7lj26yvgiivf3lxsi/post/3l3jhpomhjk2m", "params": { "downloadMode": "audio" }, @@ -1450,7 +1450,7 @@ }, { "name": "single image", - "url": "https://bsky.app/profile/thehardyboycats.bsky.social/post/3l33flpoygt26", + "url": "https://bsky.app/profile/did:plc:k4a7d65fcyevbrnntjxh57go/post/3l33flpoygt26", "params": {}, "expected": { "code": 200, @@ -1459,7 +1459,7 @@ }, { "name": "several images", - "url": "https://bsky.app/profile/tracey-m.bsky.social/post/3kzxuxbiul626", + "url": "https://bsky.app/profile/did:plc:rai7s6su2sy22ss7skouedl7/post/3kzxuxbiul626", "params": {}, "expected": { "code": 200, @@ -1467,8 +1467,8 @@ } }, { - "name": "deleted post", - "url": "https://bsky.app/profile/samuel.bsky.team/post/3l2udah76ch2c", + "name": "deleted post/invalid user", + "url": "https://bsky.app/profile/notreal.bsky.team/post/3l2udah76ch2c", "params": {}, "expected": { "code": 400, @@ -1476,4 +1476,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/api-client/.gitignore b/packages/api-client/.gitignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/packages/api-client/.gitignore @@ -0,0 +1 @@ +dist diff --git a/web/changelogs/10.0.md b/web/changelogs/10.0.md index 1a178b75..86da6d3b 100644 --- a/web/changelogs/10.0.md +++ b/web/changelogs/10.0.md @@ -47,7 +47,7 @@ and for nerds, we have a giant list of backend changes (that we are also excited this update allows us to actually innovate and develop new & exciting features. we are no longer held back by the legacy codebase. first feature of such kind is on-device remuxing. go check it out! -oh yeah, we now have 2.5 million monthly users. kind of insane. +oh yeah, we now have over 2 million monthly users. kind of insane. we hope you enjoy this update as much as we enjoyed making it. it was a really fun summer project for both of us. diff --git a/web/i18n/en/settings.json b/web/i18n/en/settings.json index 85c3d58b..90b2e0f6 100644 --- a/web/i18n/en/settings.json +++ b/web/i18n/en/settings.json @@ -65,7 +65,7 @@ "metadata.filename.basic": "basic", "metadata.filename.pretty": "pretty", "metadata.filename.nerdy": "nerdy", - "metadata.filename.description": "filename style will only be used for files tunnelled by cobalt. some services don't support filename styles other than classic.", + "metadata.filename.description": "filename style will only be used for files tunneled by cobalt. some services don't support filename styles other than classic.", "metadata.filename.preview.video": "Video Title", "metadata.filename.preview.audio": "Audio Title - Audio Author", @@ -88,17 +88,17 @@ "accessibility.motion.description": "disables animations and transitions whenever possible.", "language": "language", - "language.auto.title": "use default browser language", - "language.auto.description": "automatically picks the best language for you. if preferred browser language isn't available, english is used instead.", + "language.auto.title": "automatic selection", + "language.auto.description": "cobalt will use your browser's default language if translation is available. if not, english will be used instead.", "language.preferred.title": "preferred language", - "language.preferred.description": "if any text isn’t translated to the preferred language, it will fall back to english.", + "language.preferred.description": "this language will be used when automatic selection is disabled. any text that isn't translated will be displayed in english.", "privacy.analytics": "anonymous traffic analytics", "privacy.analytics.title": "don't contribute to analytics", "privacy.analytics.description": "anonymous traffic analytics are needed to get an approximate number of active cobalt users. no identifiable information about you is ever stored. all processed data is anonymized and aggregated.\n\nwe use a self-hosted plausible instance that doesn't use cookies and is fully compliant with GDPR, CCPA, and PECR.", "privacy.analytics.learnmore": "learn more about plausible's dedication to privacy.", - "privacy.tunnel": "tunnelling", + "privacy.tunnel": "tunneling", "privacy.tunnel.title": "always tunnel files", "privacy.tunnel.description": "cobalt will hide your ip address, browser info, and bypass local network restrictions. when enabled, files will also have readable filenames that otherwise would be gibberish.", diff --git a/web/src/components/donate/DonateShareCard.svelte b/web/src/components/donate/DonateShareCard.svelte index 7da48af8..3225c7ad 100644 --- a/web/src/components/donate/DonateShareCard.svelte +++ b/web/src/components/donate/DonateShareCard.svelte @@ -59,7 +59,7 @@
- copy + {$t("button.copy")} {#if device.supports.share} diff --git a/web/src/components/settings/LanguageDropdown.svelte b/web/src/components/settings/LanguageDropdown.svelte index dd357dd8..89f2b44f 100644 --- a/web/src/components/settings/LanguageDropdown.svelte +++ b/web/src/components/settings/LanguageDropdown.svelte @@ -1,5 +1,4 @@