[JavaScript] 纯文本查看 复制代码
// ==UserScript==
// @name 腾讯会议转写纪要导出神器 (Tencent Meeting Transcript Exporter) 修复版
// @namespace https://github.com/awesome-tampermonkey
// @version 1.1.2
// @description 一键导出腾讯会议录制视频和纯文字转写的内容和纪要,支持Markdown、HTML、TXT格式导出和复制
// @author 东哥说AI
// @match https://meeting.tencent.com/cw/*
// @match https://meeting.tencent.com/ct/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const CONFIG = {
BUTTON_STYLE: `
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
padding: 12px 20px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
`,
MODAL_STYLE: `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 10001;
display: flex;
justify-content: center;
align-items: center;
`,
MODAL_CONTENT_STYLE: `
background: white;
border-radius: 12px;
padding: 30px;
max-width: 500px;
width: 90%;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
`
};
const utils = {
getPageType() {
const url = window.location.href;
if (url.includes('/cw/')) return 'recording';
if (url.includes('/ct/')) return 'transcript';
return 'unknown';
},
getMeetingTitle() {
// 尝试多种方式获取会议标题
const selectors = [
'.meeting-main-subject .subject',
'.meeting-subject',
'.meeting-title',
'.style_header-info__6mQkP', // 新增选择器
'h1', // 通用标题
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) {
const text = el.textContent.trim();
// 如果只获取到部分内容(比如"返回"等),继续查找
if (text && text.length > 3 && !text.startsWith('返回')) {
return text;
}
}
}
// 如果以上都失败,从URL或其他地方获取
const pageTitle = document.title;
if (pageTitle && pageTitle !== '腾讯会议') {
return pageTitle;
}
return '腾讯会议转写';
},
getRecordingTime() {
// 尝试从页面中提取录制时间
const selectors = [
'.meeting-begin-time-in-date',
'.meeting-time',
'[class*="time"]',
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) {
const text = el.textContent.trim();
// 匹配时间格式
if (/\d{4}[\/\-]\d{2}[\/\-]\d{2}/.test(text)) {
return text.match(/\d{4}[\/\-]\d{2}[\/\-]\d{2}[\s\d\:]*/)[0];
}
}
}
return new Date().toLocaleString('zh-CN');
},
getMeetingKeywords() {
const keywords = [];
const topicElements = document.querySelectorAll('.topicTag .topicText');
topicElements.forEach(element => {
const keyword = element.textContent.trim();
if (keyword) {
keywords.push(keyword);
}
});
return keywords;
},
getCurrentTabType() {
const pageType = this.getPageType();
if (pageType === 'transcript') return 'both';
const activeTab = document.querySelector('.met-tabs__tabitem.is-active .tab');
if (!activeTab) return 'transcript';
const tabText = activeTab.textContent.trim();
if (tabText.includes('纪要')) return 'summary';
return 'transcript';
},
// 修复后的转写内容获取方法
async getTranscriptContent() {
const pageType = this.getPageType();
// 查找虚拟滚动容器
const scrollContainer = document.querySelector('.minutes-module-list');
if (!scrollContainer) {
return this.getTranscriptContentFallback();
}
// 检查是否需要滚动
if (scrollContainer.scrollHeight <= scrollContainer.clientHeight + 100) {
return this.getTranscriptContentFallback();
}
const originalScrollTop = scrollContainer.scrollTop;
let allContent = new Map();
let lastScrollTop = -1;
let stuckCounter = 0;
try {
// 先滚动到顶部
scrollContainer.scrollTop = 0;
await this.sleep(300);
// 持续滚动直到底部
while (scrollContainer.scrollTop !== lastScrollTop && stuckCounter < 3) {
lastScrollTop = scrollContainer.scrollTop;
// 收集当前可见的内容
const paragraphs = document.querySelectorAll('.paragraph-module_detail-page-style__Lhz8l');
paragraphs.forEach(para => {
const pid = para.getAttribute('data-pid');
if (!pid || allContent.has(pid)) return;
const speakerElement = para.querySelector('.paragraph-module_speaker-name__afSbd');
const timeElement = para.querySelector('.paragraph-module_p-start-time__QAWWl');
const textElement = para.querySelector('.paragraph-module_sentences__zK2oL');
if (textElement && textElement.textContent.trim()) {
allContent.set(pid, {
pid: parseInt(pid),
time: timeElement ? timeElement.textContent.trim() : '',
speaker: speakerElement ? speakerElement.textContent.trim() : '未知发言人',
text: textElement.textContent.trim()
});
}
});
// 向下滚动
const newScrollTop = scrollContainer.scrollTop + scrollContainer.clientHeight * 0.8;
scrollContainer.scrollTop = newScrollTop;
// 等待渲染
await this.sleep(150);
// 检查是否卡住
if (scrollContainer.scrollTop === lastScrollTop) {
stuckCounter++;
// 尝试多滚动一点
scrollContainer.scrollTop += 50;
await this.sleep(100);
} else {
stuckCounter = 0;
}
}
// 恢复原始滚动位置
scrollContainer.scrollTop = originalScrollTop;
// 按pid排序
return Array.from(allContent.values()).sort((a, b) => a.pid - b.pid);
} catch (error) {
console.error('获取转写内容失败:', error);
scrollContainer.scrollTop = originalScrollTop;
return this.getTranscriptContentFallback();
}
},
getTranscriptContentFallback() {
const paragraphs = document.querySelectorAll('.paragraph-module_detail-page-style__Lhz8l');
let content = [];
paragraphs.forEach(para => {
const speakerElement = para.querySelector('.paragraph-module_speaker-name__afSbd');
const timeElement = para.querySelector('.paragraph-module_p-start-time__QAWWl');
const textElement = para.querySelector('.paragraph-module_sentences__zK2oL');
if (textElement && textElement.textContent.trim()) {
content.push({
time: timeElement ? timeElement.textContent.trim() : '',
speaker: speakerElement ? speakerElement.textContent.trim() : '未知发言人',
text: textElement.textContent.trim()
});
}
});
return content;
},
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},
getSummaryContent() {
const pageType = this.getPageType();
if (pageType === 'transcript') {
const summaryContainer = document.querySelector('.aisummary-container .summary-content-wrap');
if (!summaryContainer) return null;
const elements = summaryContainer.querySelectorAll('h4, p, li');
return Array.from(elements).map(el => ({
type: el.tagName.toLowerCase(),
text: el.textContent.trim()
})).filter(item => item.text);
}
const summaryContainer = document.querySelector('.summary-content-wrap');
if (!summaryContainer) return null;
const elements = summaryContainer.querySelectorAll('h4, p, li, div[contenteditable="true"]');
return Array.from(elements).map(el => ({
type: el.tagName.toLowerCase(),
text: el.textContent.trim()
})).filter(item => item.text);
},
formatAsMarkdown(data, type) {
const title = this.getMeetingTitle();
const recordingTime = this.getRecordingTime();
const keywords = this.getMeetingKeywords();
const exportTime = new Date().toLocaleString('zh-CN');
let markdown = `# ${title}\n\n`;
markdown += `**录制时间**: ${recordingTime}\n`;
markdown += `**导出时间**: ${exportTime}\n`;
markdown += `**内容类型**: ${type === 'transcript' ? '转写内容' : '会议纪要'}\n`;
if (keywords.length > 0) {
markdown += `**会议关键词**: ${keywords.join('、')}\n`;
}
markdown += `\n---\n\n`;
if (type === 'transcript' && Array.isArray(data)) {
markdown += `## 转写内容\n\n`;
data.forEach(item => {
markdown += `### ${item.speaker}${item.time ? ` (${item.time})` : ''}\n\n`;
markdown += `${item.text}\n\n---\n\n`;
});
} else if (type === 'summary' && Array.isArray(data)) {
markdown += `## 会议纪要\n\n`;
data.forEach(item => {
if (item.type === 'h4') {
markdown += `### ${item.text}\n\n`;
} else if (item.type === 'li') {
markdown += `- ${item.text}\n`;
} else {
markdown += `${item.text}\n\n`;
}
});
}
return markdown;
},
formatAsHTML(data, type) {
const title = this.getMeetingTitle();
const recordingTime = this.getRecordingTime();
const keywords = this.getMeetingKeywords();
const exportTime = new Date().toLocaleString('zh-CN');
let html = `<!DOCTYPE html>\n<html lang="zh-CN">\n<head>\n`;
html += ` <meta charset="UTF-8">\n`;
html += ` <meta name="viewport" content="width=device-width, initial-scale=1.0">\n`;
html += ` <title>${title}</title>\n`;
html += ` <style>\n`;
html += ` body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; max-width: 800px; margin: 0 auto; padding: 20px; }\n`;
html += ` .header { border-bottom: 2px solid #eee; padding-bottom: 20px; margin-bottom: 30px; }\n`;
html += ` .transcript-item { margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px; }\n`;
html += ` .speaker { font-weight: bold; color: #2c3e50; }\n`;
html += ` .time { color: #7f8c8d; font-size: 0.9em; }\n`;
html += ` .content { margin-top: 8px; }\n`;
html += ` .keywords { margin: 10px 0; }\n`;
html += ` .keyword-tag { display: inline-block; background: #e3f2fd; color: #1976d2; padding: 4px 8px; margin: 2px; border-radius: 4px; font-size: 0.9em; }\n`;
html += ` </style>\n</head>\n<body>\n`;
html += ` <div class="header">\n`;
html += ` <h1>${title}</h1>\n`;
html += ` <p><strong>录制时间</strong>: ${recordingTime}</p>\n`;
html += ` <p><strong>导出时间</strong>: ${exportTime}</p>\n`;
html += ` <p><strong>内容类型</strong>: ${type === 'transcript' ? '转写内容' : '会议纪要'}</p>\n`;
if (keywords.length > 0) {
html += ` <div class="keywords">\n`;
html += ` <strong>会议关键词</strong>: `;
keywords.forEach(keyword => {
html += `<span class="keyword-tag">${keyword}</span>`;
});
html += `\n </div>\n`;
}
html += ` </div>\n`;
if (type === 'transcript' && Array.isArray(data)) {
html += ` <h2>转写内容</h2>\n`;
data.forEach(item => {
html += ` <div class="transcript-item">\n`;
html += ` <div class="speaker">${item.speaker}${item.time ? ` <span class="time">(${item.time})</span>` : ''}</div>\n`;
html += ` <div class="content">${item.text}</div>\n`;
html += ` </div>\n`;
});
} else if (type === 'summary' && Array.isArray(data)) {
html += ` <h2>会议纪要</h2>\n`;
data.forEach(item => {
if (item.type === 'h4') {
html += ` <h3>${item.text}</h3>\n`;
} else if (item.type === 'li') {
html += ` <li>${item.text}</li>\n`;
} else {
html += ` <p>${item.text}</p>\n`;
}
});
}
html += `</body>\n</html>`;
return html;
},
formatAsTXT(data, type) {
const title = this.getMeetingTitle();
const recordingTime = this.getRecordingTime();
const keywords = this.getMeetingKeywords();
const exportTime = new Date().toLocaleString('zh-CN');
let txt = `${title}\n`;
txt += `${'='.repeat(Math.min(title.length, 50))}\n\n`;
txt += `录制时间: ${recordingTime}\n`;
txt += `导出时间: ${exportTime}\n`;
txt += `内容类型: ${type === 'transcript' ? '转写内容' : '会议纪要'}\n`;
if (keywords.length > 0) {
txt += `会议关键词: ${keywords.join('、')}\n`;
}
txt += `\n`;
if (type === 'transcript' && Array.isArray(data)) {
txt += `转写内容\n${'-'.repeat(10)}\n\n`;
data.forEach(item => {
txt += `${item.speaker}${item.time ? ` (${item.time})` : ''}\n`;
txt += `${item.text}\n\n`;
});
} else if (type === 'summary' && Array.isArray(data)) {
txt += `会议纪要\n${'-'.repeat(10)}\n\n`;
data.forEach(item => {
if (item.type === 'h4') {
txt += `\n${item.text}\n${'-'.repeat(Math.min(item.text.length, 30))}\n`;
} else if (item.type === 'li') {
txt += `• ${item.text}\n`;
} else {
txt += `${item.text}\n\n`;
}
});
}
return txt;
},
downloadFile(content, filename, type) {
const mimeTypes = {
'md': 'text/markdown',
'html': 'text/html',
'txt': 'text/plain'
};
const blob = new Blob(['\ufeff' + content], { type: mimeTypes[type] || 'text/plain' }); // 添加BOM解决中文乱码
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
},
async copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (err) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.select();
const success = document.execCommand('copy');
document.body.removeChild(textArea);
return success;
}
},
showMessage(message, type = 'success') {
const existingMsg = document.querySelector('.tm-exporter-message');
if (existingMsg) existingMsg.remove();
const messageDiv = document.createElement('div');
messageDiv.className = 'tm-exporter-message';
const colors = {
'success': '#10b981',
'error': '#ef4444',
'info': '#3b82f6',
'warning': '#f59e0b'
};
messageDiv.style.cssText = `
position: fixed;
top: 80px;
right: 20px;
z-index: 10002;
padding: 12px 20px;
border-radius: 6px;
color: white;
font-weight: 600;
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
background: ${colors[type] || colors.success};
max-width: 400px;
word-wrap: break-word;
`;
messageDiv.textContent = message;
document.body.appendChild(messageDiv);
setTimeout(() => {
messageDiv.style.opacity = '0';
messageDiv.style.transform = 'translateX(100%)';
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.parentNode.removeChild(messageDiv);
}
}, 300);
}, 3000);
}
};
class TencentMeetingExporter {
constructor() {
this.init();
}
init() {
this.createExportButton();
}
createExportButton() {
// 移除已存在的按钮
const existingBtn = document.querySelector('.tm-exporter-btn');
if (existingBtn) existingBtn.remove();
const button = document.createElement('button');
button.className = 'tm-exporter-btn';
button.textContent = '📝 导出转写/纪要';
button.style.cssText = CONFIG.BUTTON_STYLE;
button.addEventListener('mouseenter', () => {
button.style.transform = 'translateY(-2px)';
button.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = 'translateY(0)';
button.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
});
button.addEventListener('click', () => {
this.showExportModal();
});
document.body.appendChild(button);
}
showExportModal() {
const currentTab = utils.getCurrentTabType();
let modalHTML;
if (currentTab === 'both') {
modalHTML = `
<h2 style="margin: 0 0 20px 0; color: #2c3e50; font-size: 24px;">导出转写/纪要</h2>
<p style="margin: 0 0 25px 0; color: #7f8c8d; line-height: 1.5;">选择要导出的内容类型和格式</p>
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-bottom: 25px;">
<button id="export-transcript-md" style="padding: 15px; border: 2px solid #3498db; background: white; color: #3498db; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📄 导出转写(MD)</button>
<button id="export-summary-md" style="padding: 15px; border: 2px solid #e74c3c; background: white; color: #e74c3c; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📋 导出纪要(MD)</button>
<button id="export-transcript-html" style="padding: 15px; border: 2px solid #f39c12; background: white; color: #f39c12; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">🌐 导出转写(HTML)</button>
<button id="export-summary-html" style="padding: 15px; border: 2px solid #9b59b6; background: white; color: #9b59b6; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">🌐 导出纪要(HTML)</button>
<button id="export-transcript-txt" style="padding: 15px; border: 2px solid #16a085; background: white; color: #16a085; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📝 导出转写(TXT)</button>
<button id="copy-transcript-md" style="padding: 15px; border: 2px solid #8e44ad; background: white; color: #8e44ad; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📋 复制转写(MD)</button>
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px;">
<button id="modal-close" style="padding: 10px 20px; border: 1px solid #bdc3c7; background: white; color: #7f8c8d; border-radius: 6px; cursor: pointer;">取消</button>
</div>
`;
} else {
const tabName = currentTab === 'transcript' ? '转写内容' : '会议纪要';
modalHTML = `
<h2 style="margin: 0 0 20px 0; color: #2c3e50; font-size: 24px;">导出${tabName}</h2>
<p style="margin: 0 0 25px 0; color: #7f8c8d; line-height: 1.5;">选择导出格式,文件名将自动使用会议标题</p>
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-bottom: 25px;">
<button id="export-md" style="padding: 15px; border: 2px solid #3498db; background: white; color: #3498db; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📄 Markdown</button>
<button id="export-html" style="padding: 15px; border: 2px solid #e74c3c; background: white; color: #e74c3c; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">🌐 HTML</button>
<button id="export-txt" style="padding: 15px; border: 2px solid #f39c12; background: white; color: #f39c12; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📝 TXT</button>
<button id="copy-md" style="padding: 15px; border: 2px solid #9b59b6; background: white; color: #9b59b6; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease;">📋 复制Markdown</button>
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px;">
<button id="modal-close" style="padding: 10px 20px; border: 1px solid #bdc3c7; background: white; color: #7f8c8d; border-radius: 6px; cursor: pointer;">取消</button>
</div>
`;
}
const modal = document.createElement('div');
modal.style.cssText = CONFIG.MODAL_STYLE;
const modalContent = document.createElement('div');
modalContent.style.cssText = CONFIG.MODAL_CONTENT_STYLE;
modalContent.innerHTML = modalHTML;
// 添加按钮悬停效果
const buttons = modalContent.querySelectorAll('button[id^="export-"], button[id^="copy-"]');
buttons.forEach(btn => {
btn.addEventListener('mouseenter', () => {
btn.style.background = btn.style.color;
btn.style.color = 'white';
});
btn.addEventListener('mouseleave', () => {
btn.style.background = 'white';
btn.style.color = btn.style.borderColor;
});
});
// 绑定事件
if (currentTab === 'both') {
modalContent.querySelector('#export-transcript-md')?.addEventListener('click', () => this.exportContent('md', 'transcript'));
modalContent.querySelector('#export-summary-md')?.addEventListener('click', () => this.exportContent('md', 'summary'));
modalContent.querySelector('#export-transcript-html')?.addEventListener('click', () => this.exportContent('html', 'transcript'));
modalContent.querySelector('#export-summary-html')?.addEventListener('click', () => this.exportContent('html', 'summary'));
modalContent.querySelector('#export-transcript-txt')?.addEventListener('click', () => this.exportContent('txt', 'transcript'));
modalContent.querySelector('#copy-transcript-md')?.addEventListener('click', () => this.copyContent('transcript'));
} else {
modalContent.querySelector('#export-md')?.addEventListener('click', () => this.exportContent('md'));
modalContent.querySelector('#export-html')?.addEventListener('click', () => this.exportContent('html'));
modalContent.querySelector('#export-txt')?.addEventListener('click', () => this.exportContent('txt'));
modalContent.querySelector('#copy-md')?.addEventListener('click', () => this.copyContent());
}
modalContent.querySelector('#modal-close').addEventListener('click', () => this.closeModal(modal));
modal.addEventListener('click', (e) => {
if (e.target === modal) {
this.closeModal(modal);
}
});
modal.appendChild(modalContent);
document.body.appendChild(modal);
}
async exportContent(format, contentType = null) {
try {
const currentTab = utils.getCurrentTabType();
const exportType = contentType || (currentTab === 'both' ? 'transcript' : currentTab);
let data;
if (exportType === 'transcript') {
utils.showMessage('正在获取转写内容,请稍候...', 'info');
data = await utils.getTranscriptContent();
if (!data || data.length === 0) {
utils.showMessage('未找到转写内容,请确保页面已加载完成', 'error');
return;
}
utils.showMessage(`获取成功!共找到 ${data.length} 条转写记录`, 'success');
} else {
data = utils.getSummaryContent();
if (!data || data.length === 0) {
utils.showMessage('未找到纪要内容,请确保页面已加载完成', 'error');
return;
}
}
const title = utils.getMeetingTitle();
const recordingTime = utils.getRecordingTime();
let timestamp;
if (recordingTime) {
timestamp = recordingTime.replace(/[^\d]/g, '').slice(0, 14);
if (timestamp.length >= 12) {
timestamp = timestamp.slice(0, 8) + '_' + timestamp.slice(8);
}
} else {
const now = new Date();
timestamp = now.getFullYear().toString() +
(now.getMonth() + 1).toString().padStart(2, '0') +
now.getDate().toString().padStart(2, '0') + '_' +
now.getHours().toString().padStart(2, '0') +
now.getMinutes().toString().padStart(2, '0') +
now.getSeconds().toString().padStart(2, '0');
}
const tabName = exportType === 'transcript' ? '转写' : '纪要';
// 清理文件名中的特殊字符
const safeTitle = title.replace(/[\\/:*?"<>|]/g, '_');
const filename = `${safeTitle}_${tabName}_${timestamp}.${format}`;
let content;
switch (format) {
case 'md':
content = utils.formatAsMarkdown(data, exportType);
break;
case 'html':
content = utils.formatAsHTML(data, exportType);
break;
case 'txt':
content = utils.formatAsTXT(data, exportType);
break;
}
utils.downloadFile(content, filename, format);
utils.showMessage(`${format.toUpperCase()}文件导出成功!`);
const modal = document.querySelector('div[style*="position: fixed"][style*="z-index: 10001"]');
if (modal) this.closeModal(modal);
} catch (error) {
console.error('导出失败:', error);
utils.showMessage('导出失败:' + error.message, 'error');
}
}
async copyContent(contentType = null) {
try {
const currentTab = utils.getCurrentTabType();
const exportType = contentType || (currentTab === 'both' ? 'transcript' : currentTab);
let data;
if (exportType === 'transcript') {
utils.showMessage('正在获取转写内容,请稍候...', 'info');
data = await utils.getTranscriptContent();
if (!data || data.length === 0) {
utils.showMessage('未找到转写内容,请确保页面已加载完成', 'error');
return;
}
utils.showMessage(`获取成功!共找到 ${data.length} 条转写记录`, 'success');
} else {
data = utils.getSummaryContent();
if (!data || data.length === 0) {
utils.showMessage('未找到纪要内容,请确保页面已加载完成', 'error');
return;
}
}
const content = utils.formatAsMarkdown(data, exportType);
const success = await utils.copyToClipboard(content);
if (success) {
utils.showMessage('Markdown内容已复制到剪贴板!');
} else {
utils.showMessage('复制失败,请重试', 'error');
}
const modal = document.querySelector('div[style*="position: fixed"][style*="z-index: 10001"]');
if (modal) this.closeModal(modal);
} catch (error) {
console.error('复制失败:', error);
utils.showMessage('复制失败:' + error.message, 'error');
}
}
closeModal(modal) {
modal.style.opacity = '0';
setTimeout(() => {
if (modal.parentNode) {
modal.parentNode.removeChild(modal);
}
}, 300);
}
}
// 页面加载完成后初始化
function init() {
// 先检查页面是否包含转写内容
const checkInterval = setInterval(() => {
const hasContent = document.querySelector('.minutes-module-list');
if (hasContent) {
clearInterval(checkInterval);
new TencentMeetingExporter();
}
}, 500);
// 最多等待10秒
setTimeout(() => {
clearInterval(checkInterval);
if (!document.querySelector('.tm-exporter-btn')) {
new TencentMeetingExporter();
}
}, 10000);
}
init();
})();