/***
@ Base: https://mconverter.eu/
@ Author: Shannz
@ Note: Converter file fast and simple.
***/
import axios from 'axios';
import { wrapper } from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';
import FormData from 'form-data';
import fs from 'fs';
import path from 'path';
import mime from 'mime-types';
const jar = new CookieJar();
const client = wrapper(axios.create({
jar,
withCredentials: true,
timeout: 60000
}));
const CONFIG = {
BASE_URL: "https://mconverter.eu",
API: {
HOME: "https://mconverter.eu/",
UPLOAD: "/cf_nocache/ajax/upload.php",
PROGRESS: "/cf_nocache/ajax/check_progress.php",
GET_TARGETS: "/cf_nocache/ajax/get_targets.php",
DOWNLOAD: "/cf_nocache/ajax/download.php"
},
HEADERS: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"Origin": "https://mconverter.eu",
"Referer": "https://mconverter.eu/",
"X-Requested-With": "XMLHttpRequest"
},
SUPPORTED_SOURCES: [
"3g2","3gp","3gp2","3gpp","7z","aac","ac3","ai","aif","aiff","amv","apk","arw","avi","avif","azw","azw3",
"bmp","bz2","cab","cbr","cbz","cr2","cr3","cso","csv","deskthemepack","dng","doc","docx","drawio","eps",
"epub","fb2","flac","flv","gif","gz","heic","htm","html","ico","ipynb","iso","jar","jpeg","jpg","json",
"jxl","m4a","markdown","mcaddon","mcpack","mctemplate","mcworld","md","mid","mkv","mobi","mov","mp3",
"mp4","mpeg","mpg","mpo","mxf","nef","odp","ods","odt","ogg","opus","pdf","png","ppm","pps","ppsx","ppt",
"pptx","psd","raf","rar","rtf","rw2","sami","smi","srt","sub","svg","tab","tar","tbz2","tgz","themepack",
"tif","tiff","tini","tsv","txt","txz","vob","wav","webm","webp","wma","wmv","xcf","xls","xlsx","xz","zip"
]
};
let sessionInitialized = false;
const initSession = async () => {
if (sessionInitialized) return;
try {
await client.get(CONFIG.API.HOME, {
headers: {
...CONFIG.HEADERS,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Sec-Fetch-Mode": "navigate",
"X-Requested-With": undefined
}
});
sessionInitialized = true;
} catch (e) {
console.log("⚠️ Gagal init session, mencoba lanjut...");
}
};
export const mconverter = {
getAvailableTargets: async (filename) => {
await initSession();
const ext = filename.split('.').pop().toLowerCase();
const form = new FormData();
form.append('extensions', ext);
try {
const res = await client.post(CONFIG.BASE_URL + CONFIG.API.GET_TARGETS, form, {
headers: { ...CONFIG.HEADERS, ...form.getHeaders() }
});
const allTargets = [];
const extractTargets = (obj) => {
if (Array.isArray(obj)) {
obj.forEach(item => extractTargets(item));
} else if (typeof obj === 'object' && obj !== null) {
if (obj.name && obj.mime) {
allTargets.push(obj);
}
Object.values(obj).forEach(val => extractTargets(val));
}
};
if (res.data && res.data.formats) {
extractTargets(res.data.formats);
}
const uniqueTargets = [...new Map(allTargets.map(item => [item.name, item])).values()];
return uniqueTargets.sort((a, b) => a.name.localeCompare(b.name));
} catch (e) {
console.error("Error fetching targets:", e.message);
return [];
}
},
convert: async (inputPath, targetFormat) => {
await initSession();
if (!fs.existsSync(inputPath)) return { error: 'File tidak ada' };
const filename = path.basename(inputPath);
const fileSize = fs.statSync(inputPath).size;
const mimeType = mime.lookup(inputPath) || 'application/octet-stream';
try {
const chunk0 = fs.createReadStream(inputPath, { start: 0, end: 0 });
const paramsInit = new URLSearchParams({
target_format: targetFormat,
total_size: fileSize,
source_mime: mimeType,
filename: filename,
abd: 'false',
captcha: ''
});
const formInit = new FormData();
formInit.append('file', chunk0);
const resInit = await client.post(`${CONFIG.BASE_URL}${CONFIG.API.UPLOAD}?${paramsInit.toString()}`, formInit, {
headers: { ...CONFIG.HEADERS, ...formInit.getHeaders() }
});
if (resInit.data.error) throw new Error(resInit.data.error.message);
const token = resInit.data.token;
if(!token) throw new Error("Gagal dapet token upload");
let startByte = 1;
const CHUNK_SIZE = 10 * 1024 * 1024;
while (startByte < fileSize) {
let endByte = Math.min(startByte + CHUNK_SIZE, fileSize);
const chunk = fs.createReadStream(inputPath, { start: startByte, end: endByte - 1 });
const params = new URLSearchParams({ token, start_byte: startByte });
const form = new FormData();
form.append('file', chunk);
const resChunk = await client.post(`${CONFIG.BASE_URL}${CONFIG.API.UPLOAD}?${params.toString()}`, form, {
headers: { ...CONFIG.HEADERS, ...form.getHeaders() },
maxContentLength: Infinity, maxBodyLength: Infinity
});
if (resChunk.data.error) throw new Error(resChunk.data.error.message);
if (!resChunk.data.awaiting_chunks) break;
startByte = endByte;
}
let status = 'processing';
let attempts = 0;
process.stdout.write(` ⏳ Convert (${targetFormat})... `);
while (status !== 'finished' && attempts < 100) {
attempts++;
await new Promise(r => setTimeout(r, 2000));
const resPoll = await client.get(`${CONFIG.BASE_URL}${CONFIG.API.PROGRESS}?token=${token}`, {
headers: CONFIG.HEADERS
});
const data = resPoll.data;
status = data.conversion_data?.status;
if (status === 'error') throw new Error(data.error_data?.error_reason || 'Unknown error');
if (status === 'finished') {
process.stdout.write('✅ Selesai!\n');
const dlParams = new URLSearchParams({
token: token,
file_idx: 1,
no_idx_in_name: 1,
orig_names: 'checked'
});
const downloadUrl = `${CONFIG.BASE_URL}${CONFIG.API.DOWNLOAD}?${dlParams.toString()}`;
return { success: true, url: downloadUrl };
}
}
return { error: 'Timeout waiting for conversion' };
} catch (e) {
process.stdout.write('❌\n');
return { error: e.message };
}
}
};