// ==UserScript==
// @name Team长链接
// @namespace local.long2.checkout
// @version 1.0.0
// @description 在 ChatGPT 页面中输入可修改参数,并提取官方返回的长链接。
// @author local
// @match https://chatgpt.com/*
// @match https://chat.openai.com/*
// @grant GM_setClipboard
// @run-at document-start
// @noframes
// ==/UserScript==
(function () {
"use strict";
const DEFAULTS = {
coupon: "", // 可修改
workspaceName: "workspace", // 可自行修改
country: "US", // 可修改
currency: "USD", // 可修改
cancelPromoCode: "", // 只修改 cancel_url 里 promoCode= 后面的值
};
const FIXED = {
planName: "chatgptteamplan",
priceInterval: "month",
seatQuantity: 2,
checkoutUiMode: "hosted",
};
const css = `
#long2-checkout-panel {
position: fixed;
right: 18px;
bottom: 18px;
z-index: 2147483647;
width: min(380px, calc(100vw - 28px));
color: #111827;
background: #ffffff;
border: 1px solid #d1d5db;
border-radius: 8px;
box-shadow: 0 18px 46px rgba(17, 24, 39, 0.18);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-size: 13px;
line-height: 1.4;
}
#long2-checkout-panel * {
box-sizing: border-box;
}
#long2-checkout-panel header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid #e5e7eb;
font-weight: 700;
}
#long2-checkout-panel .long2-body {
display: grid;
gap: 9px;
padding: 12px;
}
#long2-checkout-panel label {
display: grid;
gap: 4px;
color: #374151;
font-weight: 600;
}
#long2-checkout-panel input,
#long2-checkout-panel textarea {
width: 100%;
min-height: 34px;
color: #111827;
background: #ffffff;
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 7px 8px;
font: inherit;
outline: none;
}
#long2-checkout-panel textarea {
min-height: 88px;
resize: vertical;
word-break: break-all;
}
#long2-checkout-panel .long2-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
#long2-checkout-panel .long2-hint {
margin-top: -2px;
color: #6b7280;
font-size: 12px;
font-weight: 500;
}
#long2-checkout-panel .long2-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
#long2-checkout-panel button,
#long2-checkout-launch {
min-height: 34px;
border: 1px solid #9ca3af;
border-radius: 6px;
padding: 7px 10px;
color: #111827;
background: #f9fafb;
font: inherit;
font-weight: 650;
cursor: pointer;
}
#long2-checkout-panel button:hover,
#long2-checkout-launch:hover {
background: #f3f4f6;
}
#long2-checkout-panel .long2-primary,
#long2-checkout-launch {
color: #ffffff;
background: #2563eb;
border-color: #2563eb;
}
#long2-checkout-panel .long2-primary:hover,
#long2-checkout-launch:hover {
background: #1d4ed8;
}
#long2-checkout-panel .long2-close {
width: 28px;
min-height: 28px;
padding: 0;
border-color: transparent;
background: transparent;
font-size: 18px;
line-height: 1;
}
#long2-checkout-panel .long2-status {
min-height: 18px;
color: #4b5563;
overflow-wrap: anywhere;
}
#long2-checkout-panel .long2-status.is-error {
color: #b91c1c;
}
#long2-checkout-panel .long2-status.is-ok {
color: #047857;
}
#long2-checkout-launch {
position: fixed;
right: 18px;
bottom: 18px;
z-index: 2147483646;
min-height: 38px;
border-radius: 8px;
box-shadow: 0 12px 30px rgba(37, 99, 235, 0.25);
font: 650 13px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
`;
let panel;
let launcher;
function addCss() {
const style = document.createElement("style");
style.textContent = css;
document.head.appendChild(style);
}
function getInput(id) {
return panel.querySelector(`#${id}`).value.trim();
}
function setStatus(message, state) {
const status = panel.querySelector("#long2-status");
status.textContent = message;
status.className = `long2-status${state ? ` is-${state}` : ""}`;
}
function buildCancelUrl() {
const cancelPromoCode = getInput("long2-cancel-promo") || DEFAULTS.cancelPromoCode;
return `https://chatgpt.com/?promoCode=${encodeURIComponent(cancelPromoCode)}`;
}
function buildPayload() {
const coupon = getInput("long2-coupon") || DEFAULTS.coupon;
return {
plan_name: FIXED.planName,
team_plan_data: {
workspace_name: getInput("long2-workspace") || DEFAULTS.workspaceName,
price_interval: FIXED.priceInterval,
seat_quantity: FIXED.seatQuantity,
},
billing_details: {
country: (getInput("long2-country") || DEFAULTS.country).toUpperCase(),
currency: (getInput("long2-currency") || DEFAULTS.currency).toUpperCase(),
},
cancel_url: buildCancelUrl(),
promo_code: coupon,
checkout_ui_mode: FIXED.checkoutUiMode,
};
}
async function getAccessToken() {
const response = await fetch("/api/auth/session", {
credentials: "include",
});
if (!response.ok) {
throw new Error(`获取 Token 失败:HTTP ${response.status}`);
}
const session = await response.json();
if (!session?.accessToken) {
throw new Error("accessToken 为空,请确认当前页面已经登录。");
}
return session.accessToken;
}
async function generateLink() {
const button = panel.querySelector("#long2-generate");
const output = panel.querySelector("#long2-output");
button.disabled = true;
output.value = "";
setStatus("正在获取 Session Token...", "");
try {
const accessToken = await getAccessToken();
const payload = buildPayload();
setStatus("正在请求 长链接...", "");
const response = await fetch("https://chatgpt.com/backend-api/payments/checkout", {
method: "POST",
credentials: "include",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const data = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(`请求失败 HTTP ${response.status}:${JSON.stringify(data)}`);
}
const hostedUrl = data?.url || data?.stripe_hosted_url || data?.checkout_url;
if (!hostedUrl) {
throw new Error(`未找到长链接,原始响应:${JSON.stringify(data)}`);
}
output.value = hostedUrl;
setStatus("ChatGPT Team 链接生成成功。", "ok");
} catch (error) {
setStatus(error.message || String(error), "error");
console.error("[long2 checkout]", error);
} finally {
button.disabled = false;
}
}
async function copyLink() {
const output = panel.querySelector("#long2-output");
if (!output.value) {
setStatus("当前没有可复制的长链接。", "error");
return;
}
if (typeof GM_setClipboard === "function") {
GM_setClipboard(output.value, "text");
} else {
await navigator.clipboard.writeText(output.value);
}
setStatus("长链接已复制。", "ok");
}
function createPanel() {
panel = document.createElement("section");
panel.id = "long2-checkout-panel";
panel.innerHTML = `