mirror of
https://github.com/wukko/cobalt.git
synced 2025-05-16 21:37:06 +02:00
merge: soundcloud fix from main
This commit is contained in:
commit
9a3d35185b
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@imput/cobalt-api",
|
"name": "@imput/cobalt-api",
|
||||||
"description": "save what you love",
|
"description": "save what you love",
|
||||||
"version": "10.9.3",
|
"version": "10.9.4",
|
||||||
"author": "imput",
|
"author": "imput",
|
||||||
"exports": "./src/cobalt.js",
|
"exports": "./src/cobalt.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@ -161,12 +161,8 @@ export default async function({ host, patternMatch, params }) {
|
|||||||
isAudioOnly = true;
|
isAudioOnly = true;
|
||||||
isAudioMuted = false;
|
isAudioMuted = false;
|
||||||
r = await soundcloud({
|
r = await soundcloud({
|
||||||
url,
|
...patternMatch,
|
||||||
author: patternMatch.author,
|
|
||||||
song: patternMatch.song,
|
|
||||||
format: params.audioFormat,
|
format: params.audioFormat,
|
||||||
shortLink: patternMatch.shortLink || false,
|
|
||||||
accessKey: patternMatch.accessKey || false
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { env } from "../../config.js";
|
import { env } from "../../config.js";
|
||||||
|
import { resolveRedirectingURL } from "../url.js";
|
||||||
|
|
||||||
const cachedID = {
|
const cachedID = {
|
||||||
version: '',
|
version: '',
|
||||||
@ -7,22 +8,25 @@ const cachedID = {
|
|||||||
|
|
||||||
async function findClientID() {
|
async function findClientID() {
|
||||||
try {
|
try {
|
||||||
let sc = await fetch('https://soundcloud.com/').then(r => r.text()).catch(() => {});
|
const sc = await fetch('https://soundcloud.com/').then(r => r.text()).catch(() => {});
|
||||||
let scVersion = String(sc.match(/<script>window\.__sc_version="[0-9]{10}"<\/script>/)[0].match(/[0-9]{10}/));
|
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;
|
if (cachedID.version === scVersion) {
|
||||||
|
return cachedID.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scripts = sc.matchAll(/<script.+src="(.+)">/g);
|
||||||
|
|
||||||
let scripts = sc.matchAll(/<script.+src="(.+)">/g);
|
|
||||||
let clientid;
|
let clientid;
|
||||||
for (let script of scripts) {
|
for (let script of scripts) {
|
||||||
let url = script[1];
|
const url = script[1];
|
||||||
|
|
||||||
if (!url?.startsWith('https://a-v2.sndcdn.com/')) {
|
if (!url?.startsWith('https://a-v2.sndcdn.com/')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrf = await fetch(url).then(r => r.text()).catch(() => {});
|
const scrf = await fetch(url).then(r => r.text()).catch(() => {});
|
||||||
let id = scrf.match(/\("client_id=[A-Za-z0-9]{32}"\)/);
|
const id = scrf.match(/\("client_id=[A-Za-z0-9]{32}"\)/);
|
||||||
|
|
||||||
if (id && typeof id[0] === 'string') {
|
if (id && typeof id[0] === 'string') {
|
||||||
clientid = id[0].match(/[A-Za-z0-9]{32}/)[0];
|
clientid = id[0].match(/[A-Za-z0-9]{32}/)[0];
|
||||||
@ -37,46 +41,57 @@ async function findClientID() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function(obj) {
|
export default async function(obj) {
|
||||||
let clientId = await findClientID();
|
const clientId = await findClientID();
|
||||||
if (!clientId) return { error: "fetch.fail" };
|
if (!clientId) return { error: "fetch.fail" };
|
||||||
|
|
||||||
let link;
|
let link;
|
||||||
if (obj.url.hostname === 'on.soundcloud.com' && obj.shortLink) {
|
|
||||||
link = await fetch(`https://on.soundcloud.com/${obj.shortLink}/`, { redirect: "manual" }).then(r => {
|
if (obj.shortLink) {
|
||||||
if (r.status === 302 && r.headers.get("location").startsWith("https://soundcloud.com/")) {
|
obj = {
|
||||||
return r.headers.get("location").split('?', 1)[0]
|
...obj,
|
||||||
}
|
...await resolveRedirectingURL(
|
||||||
}).catch(() => {});
|
`https://on.soundcloud.com/${obj.shortLink}`
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link && obj.author && obj.song) {
|
if (obj.author && obj.song) {
|
||||||
link = `https://soundcloud.com/${obj.author}/${obj.song}${obj.accessKey ? `/s-${obj.accessKey}` : ''}`
|
link = `https://soundcloud.com/${obj.author}/${obj.song}`;
|
||||||
|
if (obj.accessKey) {
|
||||||
|
link += `/s-${obj.accessKey}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link && obj.shortLink) return { error: "fetch.short_link" };
|
if (!link && obj.shortLink) return { error: "fetch.short_link" };
|
||||||
if (!link) return { error: "link.unsupported" };
|
if (!link) return { error: "link.unsupported" };
|
||||||
|
|
||||||
let json = await fetch(`https://api-v2.soundcloud.com/resolve?url=${link}&client_id=${clientId}`)
|
const resolveURL = new URL("https://api-v2.soundcloud.com/resolve");
|
||||||
.then(r => r.status === 200 ? r.json() : false)
|
resolveURL.searchParams.set("url", link);
|
||||||
.catch(() => {});
|
resolveURL.searchParams.set("client_id", clientId);
|
||||||
|
|
||||||
|
const json = await fetch(resolveURL).then(r => r.json()).catch(() => {});
|
||||||
if (!json) return { error: "fetch.fail" };
|
if (!json) return { error: "fetch.fail" };
|
||||||
|
|
||||||
if (json?.policy === "BLOCK") {
|
if (json.duration > env.durationLimit * 1000) {
|
||||||
|
return { error: "content.too_long" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.policy === "BLOCK") {
|
||||||
return { error: "content.region" };
|
return { error: "content.region" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json?.policy === "SNIP") {
|
if (json.policy === "SNIP") {
|
||||||
return { error: "content.paid" };
|
return { error: "content.paid" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json?.media?.transcodings || !json?.media?.transcodings.length === 0) {
|
if (!json.media?.transcodings || !json.media?.transcodings.length === 0) {
|
||||||
return { error: "fetch.empty" };
|
return { error: "fetch.empty" };
|
||||||
}
|
}
|
||||||
|
|
||||||
let bestAudio = "opus",
|
let bestAudio = "opus",
|
||||||
selectedStream = json.media.transcodings.find(v => v.preset === "opus_0_0"),
|
selectedStream = json.media.transcodings.find(v => v.preset === "opus_0_0");
|
||||||
mp3Media = json.media.transcodings.find(v => v.preset === "mp3_0_0");
|
|
||||||
|
const mp3Media = json.media.transcodings.find(v => v.preset === "mp3_0_0");
|
||||||
|
|
||||||
// use mp3 if present if user prefers it or if opus isn't available
|
// use mp3 if present if user prefers it or if opus isn't available
|
||||||
if (mp3Media && (obj.format === "mp3" || !selectedStream)) {
|
if (mp3Media && (obj.format === "mp3" || !selectedStream)) {
|
||||||
@ -88,22 +103,17 @@ export default async function(obj) {
|
|||||||
return { error: "fetch.empty" };
|
return { error: "fetch.empty" };
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileUrlBase = selectedStream.url;
|
const fileUrl = new URL(selectedStream.url);
|
||||||
let fileUrl = `${fileUrlBase}${fileUrlBase.includes("?") ? "&" : "?"}client_id=${clientId}&track_authorization=${json.track_authorization}`;
|
fileUrl.searchParams.set("client_id", clientId);
|
||||||
|
fileUrl.searchParams.set("track_authorization", json.track_authorization);
|
||||||
|
|
||||||
if (!fileUrl.startsWith("https://api-v2.soundcloud.com/media/soundcloud:tracks:"))
|
const file = await fetch(fileUrl)
|
||||||
return { error: "fetch.empty" };
|
|
||||||
|
|
||||||
if (json.duration > env.durationLimit * 1000) {
|
|
||||||
return { error: "content.too_long" };
|
|
||||||
}
|
|
||||||
|
|
||||||
let file = await fetch(fileUrl)
|
|
||||||
.then(async r => (await r.json()).url)
|
.then(async r => (await r.json()).url)
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|
||||||
if (!file) return { error: "fetch.empty" };
|
if (!file) return { error: "fetch.empty" };
|
||||||
|
|
||||||
let fileMetadata = {
|
const fileMetadata = {
|
||||||
title: json.title.trim(),
|
title: json.title.trim(),
|
||||||
artist: json.user.username.trim(),
|
artist: json.user.username.trim(),
|
||||||
}
|
}
|
||||||
@ -113,8 +123,7 @@ export default async function(obj) {
|
|||||||
filenameAttributes: {
|
filenameAttributes: {
|
||||||
service: "soundcloud",
|
service: "soundcloud",
|
||||||
id: json.id,
|
id: json.id,
|
||||||
title: fileMetadata.title,
|
...fileMetadata
|
||||||
author: fileMetadata.artist
|
|
||||||
},
|
},
|
||||||
bestAudio,
|
bestAudio,
|
||||||
fileMetadata
|
fileMetadata
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "on.soundcloud link",
|
"name": "on.soundcloud link",
|
||||||
"url": "https://on.soundcloud.com/wLZre",
|
"url": "https://on.soundcloud.com/XHLLKSXRQ5yyGDuD9",
|
||||||
"params": {},
|
"params": {},
|
||||||
"expected": {
|
"expected": {
|
||||||
"code": 200,
|
"code": 200,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user