myagent-ai 1.20.10 → 1.20.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1669,6 +1669,7 @@ class MainAgent(BaseAgent):
1669
1669
  _media_type = "audio" if tool_name == "playaudio" else "video"
1670
1670
  _embed_url = None
1671
1671
  _embed_title = params.get("title", "")
1672
+ _fallback_link = None # [v1.20.10] 无法嵌入时提供外部链接
1672
1673
 
1673
1674
  if _media_url:
1674
1675
  # 在线链接 — 提取嵌入式播放 URL
@@ -1679,6 +1680,21 @@ class MainAgent(BaseAgent):
1679
1680
  if _yt_match:
1680
1681
  _embed_url = f"https://www.youtube.com/embed/{_yt_match.group(1)}"
1681
1682
  _embed_title = _embed_title or "YouTube 视频"
1683
+ # YouTube Music 播放列表: https://music.youtube.com/playlist?list=xxx
1684
+ elif 'music.youtube.com' in _url_lower:
1685
+ _ym_match = re.search(r'list=([\w-]+)', _media_url)
1686
+ if _ym_match:
1687
+ _embed_url = f"https://music.youtube.com/embed?list={_ym_match.group(1)}&layout=full"
1688
+ _embed_title = _embed_title or "YouTube Music"
1689
+ else:
1690
+ # 单曲: https://music.youtube.com/watch?v=xxx
1691
+ _ymv_match = re.search(r'watch\?v=([\w-]+)', _media_url)
1692
+ if _ymv_match:
1693
+ _embed_url = f"https://music.youtube.com/embed/{_ymv_match.group(1)}"
1694
+ _embed_title = _embed_title or "YouTube Music"
1695
+ else:
1696
+ _fallback_link = _media_url
1697
+ _embed_title = _embed_title or "YouTube Music"
1682
1698
  # Bilibili: https://www.bilibili.com/video/BVxxx 或 b23.tv/xxx
1683
1699
  elif 'bilibili.com' in _url_lower or 'b23.tv' in _url_lower:
1684
1700
  _bv_match = re.search(r'bilibili\.com/video/(BV[\w]+)', _media_url)
@@ -1690,8 +1706,14 @@ class MainAgent(BaseAgent):
1690
1706
  _embed_title = _embed_title or "B站视频"
1691
1707
  # QQ音乐: https://y.qq.com/n/ryqq/songDetail/xxx
1692
1708
  elif 'y.qq.com' in _url_lower:
1693
- _embed_url = _media_url
1694
- _embed_title = _embed_title or "QQ音乐"
1709
+ # QQ音乐支持 outchain player
1710
+ _qq_match = re.search(r'songDetail/(\w+)', _media_url)
1711
+ if _qq_match:
1712
+ _embed_url = f"https://y.qq.com/n/ryqq/songDetail/{_qq_match.group(1)}"
1713
+ _embed_title = _embed_title or "QQ音乐"
1714
+ else:
1715
+ _embed_url = _media_url
1716
+ _embed_title = _embed_title or "QQ音乐"
1695
1717
  # 网易云音乐: https://music.163.com/song?id=xxx
1696
1718
  elif 'music.163.com' in _url_lower:
1697
1719
  _song_match = re.search(r'music\.163\.com.*[?&]id=(\d+)', _media_url)
@@ -1723,6 +1745,19 @@ class MainAgent(BaseAgent):
1723
1745
  })
1724
1746
  result = {"success": True, "output": f"已嵌入{_embed_title}播放器: {_media_url}"}
1725
1747
 
1748
+ elif _fallback_link and stream_callback:
1749
+ # [v1.20.10] 无法嵌入但提供外部链接 — 发送链接卡片
1750
+ stream_callback({
1751
+ "type": "v2_media",
1752
+ "data": {
1753
+ "media_type": _media_type,
1754
+ "embed_url": "", # 空 embed_url 告诉前端渲染链接
1755
+ "title": _embed_title,
1756
+ "original_url": _fallback_link,
1757
+ }
1758
+ })
1759
+ result = {"success": True, "output": f"已提供{_embed_title}链接(不支持嵌入播放): {_fallback_link}"}
1760
+
1726
1761
  elif _media_file:
1727
1762
  # 本地文件 — 使用 file_send 发送文件,前端渲染内嵌播放器
1728
1763
  from pathlib import Path as _P
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.20.10",
3
+ "version": "1.20.11",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
@@ -2825,15 +2825,28 @@ function _renderMessagesInner() {
2825
2825
  let embedUrl = m.embed_url || '';
2826
2826
  const title = m.title || (isAudio ? '在线音乐' : '在线视频');
2827
2827
  const origUrl = m.original_url || embedUrl;
2828
- if (!embedUrl) continue;
2828
+ if (!embedUrl && !origUrl) continue;
2829
+ // [v1.20.10] 如果 embed_url 为空,渲染链接卡片而非 iframe
2830
+ if (!embedUrl) {
2831
+ const icon = isAudio ? '🎵' : '🎬';
2832
+ parts.push('<div class="msg-media-embed msg-media-link-card" style="padding:10px 14px;border-radius:8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);cursor:pointer" onclick="window.open(\'' + escapeHtml(origUrl) + '\',\'_blank\')">' +
2833
+ '<div class="msg-media-header"><span class="msg-media-icon">' + icon + '</span><span class="msg-media-label">' + escapeHtml(title) + '</span>' +
2834
+ '<span style="margin-left:auto;font-size:12px;opacity:0.6">点击在新窗口打开 ↗</span></div>' +
2835
+ '<div style="font-size:12px;opacity:0.5;margin-top:4px;word-break:break-all">' + escapeHtml(origUrl) + '</div>' +
2836
+ '</div>');
2837
+ continue;
2838
+ }
2829
2839
  // 前端 URL → 嵌入 URL 转换(历史回放时 embed_url 可能是原始 URL)
2830
- if (embedUrl && !embedUrl.includes('/embed/') && !embedUrl.includes('/player')) {
2840
+ if (embedUrl && !embedUrl.includes('/embed/') && !embedUrl.includes('/player') && !embedUrl.includes('/outchain/')) {
2831
2841
  const ytMatch = embedUrl.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]+)/);
2832
2842
  if (ytMatch) { embedUrl = 'https://www.youtube.com/embed/' + ytMatch[1]; }
2833
2843
  const biliMatch = embedUrl.match(/bilibili\.com\/video\/(BV[\w]+)/);
2834
2844
  if (biliMatch) { embedUrl = 'https://player.bilibili.com/player.html?bvid=' + biliMatch[1] + '&autoplay=0'; }
2835
2845
  const neteaseMatch = embedUrl.match(/music\.163\.com.*[?&]id=(\d+)/);
2836
2846
  if (neteaseMatch) { embedUrl = 'https://music.163.com/outchain/player?type=2&id=' + neteaseMatch[1] + '&auto=0&height=66'; }
2847
+ // [v1.20.10] YouTube Music 播放列表 → embed
2848
+ const ymMatch = embedUrl.match(/music\.youtube\.com.*list=([\w-]+)/);
2849
+ if (ymMatch) { embedUrl = 'https://music.youtube.com/embed?list=' + ymMatch[1] + '&layout=full'; }
2837
2850
  }
2838
2851
  if (isAudio) {
2839
2852
  parts.push('<div class="msg-media-embed msg-media-audio">' +