Skip to content

Instantly share code, notes, and snippets.

@Amr1977
Created October 7, 2025 08:03
Show Gist options
  • Select an option

  • Save Amr1977/6bb006e2adfbb96b0315cf35342feb22 to your computer and use it in GitHub Desktop.

Select an option

Save Amr1977/6bb006e2adfbb96b0315cf35342feb22 to your computer and use it in GitHub Desktop.
Downloads all MP3 files from a specific tab (if any) in a reciter page. * Usage: node download_mp3s.js "https://ourquraan.com/shyookh/<reciter>#<tab-id>"
/**
* Script: download_mp3s.js
* Description: Downloads all MP3 files from a specific tab (if any) in a reciter page.
* Usage: node download_mp3s.js "https://ourquraan.com/shyookh/<reciter>#<tab-id>"
*/
import fs from 'fs';
import path from 'path';
import axios from 'axios';
import * as cheerio from 'cheerio';
import cliProgress from 'cli-progress';
const targetUrl = process.argv[2];
if (!targetUrl) {
console.error("❌ Usage: node download_mp3s.js <url>");
process.exit(1);
}
function extractReciterName(url) {
try {
const u = new URL(url);
const decoded = decodeURIComponent(u.pathname);
const parts = decoded.split('/').filter(Boolean);
return parts.pop() || 'Unknown_Reciter';
} catch {
return 'Unknown_Reciter';
}
}
function extractTabId(url) {
try {
const u = new URL(url);
return u.hash.replace('#', '').trim() || null;
} catch {
return null;
}
}
const reciterName = extractReciterName(targetUrl);
const tabId = extractTabId(targetUrl);
const baseFolder = path.resolve('./downloads', reciterName);
const downloadDir = tabId
? path.join(baseFolder, tabId)
: baseFolder;
if (!fs.existsSync(downloadDir)) {
fs.mkdirSync(downloadDir, { recursive: true });
console.log(`πŸ“ Created folder: ${downloadDir}`);
}
async function getMp3Links(url) {
console.log(`🌐 Fetching: ${url}`);
const { data } = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
const $ = cheerio.load(data);
let links = [];
if (tabId) {
console.log(`🎯 Looking inside tab: #${tabId}`);
const tabSection = $(`#${tabId}`);
if (tabSection.length === 0) {
console.log(`⚠️ Tab with id "${tabId}" not found.`);
return [];
}
tabSection.find('a[href$=".mp3"]').each((_, el) => {
const href = $(el).attr('href');
if (href) {
const absoluteUrl = new URL(href, url).href;
if (!links.includes(absoluteUrl)) links.push(absoluteUrl);
}
});
} else {
$('a[href$=".mp3"]').each((_, el) => {
const href = $(el).attr('href');
if (href) {
const absoluteUrl = new URL(href, url).href;
if (!links.includes(absoluteUrl)) links.push(absoluteUrl);
}
});
}
console.log(`🎧 Found ${links.length} MP3 links${tabId ? ` in tab #${tabId}` : ''}.\n`);
return links;
}
async function downloadFile(fileUrl) {
const fileName = decodeURIComponent(path.basename(new URL(fileUrl).pathname));
const filePath = path.join(downloadDir, fileName);
if (fs.existsSync(filePath)) {
console.log(`⏩ Skipping (already exists): ${fileName}`);
return;
}
const response = await axios.get(fileUrl, { responseType: 'stream' });
const totalLength = parseInt(response.headers['content-length'] || '0', 10);
console.log(`⬇️ Downloading: ${fileName}`);
const progressBar = new cliProgress.SingleBar({
format: ' {bar} {percentage}% | {value}/{total} KB ',
hideCursor: true,
barCompleteChar: 'β–ˆ',
barIncompleteChar: 'β–‘'
}, cliProgress.Presets.shades_classic);
if (totalLength > 0) progressBar.start(Math.ceil(totalLength / 1024), 0);
const writer = fs.createWriteStream(filePath);
let downloaded = 0;
response.data.on('data', (chunk) => {
downloaded += chunk.length;
if (totalLength > 0) progressBar.update(Math.ceil(downloaded / 1024));
});
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', () => {
if (totalLength > 0) progressBar.stop();
console.log(`βœ… Completed: ${fileName}\n`);
resolve(fileName);
});
writer.on('error', (err) => {
if (totalLength > 0) progressBar.stop();
reject(err);
});
});
}
async function main() {
try {
const mp3Links = await getMp3Links(targetUrl);
if (mp3Links.length === 0) {
console.log("⚠️ No MP3 links found.");
return;
}
for (const link of mp3Links) {
try {
await downloadFile(link);
} catch (err) {
console.error(`❌ Failed to download: ${link}`, err.message);
}
}
console.log(`\nβœ… All downloads complete! Saved in: ${downloadDir}`);
} catch (err) {
console.error("❌ Error:", err.message);
}
}
main();
@Amr1977
Copy link
Author

Amr1977 commented Oct 7, 2025

Install dependencies:
npm install axios cheerio cli-progress

Run:

node download_mp3s.js URL

where URL is any reciter page/tab in https://ourquraan.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment