Add files via upload

This commit is contained in:
Cola-Echo
2025-12-23 01:37:48 +08:00
committed by GitHub
parent 37e172bfa9
commit c47ee87e40
4 changed files with 168 additions and 15 deletions

View File

@@ -42,6 +42,8 @@ let listenState = {
audioElement: null, audioElement: null,
progressInterval: null, progressInterval: null,
pauseTimeout: null, // 暂停后自动播放下一首的计时器 pauseTimeout: null, // 暂停后自动播放下一首的计时器
playMode: 'normal', // 播放模式: 'normal' | 'loop' | 'shuffle'
songsSinceAIChange: 0, // AI换歌保底计数器
}; };
// 导出图标供其他模块使用 // 导出图标供其他模块使用
@@ -227,6 +229,8 @@ export async function startListenTogether(song, contactIndex = currentChatIndex)
audioElement: null, audioElement: null,
progressInterval: null, progressInterval: null,
pauseTimeout: null, pauseTimeout: null,
playMode: 'normal',
songsSinceAIChange: 0,
}; };
// 隐藏搜索页,显示等待页面 // 隐藏搜索页,显示等待页面
@@ -317,9 +321,112 @@ async function onSongEnded() {
listenState.isPlaying = false; listenState.isPlaying = false;
updatePlayButton(); updatePlayButton();
// 20%几率AI换歌 // 计数器+1
if (Math.random() < 0.2) { listenState.songsSinceAIChange++;
// 20%几率AI换歌或保底5首必换所有模式下都有效
if (Math.random() < 0.2 || listenState.songsSinceAIChange >= 5) {
listenState.songsSinceAIChange = 0; // 重置计数器
await aiSelectSong(); await aiSelectSong();
return;
}
// 根据播放模式处理
if (listenState.playMode === 'loop') {
// 单曲循环:重新播放当前歌曲
await playListenSong();
} else if (listenState.playMode === 'shuffle') {
// 随机播放:播放随机歌曲
await playRandomSong();
}
// 正常模式不做处理,等待用户操作
}
/**
* 切换单曲循环模式
*/
function toggleLoopMode() {
const loopBtn = document.getElementById('wechat-listen-loop-btn');
const shuffleBtn = document.getElementById('wechat-listen-shuffle-btn');
if (listenState.playMode === 'loop') {
// 取消单曲循环
listenState.playMode = 'normal';
loopBtn?.classList.remove('active');
showToast('已关闭单曲循环');
} else {
// 开启单曲循环
listenState.playMode = 'loop';
loopBtn?.classList.add('active');
shuffleBtn?.classList.remove('active');
showToast('单曲循环');
}
}
/**
* 切换随机播放模式
*/
function toggleShuffleMode() {
const loopBtn = document.getElementById('wechat-listen-loop-btn');
const shuffleBtn = document.getElementById('wechat-listen-shuffle-btn');
if (listenState.playMode === 'shuffle') {
// 取消随机播放
listenState.playMode = 'normal';
shuffleBtn?.classList.remove('active');
showToast('已关闭随机播放');
} else {
// 开启随机播放
listenState.playMode = 'shuffle';
shuffleBtn?.classList.add('active');
loopBtn?.classList.remove('active');
showToast('随机播放');
}
}
/**
* 随机播放歌曲
*/
async function playRandomSong() {
try {
// 随机关键词列表
const keywords = [
'热门', '流行', '经典', '抖音', '网红',
'伤感', '甜蜜', '治愈', '怀旧', '浪漫',
'周杰伦', '林俊杰', '邓紫棋', '薛之谦', '陈奕迅',
'Taylor Swift', 'Ed Sheeran', 'Bruno Mars',
'说唱', '民谣', '摇滚', '电子', 'R&B'
];
const randomKeyword = keywords[Math.floor(Math.random() * keywords.length)];
// 搜索歌曲
const results = await searchMusic(randomKeyword);
if (results && results.length > 0) {
// 随机选择一首
const randomIndex = Math.floor(Math.random() * Math.min(results.length, 10));
const newSong = results[randomIndex];
listenState.currentSong = newSong;
// 更新界面
const coverEl = document.getElementById('wechat-listen-cover');
const nameEl = document.getElementById('wechat-listen-song-name');
const artistEl = document.getElementById('wechat-listen-song-artist');
if (coverEl && newSong.cover) coverEl.src = newSong.cover;
if (nameEl) nameEl.textContent = newSong.name || '未知歌曲';
if (artistEl) artistEl.textContent = newSong.artist || '未知歌手';
// 播放
await playMusic(newSong.id, newSong.platform, newSong.name, newSong.artist);
listenState.isPlaying = true;
updatePlayButton();
// AI对新歌的反应
await triggerAIAutoNextReaction(newSong);
}
} catch (e) {
console.error('[可乐] 随机播放失败:', e);
} }
} }
@@ -504,19 +611,45 @@ function filterListenMessage(text) {
} }
/** /**
* 处理AI回复 - 纯文字消息 * 处理AI回复 - 纯文字消息,按换行分条发送
*/ */
async function processAIResponse(aiResponse) { async function processAIResponse(aiResponse) {
if (!aiResponse) return; if (!aiResponse) return;
const parts = splitAIMessages(aiResponse); // 先用 ||| 分割,再按换行分割
let parts = splitAIMessages(aiResponse);
// 对每个部分再按换行分割
const allParts = [];
for (const part of parts) { for (const part of parts) {
// 按换行符分割成多条消息
const lines = part.split(/\n+/).map(l => l.trim()).filter(l => l);
allParts.push(...lines);
}
for (const part of allParts) {
if (!listenState.isConnected) break; if (!listenState.isConnected) break;
let reply = filterListenMessage(part); let reply = filterListenMessage(part);
if (!reply) continue; if (!reply) continue;
// 检查是否包含换歌标签
const changeSongMatch = reply.match(/\[换歌[:]\s*(.+?)\]/);
if (changeSongMatch) {
const songKeyword = changeSongMatch[1].trim();
// 显示AI的说明文字去掉换歌标签
const displayText = reply.replace(/\[换歌[:][^\]]*\]/g, '').trim();
if (displayText) {
showListenTypingIndicator();
await sleep(400 + Math.random() * 600);
hideListenTypingIndicator();
addListenMessage('ai', displayText);
}
// 搜索并播放新歌
await changeSongByKeyword(songKeyword, true);
continue;
}
// 直接发送纯文字消息 // 直接发送纯文字消息
showListenTypingIndicator(); showListenTypingIndicator();
await sleep(400 + Math.random() * 600); await sleep(400 + Math.random() * 600);
@@ -885,11 +1018,14 @@ function bindListenEvents() {
// 播放/暂停 // 播放/暂停
document.getElementById('wechat-listen-play-btn')?.addEventListener('click', handlePlayPauseClick); document.getElementById('wechat-listen-play-btn')?.addEventListener('click', handlePlayPauseClick);
// 星星按钮 - 打开颜色选择器 // 搜索按钮 - 打开换歌面板
document.getElementById('wechat-listen-color-btn')?.addEventListener('click', toggleColorPicker); document.getElementById('wechat-listen-search-btn')?.addEventListener('click', showChangeSongPanel);
// 颜色选择器选项点击 // 单曲循环按钮
document.getElementById('wechat-listen-color-picker')?.addEventListener('click', handleColorOptionClick); document.getElementById('wechat-listen-loop-btn')?.addEventListener('click', toggleLoopMode);
// 随机播放按钮
document.getElementById('wechat-listen-shuffle-btn')?.addEventListener('click', toggleShuffleMode);
// 结束按钮 // 结束按钮
document.getElementById('wechat-listen-end-btn')?.addEventListener('click', exitListenTogether); document.getElementById('wechat-listen-end-btn')?.addEventListener('click', exitListenTogether);
@@ -1115,6 +1251,8 @@ function cancelListenTogether() {
audioElement: null, audioElement: null,
progressInterval: null, progressInterval: null,
pauseTimeout: null, pauseTimeout: null,
playMode: 'normal',
songsSinceAIChange: 0,
}; };
} }
@@ -1165,6 +1303,8 @@ export async function exitListenTogether() {
audioElement: null, audioElement: null,
progressInterval: null, progressInterval: null,
pauseTimeout: null, pauseTimeout: null,
playMode: 'normal',
songsSinceAIChange: 0,
}; };
// AI 结束一起听后的回复 // AI 结束一起听后的回复

View File

@@ -973,8 +973,6 @@ export async function generateNewMomentForContact(contactIndex) {
return; return;
} }
showToast('正在生成朋友圈...', '⏳');
try { try {
// 调用 AI 生成朋友圈内容 // 调用 AI 生成朋友圈内容
const momentContent = await generateMomentContent(contact); const momentContent = await generateMomentContent(contact);

View File

@@ -1530,12 +1530,18 @@ function generateListenTogetherHTML() {
<!-- 控制按钮(底部) --> <!-- 控制按钮(底部) -->
<div class="wechat-listen-controls"> <div class="wechat-listen-controls">
<button class="wechat-listen-ctrl-btn" id="wechat-listen-star-btn" title="更换背景"> <button class="wechat-listen-ctrl-btn" id="wechat-listen-search-btn" title="搜索换歌">
<svg viewBox="0 0 24 24" width="20" height="20"><polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> <svg viewBox="0 0 24 24" width="20" height="20"><circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2" fill="none"/><path d="M21 21l-4.35-4.35" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="wechat-listen-ctrl-btn" id="wechat-listen-loop-btn" title="单曲循环">
<svg viewBox="0 0 24 24" width="20" height="20"><path d="M17 2l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M3 11v-1a4 4 0 014-4h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M7 22l-4-4 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M21 13v1a4 4 0 01-4 4H3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><text x="12" y="14" text-anchor="middle" font-size="8" fill="currentColor" font-weight="bold">1</text></svg>
</button> </button>
<button class="wechat-listen-ctrl-btn wechat-listen-play-btn" id="wechat-listen-play-btn"> <button class="wechat-listen-ctrl-btn wechat-listen-play-btn" id="wechat-listen-play-btn">
<svg viewBox="0 0 24 24" width="24" height="24"><polygon points="5,3 19,12 5,21" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> <svg viewBox="0 0 24 24" width="24" height="24"><polygon points="5,3 19,12 5,21" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button> </button>
<button class="wechat-listen-ctrl-btn" id="wechat-listen-shuffle-btn" title="随机播放">
<svg viewBox="0 0 24 24" width="20" height="20"><path d="M16 3h5v5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M4 20L21 3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M21 16v5h-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M15 15l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M4 4l5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>
</button>
<button class="wechat-listen-ctrl-btn" id="wechat-listen-end-btn" title="结束"> <button class="wechat-listen-ctrl-btn" id="wechat-listen-end-btn" title="结束">
<svg viewBox="0 0 24 24" width="20" height="20"><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> <svg viewBox="0 0 24 24" width="20" height="20"><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button> </button>

View File

@@ -9468,6 +9468,15 @@
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
} }
.wechat-listen-ctrl-btn.active {
color: #07c160;
background: rgba(7, 193, 96, 0.15);
}
.wechat-listen-ctrl-btn.active:hover {
background: rgba(7, 193, 96, 0.25);
}
.wechat-listen-play-btn { .wechat-listen-play-btn {
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
padding: 14px; padding: 14px;
@@ -9559,17 +9568,17 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 12px 16px; padding: 8px 16px;
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
flex-shrink: 0; flex-shrink: 0;
} }
.wechat-listen-input-text { .wechat-listen-input-text {
flex: 1; flex: 1;
padding: 10px 14px; padding: 8px 14px;
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border: none; border: none;
border-radius: 20px; border-radius: 18px;
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
outline: none; outline: none;