Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api cleanup & web rewrite in svelte #353

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,8 @@ package-lock.json
# secrets
.env

# page build
min
build

# stuff i already made but delayed
future

# docker
docker-compose.yml

# vscode
.vscode

# cookie file
cookies.json
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# cobalt
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")
![cobalt logo with repeated logo (double arrow) pattern background](/web/public/icons/pattern.png "cobalt logo with repeated logo (double arrow) pattern background")

## 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***.
Expand Down
2 changes: 2 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# cobalt api
(TODO)
File renamed without changes.
14 changes: 14 additions & 0 deletions api/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"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",
"supportedAudio": ["mp3", "ogg", "wav", "opus"],
"ffmpegArgs": {
"webm": ["-c:v", "copy", "-c:a", "copy"],
"mp4": ["-c:v", "copy", "-c:a", "copy", "-movflags", "faststart+frag_keyframe+empty_moov"],
"copy": ["-c:a", "copy"],
"audio": ["-ar", "48000", "-ac", "2", "-b:a", "320k"],
"m4a": ["-movflags", "frag_keyframe+empty_moov"],
"gif": ["-vf", "scale=-1:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", "-loop", "0"]
}
}
17 changes: 6 additions & 11 deletions src/modules/config.js → api/core/config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import UrlPattern from "url-pattern";
import { loadJSON } from "./sub/loadFromFs.js";
const config = loadJSON("./src/config.json");
const packageJson = loadJSON("./package.json");
const servicesConfigJson = loadJSON("./src/modules/processing/servicesConfig.json");
import { loadJSON } from "../modules/util/loadFromFs.js";

const config = loadJSON("config.json");
const packageJson = loadJSON("package.json");
const servicesConfigJson = loadJSON("modules/processing/servicesConfig.json");

Object.values(servicesConfigJson.config).forEach(service => {
service.patterns = service.patterns.map(
Expand All @@ -19,11 +20,5 @@ export const
streamLifespan = config.streamLifespan,
maxVideoDuration = config.maxVideoDuration,
genericUserAgent = config.genericUserAgent,
repo = packageJson["bugs"]["url"].replace('/issues', ''),
authorInfo = config.authorInfo,
donations = config.donations,
ffmpegArgs = config.ffmpegArgs,
supportedAudio = config.supportedAudio,
celebrations = config.celebrations,
links = config.links,
sponsors = config.sponsors
supportedAudio = config.supportedAudio
23 changes: 11 additions & 12 deletions src/core/api.js → api/core/endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { randomBytes } from "crypto";

const ipSalt = randomBytes(64).toString('hex');

import { version } from "../modules/config.js";
import { getJSON } from "../modules/api.js";
import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js";
import { Bright, Cyan } from "../modules/sub/consoleText.js";
import { version } from "./config.js";
import { getJSON } from "../modules/util/preApi.js";
import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/util/misc.js";
import { Bright, Cyan } from "../modules/util/consoleText.js";
import stream from "../modules/stream/stream.js";
import loc from "../localization/manager.js";
import { generateHmac } from "../modules/sub/crypto.js";
import { generateHmac } from "../modules/util/crypto.js";
import { verifyStream } from "../modules/stream/manage.js";

export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
Expand All @@ -28,7 +27,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
handler: (req, res, next, opt) => {
return res.status(429).json({
"status": "rate-limit",
"text": loc(languageCode(req), 'ErrorRateLimit')
"text": 'ErrorRateLimit'
});
}
});
Expand All @@ -41,7 +40,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
handler: (req, res, next, opt) => {
return res.status(429).json({
"status": "rate-limit",
"text": loc(languageCode(req), 'ErrorRateLimit')
"text": 'ErrorRateLimit'
});
}
});
Expand Down Expand Up @@ -109,11 +108,11 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
j = await getJSON(chck.url, lang, chck);
} else {
j = apiJSON(0, {
t: !contentCon ? "invalid content type header" : loc(lang, 'ErrorNoLink')
t: !contentCon ? "invalid content type header" : 'ErrorNoLink'
});
}
} catch (e) {
j = apiJSON(0, { t: loc(lang, 'ErrorCantProcess') });
j = apiJSON(0, { t: 'ErrorCantProcess' });
}
return res.status(j.status).json(j.body);
} catch (e) {
Expand Down Expand Up @@ -166,7 +165,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
} catch (e) {
return res.status(500).json({
status: "error",
text: loc(languageCode(req), 'ErrorCantProcess')
text: 'ErrorCantProcess'
});
}
});
Expand All @@ -176,7 +175,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
});

app.get('/favicon.ico', (req, res) => {
res.sendFile(`${__dirname}/src/front/icons/favicon.ico`)
res.sendFile(`${__dirname}/api/assets/favicon.ico`)
});

app.get('/*', (req, res) => {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { strict as assert } from "node:assert";

import { apiJSON } from "../sub/utils.js";
import { errorUnsupported, genericError, brokenLink } from "../sub/errors.js";

import loc from "../../localization/manager.js";
import { apiJSON } from "../util/misc.js";

import { testers } from "./servicesPatternTesters.js";
import matchActionDecider from "./matchActionDecider.js";
Expand Down Expand Up @@ -32,8 +29,8 @@ export default async function(host, patternMatch, url, lang, obj) {
try {
let r, isAudioOnly = !!obj.isAudioOnly, disableMetadata = !!obj.disableMetadata;

if (!testers[host]) return apiJSON(0, { t: errorUnsupported(lang) });
if (!(testers[host](patternMatch))) return apiJSON(0, { t: brokenLink(lang, host) });
if (!testers[host]) return apiJSON(0, { t: 'ErrorUnsupported' });
if (!(testers[host](patternMatch))) return apiJSON(0, { t: 'ErrorBrokenLink' });

switch (host) {
case "twitter":
Expand Down Expand Up @@ -159,20 +156,18 @@ export default async function(host, patternMatch, url, lang, obj) {
r = await dailymotion(patternMatch);
break;
default:
return apiJSON(0, { t: errorUnsupported(lang) });
return apiJSON(0, { t: 'ErrorUnsupported' });
}

if (r.isAudioOnly) isAudioOnly = true;
let isAudioMuted = isAudioOnly ? false : obj.isAudioMuted;

if (r.error && r.critical)
return apiJSON(6, { t: loc(lang, r.error) })
return apiJSON(6, { t: r.error })

if (r.error)
return apiJSON(0, {
t: Array.isArray(r.error)
? loc(lang, r.error[0], r.error[1])
: loc(lang, r.error)
t: r.error
})

return matchActionDecider(
Expand All @@ -181,6 +176,6 @@ export default async function(host, patternMatch, url, lang, obj) {
obj.filenamePattern, obj.twitterGif
)
} catch (e) {
return apiJSON(0, { t: genericError(lang, host) })
return apiJSON(0, { t: 'ErrorBadFetch' })
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { audioIgnore, services, supportedAudio } from "../config.js";
import { apiJSON } from "../sub/utils.js";
import loc from "../../localization/manager.js";
import { audioIgnore, services, supportedAudio } from "../../core/config.js";
import { apiJSON } from "../util/misc.js";
import createFilename from "./createFilename.js";

export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, disableMetadata, filenamePattern, toGif) {
Expand Down Expand Up @@ -35,7 +34,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di

switch (action) {
default:
return apiJSON(0, { t: loc(lang, 'ErrorEmptyDownload') });
return apiJSON(0, { t: 'ErrorEmptyDownload' });

case "photo":
responseType = 1;
Expand Down Expand Up @@ -127,7 +126,7 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di

case "audio":
if ((host === "reddit" && r.typeId === 1) || audioIgnore.includes(host)) {
return apiJSON(0, { t: loc(lang, 'ErrorEmptyDownload') })
return apiJSON(0, { t: 'ErrorEmptyDownload' })
}

let processType = "render",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { genericUserAgent, maxVideoDuration } from "../../config.js";
import { genericUserAgent, maxVideoDuration } from "../../../core/config.js";

// TO-DO: higher quality downloads (currently requires an account)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import HLSParser from 'hls-parser';
import { maxVideoDuration } from '../../config.js';
import { maxVideoDuration } from '../../../core/config.js';

let _token;

Expand Down Expand Up @@ -104,4 +104,4 @@ export default async function({ id }) {
},
fileMetadata
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStream } from "../../stream/manage.js";
import { genericUserAgent } from "../../config.js";
import { genericUserAgent } from "../../../core/config.js";
import { getCookie, updateCookie } from "../cookie/manager.js";

const commonInstagramHeaders = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { genericUserAgent, maxVideoDuration } from "../../config.js";
import { cleanString } from "../../sub/utils.js";
import { genericUserAgent, maxVideoDuration } from "../../../core/config.js";
import { cleanString } from "../../util/misc.js";

const resolutions = {
"ultra": "2160",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { genericUserAgent } from "../../config.js";
import { genericUserAgent } from "../../../core/config.js";

const videoLinkBase = {
"regular": "https://v1.pinimg.com/videos/mc/720p/",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { genericUserAgent, maxVideoDuration } from "../../config.js";
import { genericUserAgent, maxVideoDuration } from "../../../core/config.js";
import { getCookie, updateCookieValues } from "../cookie/manager.js";

async function getAccessToken() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import HLS from 'hls-parser';
import { maxVideoDuration } from "../../config.js";
import { cleanString } from '../../sub/utils.js';
import { maxVideoDuration } from "../../../core/config.js";
import { cleanString } from '../../util/misc.js';

export default async function(obj) {
let quality = obj.quality === "max" ? "9000" : obj.quality;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { maxVideoDuration } from "../../config.js";
import { cleanString } from "../../sub/utils.js";
import { maxVideoDuration } from "../../../core/config.js";
import { cleanString } from "../../util/misc.js";

const cachedID = {
version: '',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { genericUserAgent } from "../../config.js";
import { genericUserAgent } from "../../../core/config.js";

const shortDomain = "https://vt.tiktok.com/";
const apiPath = "https://api22-normal-c-alisg.tiktokv.com/aweme/v1/feed/?region=US&carrier_region=US";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import psl from "psl";
import { genericUserAgent } from "../../config.js";
import { genericUserAgent } from "../../../core/config.js";

const API_KEY = 'jrsCWX1XDuVxAFO4GkK147syAoN8BJZ5voz8tS80bPcj26Vc5Z';
const API_BASE = 'https://api-http2.tumblr.com';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { maxVideoDuration } from "../../config.js";
import { cleanString } from '../../sub/utils.js';
import { maxVideoDuration } from "../../../core/config.js";
import { cleanString } from '../../util/misc.js';

const gqlURL = "https://gql.twitch.tv/gql";
const clientIdHead = { "client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko" };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { genericUserAgent } from "../../config.js";
import { genericUserAgent } from "../../../core/config.js";
import { createStream } from "../../stream/manage.js";

const graphqlURL = 'https://twitter.com/i/api/graphql/5GOHgZe-8U2j5sVHQzEm9A/TweetResultByRestId';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { maxVideoDuration } from "../../config.js";
import { cleanString } from '../../sub/utils.js';
import { maxVideoDuration } from "../../../core/config.js";
import { cleanString } from '../../util/misc.js';

const resolutionMatch = {
"3840": "2160",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { genericUserAgent, maxVideoDuration } from "../../config.js";
import { cleanString } from "../../sub/utils.js";
import { genericUserAgent, maxVideoDuration } from "../../../core/config.js";
import { cleanString } from "../../util/misc.js";

const resolutions = ["2160", "1440", "1080", "720", "480", "360", "240"];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Innertube } from 'youtubei.js';
import { maxVideoDuration } from '../../config.js';
import { cleanString } from '../../sub/utils.js';
import { maxVideoDuration } from '../../../core/config.js';
import { cleanString } from '../../util/misc.js';

const yt = await Innertube.create();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { services } from "../config.js";
import { services } from "../../core/config.js";
import { strict as assert } from "node:assert";
import psl from "psl";

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/modules/stream/manage.js → api/modules/stream/manage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import NodeCache from "node-cache";
import { randomBytes } from "crypto";
import { nanoid } from 'nanoid';

import { decryptStream, encryptStream, generateHmac } from "../sub/crypto.js";
import { streamLifespan } from "../config.js";
import { decryptStream, encryptStream, generateHmac } from "../util/crypto.js";
import { streamLifespan } from "../../core/config.js";

const streamNoAccess = {
error: "i couldn't verify if you have access to this stream. go back and try again!",
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/modules/stream/types.js → api/modules/stream/types.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { spawn } from "child_process";
import ffmpeg from "ffmpeg-static";
import { ffmpegArgs, genericUserAgent } from "../config.js";
import { metadataManager } from "../sub/utils.js";
import { ffmpegArgs, genericUserAgent } from "../../core/config.js";
import { metadataManager } from "../util/misc.js";
import { request } from "undici";
import { create as contentDisposition } from "content-disposition-header";

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 14 additions & 0 deletions api/modules/util/loadFromFs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as fs from "fs";

import path from 'path';
import { fileURLToPath } from 'url';

const dir = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../');

export function loadJSON(filePath) {
try {
return JSON.parse(fs.readFileSync(path.join(dir, filePath), 'utf-8'))
} catch(e) {
return false
}
}
File renamed without changes.
Loading