Add SoundCload to downloader

This commit is contained in:
Sudo Space 2025-04-11 14:12:50 +03:30
parent 6b5a01d607
commit f6518ef851
7 changed files with 92 additions and 2 deletions

View file

@ -12,6 +12,7 @@ This bot supports concurrency, meaning that if multiple users request the same c
- 🎧 Youtube Music
- 👯 Tiktok (Video)
- 📸 Instagram (Video)
- ☁️ SoundCloud
## Admin's Commands

View file

@ -29,6 +29,7 @@ checker.on("message", (ctx, next) => {
user!.media = { type: "tt", url: link };
else if (domain == "www.instagram.com" || domain == "instagram.com")
user!.media = { type: "ig", url: link };
else if (domain == "soundcloud.com") user!.media = { type: "sc", url: link };
else return ctx.reply("Unsupported platform! ❌");
next();
});

View file

@ -13,7 +13,8 @@ it support currently:
📺 Youtube (Video / Audio)
🎧 Youtube Music
👯 Tiktok (Video)
📸 Instagram (Video)`);
📸 Instagram (Video)
SoundCloud`);
});
commands.command("clean", async (ctx) => {

View file

@ -7,6 +7,7 @@ import handleYoutube from "middlewares/services/youtube";
import handleYTMusic from "middlewares/services/youtube-muisc";
import handleTiktok from "middlewares/services/tiktok";
import handleInstagram from "./services/instagram";
import handleSoundCloud from "./services/soundcloud";
import { youtubeFormatsList } from "middlewares/services/youtube";
@ -31,6 +32,10 @@ downloader.use(async (ctx, next) => {
await handleInstagram(ctx, media.url);
break;
case "sc":
await handleSoundCloud(ctx, media.url);
break;
case "yt":
if (ctx.callbackQuery) {
return next();

View file

@ -0,0 +1,36 @@
import { InputFile } from "grammy";
import type { UserContext } from "types/type";
import SoundCloud from "models/soundcloud";
import { waitList, waitForDownload } from "helpers/utils";
async function handleSoundCloud(ctx: UserContext, url: string) {
let ytdlp: SoundCloud;
const instance = waitList.get(url);
if (instance) ytdlp = instance as SoundCloud;
else {
ytdlp = new SoundCloud(url);
waitList.set(url, ytdlp);
}
const msg = await ctx.reply("⬇️ Downloading...");
try {
if (ytdlp.status == "INACTIVE") await ytdlp.downloadAudio();
else await waitForDownload(ytdlp);
await ctx.api.sendChatAction(ctx.chatId!, "upload_document");
await ctx.replyWithAudio(new InputFile(ytdlp.filePath));
await ctx.api.deleteMessage(msg.chat.id, msg.message_id);
await ytdlp.clean();
} catch (error) {
console.log(error);
return ctx.reply("Download operation has been failed. 😭");
}
waitList.delete(url);
}
export default handleSoundCloud;

46
src/models/soundcloud.ts Normal file
View file

@ -0,0 +1,46 @@
import Ytdlp from "models/ytdlp";
import { spawn } from "bun";
import { join } from "path";
import { rootPath, sanitizePath } from "helpers/utils";
class SoundCloud extends Ytdlp {
async downloadAudio() {
const outPath = join(rootPath(), "downloads", `%(title)s.%(ext)s`);
this.status = "ACTIVE";
const p = spawn(
[
"yt-dlp",
"--extract-audio",
"--audio-format",
"mp3",
"-f",
"ba",
"--embed-thumbnail",
"--add-metadata",
"-o",
outPath,
this.url,
"--quiet",
"--exec",
"echo {}",
],
{
stderr: "pipe",
stdout: "pipe",
}
);
const exitCode = await p.exited;
if (exitCode != 0) {
this.status = "INACTIVE";
const err = new Error(await new Response(p.stderr).text());
throw err;
}
const path = await new Response(p.stdout).text();
this.filePath = sanitizePath(path);
this.status = "INACTIVE";
}
}
export default SoundCloud;

View file

@ -3,7 +3,7 @@ export interface UserSessionData {
id: string;
role: "ADMIN" | "USER";
media?: {
type: "pin" | "yt" | "ytm" | "tt" | "ig";
type: "pin" | "yt" | "ytm" | "tt" | "ig" | "sc";
url: string;
};
} | null;