internal changes only
- remade config module - renamed loc to i18n because that's what all developers do - moved code to src to make repo look cleaner - fixed some i18n strings
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
node_modules
|
||||
package-lock.json
|
||||
.env
|
||||
.env
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# cobalt
|
||||
Sleek and easy to use social media downloader built on JavaScript. Try it out live: [co.wukko.me](https://co.wukko.me/)!
|
||||
|
||||
![cobalt logo](https://raw.githubusercontent.com/wukko/cobalt/current/files/icons/wide.png "cobalt logo")
|
||||
![cobalt logo](https://raw.githubusercontent.com/wukko/cobalt/current/src/static/icons/wide.png "cobalt logo")
|
||||
|
||||
## What is cobalt?
|
||||
Everyone is annoyed by the mess video downloaders are on the web, and cobalt aims to be the ultimate social media downloader, that is efficient, pretty, and doesn't bother you with ads or privacy invasion agreement popups.
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import loadJson from "./sub/load-json.js";
|
||||
|
||||
let config = loadJson("./config.json");
|
||||
let services = loadJson("./modules/services/all.json");
|
||||
|
||||
let appName = config.appName
|
||||
let version = config.version
|
||||
let streamLifespan = config.streamLifespan
|
||||
let maxVideoDuration = config.maxVideoDuration
|
||||
let genericUserAgent = config.genericUserAgent
|
||||
let repo = config.repo
|
||||
let authorInfo = config.authorInfo
|
||||
let supportedLanguages = config.supportedLanguages
|
||||
let quality = config.quality
|
||||
let internetExplorerRedirect = config.internetExplorerRedirect
|
||||
let donations = config.donations
|
||||
let ffmpegArgs = config.ffmpegArgs
|
||||
|
||||
export {appName, version, streamLifespan, maxVideoDuration, genericUserAgent, repo, authorInfo, services, supportedLanguages, quality, internetExplorerRedirect, donations, ffmpegArgs}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cobalt",
|
||||
"description": "easy to use social media downloader",
|
||||
"description": "probably the friendliest social media downloader yet",
|
||||
"version": "2.2",
|
||||
"author": "wukko",
|
||||
"exports": "./cobalt.js",
|
||||
|
@ -9,8 +9,8 @@
|
|||
"node": ">=14.16"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node cobalt",
|
||||
"setup": "node modules/setup.js"
|
||||
"start": "node src/cobalt",
|
||||
"setup": "node src/modules/setup"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -10,7 +10,7 @@ import { appName, genericUserAgent, version, internetExplorerRedirect } from "./
|
|||
import { getJSON } from "./modules/api.js";
|
||||
import renderPage from "./modules/page-renderer.js";
|
||||
import { apiJSON } from "./modules/sub/api-helper.js";
|
||||
import loc from "./modules/sub/loc.js";
|
||||
import loc from "./modules/sub/i18n.js";
|
||||
import { Bright, Cyan } from "./modules/sub/console-text.js";
|
||||
import stream from "./modules/stream/stream.js";
|
||||
|
||||
|
@ -19,7 +19,7 @@ const app = express();
|
|||
|
||||
app.disable('x-powered-by');
|
||||
|
||||
if (fs.existsSync('./.env') && fs.existsSync('./config.json')) {
|
||||
if (fs.existsSync('./.env')) {
|
||||
const apiLimiter = rateLimit({
|
||||
windowMs: 20 * 60 * 1000,
|
||||
max: 100,
|
||||
|
@ -41,7 +41,7 @@ if (fs.existsSync('./.env') && fs.existsSync('./config.json')) {
|
|||
|
||||
app.use('/api/', apiLimiter);
|
||||
app.use('/api/stream', apiLimiterStream);
|
||||
app.use('/', express.static('files'));
|
||||
app.use('/', express.static('./src/static'));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
try {
|
11
src/i18n/en/accessibility.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"about": "View about",
|
||||
"settings": "Open settings",
|
||||
"input": "Link input area",
|
||||
"download": "Download button",
|
||||
"changelog": "View changelog",
|
||||
"close": "Close the popup",
|
||||
"alwaysVisibleButton": "Keep the download button always visible",
|
||||
"downloadPopup": "Ask what to do with downloads",
|
||||
"donate": "Open donation popup"
|
||||
}
|
|
@ -4,7 +4,7 @@ import { services as patterns } from "./config.js";
|
|||
|
||||
import { cleanURL, apiJSON } from "./sub/api-helper.js";
|
||||
import { errorUnsupported } from "./sub/errors.js";
|
||||
import loc from "./sub/loc.js";
|
||||
import loc from "./sub/i18n.js";
|
||||
import match from "./match.js";
|
||||
|
||||
export async function getJSON(originalURL, ip, lang, format, quality) {
|
17
src/modules/config.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import loadJson from "./sub/load-json.js";
|
||||
const config = loadJson("./src/config.json");
|
||||
|
||||
export const
|
||||
services = loadJson("./src/modules/services/all.json"),
|
||||
appName = config.appName,
|
||||
version = config.version,
|
||||
streamLifespan = config.streamLifespan,
|
||||
maxVideoDuration = config.maxVideoDuration,
|
||||
genericUserAgent = config.genericUserAgent,
|
||||
repo = config.repo,
|
||||
authorInfo = config.authorInfo,
|
||||
supportedLanguages = config.supportedLanguages,
|
||||
quality = config.quality,
|
||||
internetExplorerRedirect = config.internetExplorerRedirect,
|
||||
donations = config.donations,
|
||||
ffmpegArgs = config.ffmpegArgs
|
|
@ -41,9 +41,9 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit
|
|||
}) : apiJSON(0, { t: r.error });
|
||||
} else throw Error()
|
||||
case "youtube":
|
||||
if (patternMatch["id"]) {
|
||||
if (patternMatch["id"] && patternMatch["id"].length >= 11) {
|
||||
let fetchInfo = {
|
||||
id: patternMatch["id"].slice(0, 11),
|
||||
id: patternMatch["id"].slice(0,11),
|
||||
lang: lang, quality: quality,
|
||||
format: "mp4"
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
import { services, appName, authorInfo, version, quality, repo, donations } from "./config.js";
|
||||
import { getCommitInfo } from "./sub/current-commit.js";
|
||||
import loc from "./sub/loc.js";
|
||||
import loc from "./sub/i18n.js";
|
||||
|
||||
let s = services
|
||||
let enabledServices = Object.keys(s).filter((p) => {
|
|
@ -1,5 +1,5 @@
|
|||
import got from "got";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
import { genericUserAgent, maxVideoDuration } from "../config.js";
|
||||
|
||||
export default async function(obj) {
|
||||
|
@ -15,14 +15,10 @@ export default async function(obj) {
|
|||
let streamData = JSON.parse(html.split('<script>window.__playinfo__=')[1].split('</script>')[0]);
|
||||
if (streamData.data.timelength <= maxVideoDuration) {
|
||||
let video = streamData["data"]["dash"]["video"].filter((v) => {
|
||||
if (!v["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/") && v["height"] != 4320) {
|
||||
return true;
|
||||
}
|
||||
if (!v["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/") && v["height"] != 4320) return true;
|
||||
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
||||
let audio = streamData["data"]["dash"]["audio"].filter((a) => {
|
||||
if (!a["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) {
|
||||
return true;
|
||||
}
|
||||
if (!a["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) return true;
|
||||
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
||||
return { urls: [video[0]["baseUrl"], audio[0]["baseUrl"]], time: streamData.data.timelength, filename: `bilibili_${obj.id}_${video[0]["width"]}x${video[0]["height"]}.mp4` };
|
||||
} else {
|
|
@ -1,5 +1,5 @@
|
|||
import got from "got";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
import { genericUserAgent, maxVideoDuration } from "../config.js";
|
||||
|
||||
export default async function(obj) {
|
|
@ -1,5 +1,5 @@
|
|||
import got from "got";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
import { services } from "../config.js";
|
||||
|
||||
const configSt = services.twitter;
|
|
@ -1,6 +1,6 @@
|
|||
import got from "got";
|
||||
import { xml2json } from "xml-js";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
import { genericUserAgent, maxVideoDuration, services } from "../config.js";
|
||||
import selectQuality from "../stream/select-quality.js";
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import ytdl from "ytdl-core";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
import { maxVideoDuration, quality as mq } from "../config.js";
|
||||
import selectQuality from "../stream/select-quality.js";
|
||||
|
|
@ -4,7 +4,7 @@ import got from "got";
|
|||
import { ffmpegArgs, genericUserAgent } from "../config.js";
|
||||
import { msToTime } from "../sub/api-helper.js";
|
||||
import { internalError } from "../sub/errors.js";
|
||||
import loc from "../sub/loc.js";
|
||||
import loc from "../sub/i18n.js";
|
||||
|
||||
export async function streamDefault(streamInfo, res) {
|
||||
try {
|
|
@ -1,4 +1,4 @@
|
|||
import loc from "./loc.js";
|
||||
import loc from "./i18n.js";
|
||||
|
||||
export function internalError(res) {
|
||||
res.status(501).json({ status: "error", text: "Internal Server Error" });
|
|
@ -6,7 +6,7 @@ export default function(lang, cat, string, replacement) {
|
|||
lang = 'en'
|
||||
}
|
||||
try {
|
||||
let str = loadJson(`./strings/${lang}/${cat}.json`);
|
||||
let str = loadJson(`./src/i18n/${lang}/${cat}.json`);
|
||||
if (str && str[string]) {
|
||||
let s = str[string].replace(/\n/g, '<br/>').replace(/{appName}/g, appName).replace(/{repo}/g, repo)
|
||||
if (replacement) {
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"about": "About",
|
||||
"settings": "Settings",
|
||||
"input": "URL input area",
|
||||
"download": "Download button",
|
||||
"changelog": "Changelog",
|
||||
"close": "Close button",
|
||||
"alwaysVisibleButton": "Keep the download button always visible",
|
||||
"donate": "Support development of {appName} by donating"
|
||||
}
|