






















<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MIMO API Key Extractor</title>
<style>
:root {
--system-blue: #007AFF;
--system-blue-hover: #0062cc;
--system-gray: #8E8E93;
--system-gray-6: #F2F2F7;
--system-background: #F5F5F7;
--card-background: rgba(255, 255, 255, 0.85);
--glass-border: rgba(255, 255, 255, 0.6);
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04);
--shadow-md: 0 12px 24px rgba(0, 0, 0, 0.08);
--radius-lg: 20px;
--radius-md: 12px;
--font-primary: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
--font-mono: "SF Mono", "Menlo", "Monaco", "Courier New", monospace;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: var(--font-primary);
background-color: var(--system-background);
background-image:
radial-gradient(at 80% 0%, hsla(189,100%,56%,0.1) 0px, transparent 50%),
radial-gradient(at 0% 50%, hsla(355,100%,93%,0.3) 0px, transparent 50%),
radial-gradient(at 80% 50%, hsla(240,100%,70%,0.05) 0px, transparent 50%);
color: #1d1d1f;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
}
.main-container {
width: 100%;
max-width: 860px;
background: var(--card-background);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
overflow: hidden;
animation: fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.header {
padding: 40px 40px 20px;
text-align: center;
}
.header h1 {
font-size: 32px;
font-weight: 700;
letter-spacing: -0.5px;
margin-bottom: 8px;
background: linear-gradient(135deg, #1d1d1f 0%, #434344 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header p {
color: var(--system-gray);
font-size: 15px;
font-weight: 400;
}
.content {
padding: 20px 40px 40px;
}
.input-wrapper {
position: relative;
margin-bottom: 24px;
}
textarea {
width: 100%;
min-height: 180px;
padding: 20px;
border: none;
border-radius: var(--radius-md);
background: var(--system-gray-6);
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.6;
color: #1d1d1f;
resize: vertical;
transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
box-shadow: inset 0 1px 4px rgba(0,0,0,0.02);
}
textarea::placeholder {
color: #aeaeb2;
font-family: var(--font-primary);
}
textarea:focus {
outline: none;
background: #fff;
box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.15);
}
.action-bar {
display: flex;
gap: 16px;
margin-bottom: 32px;
}
button {
border: none;
padding: 14px 28px;
border-radius: 980px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
button:active {
transform: scale(0.96);
}
.btn-primary {
background: var(--system-blue);
color: white;
flex: 2;
box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
}
.btn-primary:hover {
background: var(--system-blue-hover);
box-shadow: 0 6px 16px rgba(0, 122, 255, 0.4);
}
.btn-secondary {
background: rgba(0, 0, 0, 0.05);
color: #1d1d1f;
flex: 1;
}
.btn-secondary:hover {
background: rgba(0, 0, 0, 0.1);
}
.result-panel {
border-top: 1px solid rgba(0,0,0,0.06);
padding-top: 30px;
display: none;
animation: slideDown 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.result-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.result-title {
font-size: 17px;
font-weight: 600;
color: #1d1d1f;
}
.badges {
display: flex;
gap: 8px;
}
.badge {
padding: 4px 10px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.3px;
}
.badge-count {
background: rgba(0, 122, 255, 0.1);
color: var(--system-blue);
}
.badge-check {
background: rgba(52, 199, 89, 0.1);
color: #34C759;
}
.key-list {
max-height: 360px;
overflow-y: auto;
background: #fff;
border-radius: var(--radius-md);
border: 1px solid rgba(0,0,0,0.04);
box-shadow: 0 4px 12px rgba(0,0,0,0.02);
}
.key-list::-webkit-scrollbar {
width: 8px;
}
.key-list::-webkit-scrollbar-track {
background: transparent;
}
.key-list::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,0.1);
border-radius: 4px;
}
.key-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid rgba(0,0,0,0.04);
transition: background 0.2s;
}
.key-item:last-child {
border-bottom: none;
}
.key-item:hover {
background: #f9f9fa;
}
.key-text {
font-family: var(--font-mono);
font-size: 13px;
color: #333;
word-break: break-all;
margin-right: 16px;
}
.btn-copy-small {
padding: 6px 12px;
font-size: 12px;
border-radius: 6px;
background: transparent;
color: var(--system-blue);
border: 1px solid rgba(0, 122, 255, 0.2);
flex-shrink: 0;
}
.btn-copy-small:hover {
background: rgba(0, 122, 255, 0.05);
}
.btn-copy-small.copied {
background: #34C759;
border-color: transparent;
color: white;
}
.export-actions {
margin-top: 24px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.btn-export {
background: white;
border: 1px solid rgba(0,0,0,0.08);
color: #1d1d1f;
box-shadow: 0 2px 6px rgba(0,0,0,0.02);
}
.btn-export:hover {
border-color: rgba(0,0,0,0.15);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
/* Toast 浮层 */
.toast-container {
position: fixed;
top: 24px;
left: 50%;
transform: translateX(-50%);
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
pointer-events: none;
}
.toast {
padding: 12px 24px;
border-radius: 980px;
font-size: 14px;
font-weight: 500;
color: #fff;
background: rgba(30, 30, 30, 0.9);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
animation: toastIn 0.35s cubic-bezier(0.16, 1, 0.3, 1), toastOut 0.3s cubic-bezier(0.16, 1, 0.3, 1) 1.8s forwards;
pointer-events: auto;
}
.toast.success {
background: rgba(52, 199, 89, 0.95);
}
.toast.error {
background: rgba(255, 59, 48, 0.95);
}
@keyframes toastIn {
from { opacity: 0; transform: translateY(-12px) scale(0.92); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes toastOut {
from { opacity: 1; transform: translateY(0) scale(1); }
to { opacity: 0; transform: translateY(-12px) scale(0.92); }
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.98); }
to { opacity: 1; transform: scale(1); }
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 600px) {
body { padding: 20px 10px; }
.header { padding: 30px 20px 10px; }
.content { padding: 20px; }
.action-bar { flex-direction: column; }
.export-actions { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<!-- Toast 容器 -->
<div class="toast-container" id="toastContainer"></div>
<div class="main-container">
<div class="header">
<h1>API Key Extraction</h1>
<p>Professional MIMO Code Key Processor</p>
</div>
<div class="content">
<div class="input-wrapper">
<textarea id="inputText" placeholder="请在此粘贴包含 MIMO API 密钥的文本内容..."></textarea>
</div>
<div class="action-bar">
<button class="btn-primary" id="btnExtract">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
智能提取
</button>
<button class="btn-secondary" id="btnClear">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
清空
</button>
</div>
<div id="resultSection" class="result-panel">
<div class="result-header">
<span class="result-title">提取结果</span>
<div class="badges">
<span class="badge badge-count" id="countBadge">0 items</span>
<span class="badge badge-check">Length: 51 chars</span>
</div>
</div>
<div class="key-list" id="resultList"></div>
<div class="export-actions">
<button class="btn-export" id="btnCopyNewline">
📋 复制全部 (换行分隔)
</button>
<button class="btn-export" id="btnCopyComma">
📑 复制全部 (逗号分隔)
</button>
</div>
</div>
</div>
</div>
<script>
(function() {
'use strict';
var extractedKeys = [];
// DOM 元素引用
var inputText = document.getElementById('inputText');
var resultSection = document.getElementById('resultSection');
var resultList = document.getElementById('resultList');
var countBadge = document.getElementById('countBadge');
var btnExtract = document.getElementById('btnExtract');
var btnClear = document.getElementById('btnClear');
var btnCopyNewline = document.getElementById('btnCopyNewline');
var btnCopyComma = document.getElementById('btnCopyComma');
var toastContainer = document.getElementById('toastContainer');
// ========== 事件绑定 ==========
btnExtract.addEventListener('click', extractKeys);
btnClear.addEventListener('click', clearAll);
// 键盘快捷键:Ctrl+Enter / Cmd+Enter 触发提取
inputText.addEventListener('keydown', function(e) {
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
e.preventDefault();
extractKeys();
}
});
// 批量复制按钮 —— 同步执行,保持用户手势
btnCopyNewline.addEventListener('click', function() {
copyAllKeys('newline');
});
btnCopyComma.addEventListener('click', function() {
copyAllKeys('comma');
});
// 结果列表点击事件委托(处理每条密钥的复制按钮)
resultList.addEventListener('click', function(e) {
var btn = e.target.closest('.btn-copy-small');
if (!btn) return;
var key = btn.getAttribute('data-key');
if (key) {
copyKey(key, btn);
}
});
// ========== 核心函数 ==========
function extractKeys() {
var text = inputText.value;
if (!text.trim()) {
shakeElement(inputText);
return;
}
// tp- 开头 + 恰好48位字母数字(大小写混合)
var regex = /tp-[a-zA-Z0-9]{48}\b/g;
var keys = text.match(regex);
if (keys && keys.length > 0) {
// 去重
extractedKeys = [];
var seen = {};
for (var i = 0; i < keys.length; i++) {
if (!seen[keys[i]]) {
seen[keys[i]] = true;
if (keys[i].length === 51) {
extractedKeys.push(keys[i]);
}
}
}
if (extractedKeys.length > 0) {
displayResults();
} else {
showToast('未找到符合标准长度(51字符)的密钥', 'error');
hideResults();
}
} else {
showToast('未检测到有效的 tp- 格式密钥', 'error');
hideResults();
}
}
function displayResults() {
resultSection.style.display = 'block';
countBadge.textContent = extractedKeys.length + ' 个密钥';
resultList.innerHTML = '';
for (var i = 0; i < extractedKeys.length; i++) {
(function(key, index) {
var keyItem = document.createElement('div');
keyItem.className = 'key-item';
keyItem.style.animation = 'fadeIn 0.3s ease backwards ' + (index * 0.05) + 's';
var keySpan = document.createElement('span');
keySpan.className = 'key-text';
keySpan.textContent = key;
var copyBtn = document.createElement('button');
copyBtn.className = 'btn-copy-small';
copyBtn.textContent = '复制';
copyBtn.setAttribute('data-key', key);
keyItem.appendChild(keySpan);
keyItem.appendChild(copyBtn);
resultList.appendChild(keyItem);
})(extractedKeys[i], i);
}
resultSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
function hideResults() {
resultSection.style.display = 'none';
}
function copyKey(key, btnElement) {
var ok = copyToClipboard(key);
if (ok) {
var originalText = btnElement.textContent;
btnElement.textContent = '已复制';
btnElement.classList.add('copied');
setTimeout(function() {
btnElement.textContent = originalText;
btnElement.classList.remove('copied');
}, 1500);
} else {
showToast('复制失败,请手动复制', 'error');
}
}
function copyAllKeys(format) {
if (extractedKeys.length === 0) return;
var content;
if (format === 'newline') {
content = extractedKeys.join('\n');
} else {
content = extractedKeys.join(',');
}
var ok = copyToClipboard(content);
if (ok) {
showToast('✅ 已复制 ' + extractedKeys.length + ' 个密钥', 'success');
} else {
showToast('复制失败,请手动复制', 'error');
}
}
// ========== 剪贴板复制(纯同步,保留用户手势) ==========
function copyToClipboard(text) {
// 方法1:navigator.clipboard(仅 HTTPS / localhost 可用)
if (navigator.clipboard && navigator.clipboard.writeText && window.isSecureContext) {
// 注意:这里仍然是异步的,但因为是 click handler 直接调用,
// 用户手势上下文还在,所以 writeText 能正常工作
navigator.clipboard.writeText(text).then(function() {
// 成功,什么都不用做(调用方已经显示了 toast)
}).catch(function() {
// 静默失败,走降级
fallbackCopy(text);
});
return true;
}
// 方法2:execCommand 降级(同步,兼容 HTTP)
return fallbackCopy(text);
}
function fallbackCopy(text) {
try {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
textarea.style.opacity = '0';
textarea.style.pointerEvents = 'none';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
var success = document.execCommand('copy');
document.body.removeChild(textarea);
return success;
} catch (err) {
return false;
}
}
function clearAll() {
inputText.value = '';
inputText.focus();
if (resultSection.style.display === 'block') {
resultSection.style.opacity = '0';
setTimeout(function() {
resultSection.style.display = 'none';
resultSection.style.opacity = '1';
extractedKeys = [];
}, 300);
} else {
extractedKeys = [];
}
}
// ========== 辅助函数 ==========
function shakeElement(el) {
el.style.transform = 'translateX(4px)';
setTimeout(function() { el.style.transform = 'translateX(-4px)'; }, 50);
setTimeout(function() { el.style.transform = 'translateX(0)'; }, 100);
}
function showToast(message, type) {
type = type || 'info';
var toast = document.createElement('div');
toast.className = 'toast ' + type;
toast.textContent = message;
toastContainer.appendChild(toast);
setTimeout(function() {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 2200);
}
})();
</script>
</body>
</html>
[!提示]
巧用L站搜索框
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。