import axios from "axios"; import FormData from "form-data"; import crypto from "node:crypto"; import fs from "node:fs"; import fsp from "node:fs/promises"; import path from "node:path"; import { CookieJar } from "tough-cookie"; import { wrapper } from "axios-cookiejar-support"; const BASE_URL = "https://wink.ai"; const STRATEGY_URL = "https://strategy.app.meitudata.com"; const CLIENT_ID = "1189857605"; const VERSION = "5.1.2"; const COUNTRY_CODE = "ID"; const CLIENT_LANGUAGE = "en_US"; const CLIENT_TIMEZONE = "Asia/Jakarta"; const TASK_TYPE = "12"; const CONTENT_TYPE = "1"; const UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36"; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function extToMime(file) { const ext = path.extname(file).toLowerCase(); if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg"; if (ext === ".png") return "image/png"; if (ext === ".webp") return "image/webp"; return "application/octet-stream"; } function fileSuffix(file) { const ext = path.extname(file).toLowerCase(); if (ext === ".jpeg") return ".jpg"; if (ext) return ext; return ".jpg"; } function makeTrace() { return `${crypto.randomBytes(16).toString("hex")}-${crypto.randomBytes(8).toString("hex")}-1`; } function traceHeaders(transaction = "GET%20%2F%5Blocale%5D%2Fimage-enhancer%2Fupload") { const trace = makeTrace(); return { "sentry-trace": trace, baggage: [ "sentry-environment=release", "sentry-release=5.1.2", "sentry-public_key=e1bf914f3448d9bc8a10c7e499d17d54", `sentry-trace_id=${trace.split("-")[0]}`, `sentry-transaction=${transaction}`, "sentry-sampled=true", "sentry-sample_rate=0.75" ].join(",") }; } function baseParams(GNUM, extra = {}) { return new URLSearchParams({ client_id: CLIENT_ID, version: VERSION, country_code: COUNTRY_CODE, gnum: GNUM, client_language: CLIENT_LANGUAGE, client_channel_id: "", client_timezone: CLIENT_TIMEZONE, ...extra }); } export async function wink(IMAGE_PATH) { try { const GNUM = crypto.randomUUID(); const jar = new CookieJar(); await jar.setCookie(`_sm=${GNUM}; Path=/; Domain=wink.ai`, BASE_URL); await jar.setCookie(`meitustat=${encodeURIComponent(JSON.stringify({ wgid: GNUM }))}; Path=/; Domain=wink.ai`, BASE_URL); const api = wrapper(axios.create({ baseURL: BASE_URL, jar, withCredentials: true, validateStatus: () => true, headers: { accept: "*/*", origin: BASE_URL, referer: `${BASE_URL}/image-enhancer/upload`, "user-agent": UA, "sec-ch-ua": "\"Google Chrome\";v=\"147\", \"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"147\"", "sec-ch-ua-mobile": "?1", "sec-ch-ua-platform": "\"Android\"", ab_info: JSON.stringify({ ab_codes: [], version: "1.4.4" }) } })); if (!fs.existsSync(IMAGE_PATH)) throw new Error(`File tidak ditemukan: ${IMAGE_PATH}`); const getMaatSign = async () => { const params = baseParams(GNUM, { suffix: fileSuffix(IMAGE_PATH), type: "temp", count: "1" }); const res = await api.get(`/api/file/get_maat_sign.json?${params.toString()}`, { headers: traceHeaders() }); if (res.status >= 400 || res.data?.code !== 0) throw new Error(`get_maat_sign gagal: ${JSON.stringify(res.data)}`); return res.data.data; }; const getUploadPolicy = async (sign) => { const params = new URLSearchParams({ app: sign.app, count: String(sign.count), sig: sign.sig, sigTime: sign.sig_time, sigVersion: sign.sig_version, suffix: sign.suffix, type: sign.type }); const res = await axios.get(`${STRATEGY_URL}/upload/policy?${params.toString()}`, { headers: { accept: "*/*", origin: BASE_URL, referer: `${BASE_URL}/`, "user-agent": UA }, validateStatus: () => true }); if (res.status >= 400 || !Array.isArray(res.data) || !res.data[0]?.qiniu) throw new Error(`upload policy gagal: ${JSON.stringify(res.data)}`); return res.data[0].qiniu; }; const uploadToQiniu = async (policy, filePath) => { const form = new FormData(); form.append("file", fs.createReadStream(filePath), { filename: path.basename(filePath), contentType: extToMime(filePath) }); form.append("token", policy.token); form.append("key", policy.key); form.append("fname", path.basename(filePath)); const res = await axios.post(policy.url, form, { headers: form.getHeaders({ origin: BASE_URL, referer: `${BASE_URL}/`, "user-agent": UA, accept: "*/*" }), maxBodyLength: Infinity, maxContentLength: Infinity, validateStatus: () => true }); if (res.status >= 400) throw new Error(`upload qiniu gagal HTTP ${res.status}`); return { file_key: policy.key, source_url: res.data.url || res.data.data || policy.data }; }; const sign = await getMaatSign(); const policy = await getUploadPolicy(sign); const uploaded = await uploadToQiniu(policy, IMAGE_PATH); const TASK_NAME = `Enhancer-Ultra HD-${path.parse(IMAGE_PATH).name}`; const delivery = async (sourceUrl) => { const body = baseParams(GNUM, { type: TASK_TYPE, content_type: CONTENT_TYPE, source_url: sourceUrl, type_params: JSON.stringify({ is_mirror: 0, orientation_tag: 1, j_420_trans: "1", return_ext: "2" }), right_detail: JSON.stringify({ source: "1", touch_type: "4", function_id: "630", material_id: "63011", url: "https://wink.ai/image-enhancer/upload" }), ext_params: JSON.stringify({ task_name: TASK_NAME, records: TASK_TYPE }), with_prepare: "1" }); const res = await api.post("/api/meitu_ai/delivery.json", body.toString(), { headers: { ...traceHeaders(), "content-type": "application/x-www-form-urlencoded;charset=UTF-8" } }); if (res.status >= 400 || res.data?.code !== 0) throw new Error(`delivery gagal: ${JSON.stringify(res.data)}`); return res.data.data; }; const task = await delivery(uploaded.source_url); const firstMsgId = task.msg_id || task.prepare_msg_id; if (!firstMsgId) throw new Error(`delivery tidak mengembalikan msg_id`); const waitResult = async (msgId) => { for (let i = 1; i <= 80; i++) { const params = baseParams(GNUM, { msg_ids: msgId }); const res = await api.get(`/api/meitu_ai/query_batch.json?${params.toString()}`, { headers: { ...traceHeaders("%2F%3Alocale%2Feditor%2Frecent-task"), referer: `${BASE_URL}/image-enhancer/upload` } }); if (res.status >= 400 || res.data?.code !== 0) throw new Error(`query batch gagal`); const item = res.data.data?.item_list?.[0]; const resultValue = item?.result?.result || ""; const realMsgId = item?.result?.msg_id || item?.msg_id || ""; if (resultValue && resultValue !== msgId && !resultValue.startsWith("http")) { msgId = resultValue; continue; } if (realMsgId && realMsgId !== msgId && !realMsgId.startsWith("wpr_")) { msgId = realMsgId; continue; } const url = item?.result?.media_info_list?.[0]?.media_data; if (url && url.startsWith("http") && item?.result?.error_code === 0) return url; await sleep(3000); } throw new Error("Timeout"); }; const resultUrl = await waitResult(firstMsgId); return { status: true, resultUrl }; } catch (e) { return { status: false, error: e.message }; } }