mobile, idek

This commit is contained in:
sky
2025-08-17 19:14:11 -04:00
parent db94e9fe49
commit 4e315c993a
6 changed files with 293 additions and 119 deletions

View File

@ -9,17 +9,145 @@ async function search(query) {
let data = sc.search(query);
return data;
}
async function download(url) {
try {
const info = await sc.getByUrl(url);
// so um fuck lucida
// based on https://github.com/imputnet/cobalt/blob/58ea4aed01383ead74d5e32e75335eddc2f015be/api/src/processing/services/soundcloud.js
const { stream } = await info.getStream();
const cachedID = {
version: '',
id: ''
}
return stream.path;
} catch (err) {
console.error('Stream error:', err)
return(err.message || 'Failed to stream track')
}
async function findClientID() {
try {
const sc = await fetch('https://soundcloud.com/').then(r => r.text()).catch(() => {});
const scVersion = String(sc.match(/<script>window\.__sc_version="[0-9]{10}"<\/script>/)[0].match(/[0-9]{10}/));
if (cachedID.version === scVersion) {
return cachedID.id;
}
const scripts = sc.matchAll(/<script.+src="(.+)">/g);
let clientid;
for (let script of scripts) {
const url = script[1];
if (!url?.startsWith('https://a-v2.sndcdn.com/')) {
return;
}
const scrf = await fetch(url).then(r => r.text()).catch(() => {});
const id = scrf.match(/\("client_id=[A-Za-z0-9]{32}"\)/);
if (id && typeof id[0] === 'string') {
clientid = id[0].match(/[A-Za-z0-9]{32}/)[0];
break;
}
}
cachedID.version = scVersion;
cachedID.id = clientid;
return clientid;
} catch {}
}
const findBestForPreset = (transcodings, preset) => {
let inferior;
for (const entry of transcodings) {
const protocol = entry?.format?.protocol;
if (entry.snipped || protocol?.includes('encrypted')) {
continue;
}
if (entry?.preset?.startsWith(`${preset}_`)) {
if (protocol === 'progressive') {
return entry;
}
inferior = entry;
}
}
return inferior;
}
async function download(obj) {
const clientId = await findClientID();
if (!clientId) return { error: "fetch.fail" };
let link = obj;
const resolveURL = new URL("https://api-v2.soundcloud.com/resolve");
resolveURL.searchParams.set("url", link);
resolveURL.searchParams.set("client_id", clientId);
const json = await fetch(resolveURL).then(r => r.json()).catch(() => {});
if (!json) return { error: "fetch.fail" };
if (json.duration > 60 * 30 * 1000) {
return { error: "content.too_long" };
}
if (json.policy === "BLOCK") {
return { error: "content.region" };
}
if (json.policy === "SNIP") {
return { error: "content.paid" };
}
if (!json.media?.transcodings || !json.media?.transcodings.length === 0) {
return { error: "fetch.empty" };
}
let bestAudio = "opus",
selectedStream = findBestForPreset(json.media.transcodings, "opus");
const mp3Media = findBestForPreset(json.media.transcodings, "mp3");
// use mp3 if present if user prefers it or if opus isn't available
if (mp3Media && (obj.format === "mp3" || !selectedStream)) {
selectedStream = mp3Media;
bestAudio = "mp3"
}
if (!selectedStream) {
return { error: "fetch.empty" };
}
const fileUrl = new URL(selectedStream.url);
fileUrl.searchParams.set("client_id", clientId);
fileUrl.searchParams.set("track_authorization", json.track_authorization);
const file = await fetch(fileUrl)
.then(async r => new URL((await r.json()).url))
.catch(() => {});
if (!file) return { error: "fetch.empty" };
const artist = json.user?.username?.trim();
const fileMetadata = {
title: json.title?.trim(),
album: json.publisher_metadata?.album_title?.trim(),
artist,
album_artist: artist,
composer: json.publisher_metadata?.writer_composer?.trim(),
genre: json.genre?.trim(),
date: json.display_date?.trim().slice(0, 10),
copyright: json.license?.trim(),
}
return {
urls: file.toString(),
filenameAttributes: {
service: "soundcloud",
id: json.id,
...fileMetadata
},
bestAudio,
fileMetadata,
isHLS: file.pathname.endsWith('.m3u8'),
}
}
export { search, download };

View File

@ -8,6 +8,7 @@ import { download } from "./music.js";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime.js";
import { error } from "node:console";
dayjs.extend(relativeTime);
const sanitizeConfig = {
@ -201,7 +202,7 @@ async function editProfile(body, token, admin) {
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(path, "");
await sharp(pfp, { animated: fileType == "gif" })
.resize({ width: 300, withoutEnlargement: true })
.resize({ width: 400, withoutEnlargement: true })
.webp({ quality: 70, effort: 4 })
.toFile(path);
await fs.unlink(`${__dirname}/${userData.pfp_url}`, () => {});
@ -217,13 +218,25 @@ async function editProfile(body, token, admin) {
if(checkStatusRequest.status != 200) {
return { success: false, err: "processing server is down, try again later"};
}
let path = await download(body.url);
console.log("exit download");
let file = Bun.file(path);
let data = await download(body.url);
if(data.error) {
if(data.error == "content.too_long") {
return { success: false, err: "the song was too long, pick something shorter!"};
} else if(data.error == "content.region") {
return { success: false, err: "the song could not be downloaded due to the region of the server."};
} else if(data.error == "content.paid") {
return { success: false, err: "the song is go+ only, and we're too poor to pay for that :( pick another song"};
} else if(data.error == "fetch.empty") {
return { success: false, err: "we could not fetch this song successfully"};
} else {
return { success: false, err: "an unknown error happened! error code: " + error};
}
}
let streamingURL = data.urls;
let request = new Request({
url: process.env.PROCESSING_SERVER + "/process",
method: "POST",
body: await file.arrayBuffer(),
body: JSON.stringify({url: streamingURL}),
headers: {
"X-Authentication": process.env.PROCESSING_SERVER_SECRET
}