mirror of
https://github.com/imputnet/cobalt.git
synced 2025-07-18 03:08:30 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
d336e5bd2e
@ -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");
|
||||
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 + '@\\.:'
|
||||
})
|
||||
)
|
||||
})
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
1
packages/api-client/.gitignore
vendored
Normal file
1
packages/api-client/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dist
|
@ -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.
|
||||
|
||||
|
@ -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.",
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
||||
<div class="action-button-icon">
|
||||
<CopyIcon check={copied} />
|
||||
</div>
|
||||
copy
|
||||
{$t("button.copy")}
|
||||
</button>
|
||||
|
||||
{#if device.supports.share}
|
||||
|
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import locale from "$lib/i18n/locale";
|
||||
import languages from "$i18n/languages.json";
|
||||
|
||||
import { t, locales } from "$lib/i18n/translations";
|
||||
@ -10,10 +9,12 @@
|
||||
$: currentSetting = $settings.appearance.language;
|
||||
$: disabled = $settings.appearance.autoLanguage;
|
||||
|
||||
const updateLocale = (lang: string) => {
|
||||
const updateLocale = (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
|
||||
updateSetting({
|
||||
appearance: {
|
||||
language: lang as keyof typeof languages,
|
||||
language: target.value as keyof typeof languages,
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -34,8 +35,7 @@
|
||||
</div>
|
||||
<select
|
||||
id="setting-dropdown-appearance-language"
|
||||
bind:value={$locale}
|
||||
on:change={() => updateLocale($locale)}
|
||||
on:change={updateLocale}
|
||||
{disabled}
|
||||
>
|
||||
{#each $locales as value}
|
||||
|
@ -7,7 +7,7 @@ import type {
|
||||
LocalizationContent
|
||||
} from '$lib/types/i18n';
|
||||
|
||||
import languages from '$i18n/languages.json';
|
||||
import _languages from '$i18n/languages.json';
|
||||
|
||||
const locFiles = import.meta.glob('$i18n/*/**/*.json');
|
||||
const parsedLocfiles: StructuredLocfileInfo = {};
|
||||
@ -22,6 +22,8 @@ for (const [path, loader] of Object.entries(locFiles)) {
|
||||
}
|
||||
|
||||
const defaultLocale = 'en';
|
||||
const languages: Record<string, string> = _languages;
|
||||
|
||||
const config: Config<{
|
||||
value?: string;
|
||||
formats?: string;
|
||||
@ -30,6 +32,8 @@ const config: Config<{
|
||||
}> = {
|
||||
fallbackLocale: defaultLocale,
|
||||
translations: Object.keys(parsedLocfiles).reduce((obj, lang) => {
|
||||
languages[lang] ??= `${lang} (missing name)`;
|
||||
|
||||
return {
|
||||
...obj,
|
||||
[lang]: { languages }
|
||||
|
@ -18,7 +18,7 @@
|
||||
<h3>leading privacy</h3>
|
||||
<p>
|
||||
all requests to backend are anonymous and all tunnels are encrypted.
|
||||
we have a strict zero log policy and don't track <i>anything at all</i>.
|
||||
we have a strict zero log policy and don't track <i>anything</i> about individual people.
|
||||
</p>
|
||||
<p>
|
||||
to avoid caching or storing downloaded files, cobalt processes them on-fly, sending processed pieces directly to client.
|
||||
|
@ -25,10 +25,10 @@
|
||||
<section id="saving">
|
||||
<h3>saving</h3>
|
||||
<p>
|
||||
when using saving functionality, in some cases cobalt will encrypt & temporarily store information needed for tunnelling. it's stored in processing server's RAM for 90 seconds and irreversibly purged afterwards. no one has access to it, even instance owners, as long as they don't modify the official cobalt image.
|
||||
when using saving functionality, in some cases cobalt will encrypt & temporarily store information needed for tunneling. it's stored in processing server's RAM for 90 seconds and irreversibly purged afterwards. no one has access to it, even instance owners, as long as they don't modify the official cobalt image.
|
||||
</p>
|
||||
<p>
|
||||
processed/tunnelled files are never cached anywhere. everything is tunnelled live. cobalt's saving functionality is essentially a fancy proxy service.
|
||||
processed/tunneled files are never cached anywhere. everything is tunneled live. cobalt's saving functionality is essentially a fancy proxy service.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user