// src/utils.js
function getBeijingDateStr(timeMs) {
const beijingOffset = 8 * 60 * 60 * 1e3;
const date = new Date(timeMs + beijingOffset);
return date.toISOString().split("T")[0];
}
function getSelfDestructTime(expireDate, hasPaid) {
if (!expireDate || expireDate === "-1" || expireDate === "trial") return null;
const t = Date.parse(expireDate.includes("T") ? expireDate : expireDate + "T00:00:00+08:00");
if (isNaN(t)) return null;
return t + (hasPaid ? 365 : 180) * 864e5;
}
async function md5Hex(text) {
const msgUint8 = new TextEncoder().encode(text);
const hashBuffer = await crypto.subtle.digest("MD5", msgUint8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
return hashHex;
}
function vipJson(obj, status = 200) {
return new Response(JSON.stringify(obj), {
status,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Cache-Control": "no-store"
}
});
}
// src/config.js
var regPriceCNY = "1.00";
var priceCNY = "9.90";
var priceYearCNY = "99.00";
var APP_LATEST_VERSION_CODE = 576;
var APP_LATEST_VERSION_NAME = "26.09.17";
var APK_URL_TV = "https://videovideo.2000168.xyz/\u7B80\u5355\u5F71\u89C6\u7535\u89C6\u7248-v576.apk";
var APK_URL_MOBILE = "https://videovideo.2000168.xyz/\u7B80\u5355\u5F71\u89C6\u79FB\u52A8\u7248-v576.apk";
var APP_CHANGELOG = "\u4F18\u5316\u65E5\u5E38bug";
var PROMO_IMAGE_URL = "";
var POSTER_URLS = [
"https://mdb.yuncongz.com/static/upload/raw/0005d5b734104313ba6c020636682002.jpg",
// 海报1 → 首屏海报墙(竖版 600×900px)
"https://mdb.yuncongz.com/static/upload/raw/7d0dd1a5ad904bfa8cf9016a55016ade.jpg",
// 海报2
"https://mdb.yuncongz.com/static/upload/raw/3e4253d8066d4eb1bbfb1515b7c9d50e.jpg",
// 海报3
"https://mdb.yuncongz.com/static/upload/raw/38dd2e7e96434268b7e005aa4a468370.jpg",
// 海报4
"https://mdb.yuncongz.com/static/upload/raw/baa5a5c38a9340358b1ac6ba8f35ddda.jpg",
// 海报5
"https://mdb.yuncongz.com/static/upload/raw/2729709f4f46490c94f181baa0403207.jpg",
// 海报6
"https://mdb.yuncongz.com/static/upload/raw/5aa3209bedf243ce871303502c2fe36f.jpg",
// 海报7
"https://mdb.yuncongz.com/static/upload/raw/9c6bb4c6c95a48f3b590f002b714df63.jpg"
// 海报8
];
var VIDEO_SRC_URL = "https://videovideo.2000168.xyz/tutorial.mp4";
var VIDEO_POSTER_URL = "https://videovideo.2000168.xyz/tutorial-poster.jpg";
var FAVICON_URL = "https://go.2000168.xyz/favicon.ico";
var SHARE_IMAGE_URL = "https://videovideo.2000168.xyz/og-cover.jpg";
// src/pay.js
async function generateSign(params, key) {
const sortedKeys = Object.keys(params).sort();
const tempArray = [];
for (const k of sortedKeys) {
const v = params[k];
if (k !== "sign" && k !== "sign_type" && v !== null && v !== void 0 && v !== "") {
tempArray.push(`${k}=${v}`);
}
}
const rawString = tempArray.join("&") + key;
return await md5Hex(rawString);
}
function getPayUrlFailReason(env) {
if (env.PAY_PAUSED === "true" || env.PAY_PAUSED === true) return "pay_paused";
if (!env.MOTION_PID || !env.MOTION_KEY) return "missing_config";
return null;
}
async function getDynamicPayQrCode(token, isTrial, origin, env, clientIP, isYear = false) {
if (env.PAY_PAUSED === "true" || env.PAY_PAUSED === true) {
console.warn("pay_url_fail reason=pay_paused");
return null;
}
const motionPid = env.MOTION_PID;
const motionKey = env.MOTION_KEY;
const motionGateway = env.MOTION_GATEWAY || "https://motionpay.net/submit.php";
if (!motionPid || !motionKey) {
console.warn("pay_url_fail reason=missing_config pid=" + (motionPid ? 1 : 0) + " key=" + (motionKey ? 1 : 0));
return null;
}
let finalPrice = isTrial ? regPriceCNY : priceCNY;
let finalName = isTrial ? "VIP-Trial" : "VIP-Monthly";
let finalDays = "30";
if (!isTrial && isYear) {
finalPrice = priceYearCNY;
finalName = "VIP-Yearly";
finalDays = "365";
}
const cacheKey = `pay_url_cache_${token}_${isYear ? "year" : "month"}_${finalPrice}`;
const cachedUrl = await env.USER_DB.get(cacheKey);
if (cachedUrl) return cachedUrl;
const shortId = Date.now().toString(36) + Math.random().toString(36).substr(2, 4);
const orderMapKey = `ord_${shortId}`;
await env.USER_DB.put(orderMapKey, JSON.stringify({ t: token, d: finalDays }), { expirationTtl: 604800 });
const dynamicOrderId = `V${shortId}`;
const payParams = {
pid: motionPid,
type: "wxpay",
out_trade_no: dynamicOrderId,
notify_url: `https://vip.8000168.xyz/api/pay-callback`,
return_url: `${origin}/pay/success?token=${token}`,
name: finalName,
money: finalPrice,
clientip: clientIP || "127.0.0.1",
device: "pc",
rawurl: "1"
};
const sign = await generateSign(payParams, motionKey);
payParams.sign = sign;
payParams.sign_type = "MD5";
let mapiGateway = motionGateway.trim();
if (mapiGateway.includes("submit.php")) {
mapiGateway = mapiGateway.replace("submit.php", "mapi.php");
} else if (!mapiGateway.includes("mapi.php")) {
mapiGateway = mapiGateway.endsWith("/") ? mapiGateway + "mapi.php" : mapiGateway + "/mapi.php";
}
try {
const queryStr = new URLSearchParams(payParams).toString();
const finalApiUrl = `${mapiGateway}?${queryStr}`;
const response = await fetch(finalApiUrl, {
method: "GET",
headers: { "Accept": "application/json" }
});
const res = await response.json();
if (res && (res.code === 1 || res.code === "1")) {
const payQr = res.qrcode || res.payurl || res.url;
if (payQr) {
await env.USER_DB.put(cacheKey, payQr, { expirationTtl: 300 });
return payQr;
}
} else {
console.warn("\u26A0\uFE0F [\u6613\u652F\u4ED8\u63A5\u53E3\u62A5\u9519\u660E\u7EC6]\uFF1A", JSON.stringify(res));
}
} catch (e) {
console.error("pay_url_fail reason=gateway_error exception:", e);
}
console.warn("pay_url_fail reason=gateway_error gateway=" + mapiGateway);
return null;
}
// src/user-db.js
async function getUserByDeviceId(env, deviceId) {
let row;
try {
row = await env.DB.prepare("SELECT * FROM users WHERE device_id = ?").bind(deviceId).first();
} catch (e) {
console.warn("D1 query failed:", e.message);
}
if (!row) {
const raw = await env.USER_DB.get(deviceId);
if (!raw) return null;
try {
row = JSON.parse(raw);
} catch (_) {
return null;
}
}
if (!row) return null;
const sdTime = getSelfDestructTime(row.expire_date, !!row.has_paid);
if (sdTime && sdTime < Date.now()) return null;
return {
invite_code: row.invite_code,
invite_count: row.invite_count,
invite_paid_count: row.invite_paid_count,
invite_earned_days: row.invite_earned_days,
referred_by: row.referred_by,
expire_date: row.expire_date,
is_blocked: !!row.is_blocked,
has_paid: !!row.has_paid,
disable_referral: !!row.disable_referral
};
}
async function getUserByInviteCode(env, inviteCode) {
const row = await env.DB.prepare("SELECT * FROM users WHERE invite_code = ?").bind(inviteCode).first();
if (!row) return null;
const sdTime = getSelfDestructTime(row.expire_date, !!row.has_paid);
if (sdTime && sdTime < Date.now()) return null;
return {
device_id: row.device_id,
invite_code: row.invite_code,
invite_count: row.invite_count,
invite_paid_count: row.invite_paid_count,
invite_earned_days: row.invite_earned_days,
referred_by: row.referred_by,
expire_date: row.expire_date,
is_blocked: !!row.is_blocked,
has_paid: !!row.has_paid,
disable_referral: !!row.disable_referral
};
}
async function upsertUser(env, deviceId, data) {
await env.DB.prepare(
"INSERT OR REPLACE INTO users (device_id, invite_code, invite_count, invite_paid_count, invite_earned_days, referred_by, expire_date, is_blocked, has_paid, disable_referral) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
).bind(
deviceId,
data.invite_code || "",
data.invite_count || 0,
data.invite_paid_count || 0,
data.invite_earned_days || 0,
data.referred_by || "",
data.expire_date || "trial",
data.is_blocked ? 1 : 0,
data.has_paid ? 1 : 0,
data.disable_referral ? 1 : 0
).run();
}
// src/referral.js
function applyReferralReward(referrerData, now) {
const todayStr = getBeijingDateStr(now);
if (!referrerData.invite_count_today_date || referrerData.invite_count_today_date !== todayStr) {
referrerData.invite_count_today_date = todayStr;
referrerData.invite_count_today = 0;
}
referrerData.invite_paid_count = (referrerData.invite_paid_count || 0) + 1;
if (referrerData.invite_count_today >= 2) {
referrerData.invite_count = (referrerData.invite_count || 0) + 1;
return { ok: false, limit: true };
}
referrerData.invite_count_today += 1;
let refExpire = referrerData.expire_date;
let refBaseTime = now;
if (refExpire && refExpire !== -1 && refExpire !== "-1" && refExpire !== "trial") {
const refExpireTime = Date.parse(refExpire.includes("T") ? refExpire : `${refExpire}T00:00:00+08:00`);
const finalRefExpireTime = refExpireTime ? refExpireTime + 24 * 60 * 60 * 1e3 - 1e3 : NaN;
if (!isNaN(finalRefExpireTime) && finalRefExpireTime > now) {
refBaseTime = finalRefExpireTime;
}
}
if (refExpire !== -1 && refExpire !== "-1") {
const refFinalExpireMs = refBaseTime + 30 * 24 * 60 * 60 * 1e3;
referrerData.expire_date = getBeijingDateStr(refFinalExpireMs);
}
referrerData.invite_count = (referrerData.invite_count || 0) + 1;
referrerData.invite_earned_days = (referrerData.invite_earned_days || 0) + 30;
return { ok: true };
}
function applyInviteeReward(userData, now) {
const exp = userData.expire_date;
if (exp === -1 || exp === "-1") return;
const newExpireMs = now + 30 * 24 * 60 * 60 * 1e3;
if (exp && exp !== "trial") {
const t = Date.parse(String(exp).includes("T") ? String(exp) : `${String(exp)}T00:00:00+08:00`);
const endMs = t ? t + 24 * 60 * 60 * 1e3 - 1e3 : NaN;
if (!isNaN(endMs) && endMs > newExpireMs) return;
}
userData.expire_date = getBeijingDateStr(newExpireMs);
}
// src/pages/bottom-nav.js
function getBottomNavHtml(activeTab, token) {
const tokenParam = token ? "?token=" + token : "";
return `