mobile, idek
This commit is contained in:
@ -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 };
|
||||
@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user