WWW.YOUINFO.SITE
标签聚合 强大

/tag/强大

LinuxDo 最新话题 · 2026-06-10 14:05:26+08:00 · tech

Brave 是一款基于 Chromium 内核的开源浏览器,以强大的隐私保护和广告拦截功能著称。它默认启用 Shields 功能,可有效阻挡广告、跟踪器和指纹识别,同时提供更快的浏览速度和更低的资源占用。 Brave 还长期支持 MC2(Manifest V2)扩展 ,为用户提供了更灵活的扩展兼容性。 2026 年 6 月初,Brave 正式发布了 Brave Origin 版本,(59.9$买断制)。该版本保留了 Brave 的 核心优势 的基础上, 移除或禁用的功能 (这些功能在普通版中默认可用)包括: Leo AI 助手 Brave News(新闻) Playlist(播放列表) Rewards 系统(同时禁用浏览器内 Brave 广告) Speedreader(速度阅读器) VPN Wallet(加密货币钱包,同时禁用 Web3 域名) Talk(通话功能) Tor 私有窗口 Wayback Machine 集成 Web Discovery Project 部分统计数据和遥测(如日常使用 ping、崩溃日志、P3A 隐私保护分析)等 Origin 因移除多余组件,启动更快、资源占用更低、界面更简洁,提供更纯粹的浏览器体验。 但是目前可以通过 macOS 系统级配置文件 (.mobileconfig)和 Windows JSON 策略 的方式达到近似的效果。 效果图如下: macOS 使用方法 将下方 XML 内容复制并保存为 Brave-Policies.mobileconfig 文件。 双击文件安装配置描述文件。 安装完成后重启 Brave 浏览器。 打开 brave://policy/ 确认策略生效。 XML <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadScope</key> <string>System</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadRemovalDisallowed</key> <false/> <key>PayloadUUID</key> <string>e143b891-3398-48f9-bee1-54d3b6db44b3</string> <key>PayloadDisplayName</key> <string>Brave Policies</string> <key>PayloadDescription</key> <string>Brave Browser system-level policies</string> <key>PayloadIdentifier</key> <string>com.brave.Browser</string> <key>PayloadContent</key> <array> <dict> <key>PayloadIdentifier</key> <string>com.brave.Browser</string> <key>PayloadType</key> <string>com.brave.Browser</string> <key>PayloadUUID</key> <string>88032831-5301-41ad-8231-10efa9d67ab3</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadEnabled</key> <true/> <key>TabSearchActivated</key> <false/> <key>GlobalMediaControlsEnabled</key> <false/> <key>TorDisabled</key> <true/> <key>BraveRewardsDisabled</key> <true/> <key>BraveWalletDisabled</key> <true/> <key>BraveVPNDisabled</key> <true/> <key>BraveAIChatEnabled</key> <false/> <key>BraveSidebarAvailable</key> <false/> <key>BraveShoppingEnabled</key> <false/> <key>BraveSponsorshipsEnabled</key> <false/> <key>BraveTalkDisabled</key> <true/> <key>IPFSEnabled</key> <false/> <key>DefaultLocalFontsSetting</key> <integer>3</integer> <key>DefaultSensorsSetting</key> <integer>3</integer> <key>DefaultSerialGuardSetting</key> <integer>2</integer> <key>CloudReportingEnabled</key> <false/> <key>DriveDisabled</key> <true/> <key>PasswordSharingEnabled</key> <false/> <key>QuickAnswersEnabled</key> <false/> <key>SafeBrowsingExtendedReportingEnabled</key> <false/> <key>SafeBrowsingSurveysEnabled</key> <false/> <key>SafeBrowsingDeepScanningEnabled</key> <false/> <key>DeviceActivityHeartbeatEnabled</key> <false/> <key>DeviceMetricsReportingEnabled</key> <false/> <key>HeartbeatEnabled</key> <false/> <key>LogUploadEnabled</key> <false/> <key>ReportDeviceActivityTimes</key> <false/> <key>ReportDeviceAppInfo</key> <false/> <key>ReportDeviceSystemInfo</key> <false/> <key>ReportDeviceUsers</key> <false/> <key>AlternateErrorPagesEnabled</key> <false/> <key>AutofillCreditCardEnabled</key> <false/> <key>BackgroundModeEnabled</key> <false/> <key>BrowserGuestModeEnabled</key> <true/> <key>BrowserSignin</key> <integer>0</integer> <key>BuiltInDnsClientEnabled</key> <false/> <key>DefaultBrowserSettingEnabled</key> <false/> <key>DefaultBrowserSettingNotificationAllowed</key> <false/> <key>MetricsReportingEnabled</key> <false/> <key>ParcelTrackingEnabled</key> <false/> <key>RelatedWebsiteSetsEnabled</key> <false/> <key>ShoppingListEnabled</key> <false/> </dict> </array> </dict> </plist> Windows 使用方法(JSON 策略,与 macOS 配置一致) 创建文件夹路径(推荐使用以下路径之一): C:\ProgramData\BraveSoftware\Brave-Browser\Policies\Managed\ 或 C:\Program Files\BraveSoftware\Brave-Browser\Application\Policies\Managed\ 在 Managed 目录下新建文件 brave_policy.json,复制下方完整 JSON 内容并保存。 重启 Brave 浏览器。 打开 brave://policy/ 页面确认所有策略已生效。 JSON { "policies": { "TabSearchActivated": false, "GlobalMediaControlsEnabled": false, "TorDisabled": true, "BraveRewardsDisabled": true, "BraveWalletDisabled": true, "BraveVPNDisabled": true, "BraveAIChatEnabled": false, "BraveSidebarAvailable": false, "BraveShoppingEnabled": false, "BraveSponsorshipsEnabled": false, "BraveTalkDisabled": true, "IPFSEnabled": false, "DefaultLocalFontsSetting": 3, "DefaultSensorsSetting": 3, "DefaultSerialGuardSetting": 2, "CloudReportingEnabled": false, "DriveDisabled": true, "PasswordSharingEnabled": false, "QuickAnswersEnabled": false, "SafeBrowsingExtendedReportingEnabled": false, "SafeBrowsingSurveysEnabled": false, "SafeBrowsingDeepScanningEnabled": false, "DeviceActivityHeartbeatEnabled": false, "DeviceMetricsReportingEnabled": false, "HeartbeatEnabled": false, "LogUploadEnabled": false, "ReportDeviceActivityTimes": false, "ReportDeviceAppInfo": false, "ReportDeviceSystemInfo": false, "ReportDeviceUsers": false, "AlternateErrorPagesEnabled": false, "AutofillCreditCardEnabled": false, "BackgroundModeEnabled": false, "BrowserGuestModeEnabled": true, "BrowserSignin": 0, "BuiltInDnsClientEnabled": false, "DefaultBrowserSettingEnabled": false, "DefaultBrowserSettingNotificationAllowed": false, "MetricsReportingEnabled": false, "ParcelTrackingEnabled": false, "RelatedWebsiteSetsEnabled": false, "ShoppingListEnabled": false } } 注意 : 配置后若需移除,删除对应配置文件并重启浏览器即可。 Windows 用户也可使用 Group Policy 编辑器 + 官方 ADMX 模板进行管理。 Linux 用户可 免费 使用 Brave Origin 。 始终从官网下载最新版 Brave 浏览器。 欢迎大家测试并反馈效果。如果有其他平台需求或需要调整策略,欢迎留言。支持正版的朋友也可直接购买 Brave Origin(支持多设备激活),也可组团拼车。 AI 编写提示 :本帖内容由 AI 辅助生成和优化,旨在提供准确、清晰的配置指导。所有配置文件均基于公开的 Brave 企业策略文档整理,使用前请自行验证,并在必要时备份重要数据。 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-10 10:51:41+08:00 · tech

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FLAC 歌词嵌入 · LRCLib</title> <style> :root { --bg: #08080f; --surface: #111118; --surface2: #181820; --border: #222230; --text: #e0e0e8; --text2: #8888a0; --accent: #a78bfa; --accent2: #7c5cfc; --green: #34d399; --gold: #fbbf24; --radius: 16px; --radius-sm: 10px; --radius-xs: 8px; } * { margin: 0; padding: 0; box-sizing: border-box; } body { background: var(--bg); font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif; min-height: 100vh; display: flex; justify-content: center; padding: 28px 16px; color: var(--text); } .container { width: 100%; max-width: 960px; display: flex; flex-direction: column; gap: 18px; } .header { text-align: center; padding: 8px 0 4px; } .header h1 { font-size: 1.7rem; font-weight: 700; letter-spacing: -0.4px; background: linear-gradient(135deg, #a78bfa, #34d399); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .header .sub { font-size: 0.82rem; color: var(--text2); margin-top: 2px; } .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; } .card-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 1.5px; color: var(--text2); margin-bottom: 12px; font-weight: 600; } .drop-wrapper { position: relative; } .drop-wrapper input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; z-index: 2; } .drop-zone { background: var(--surface2); border: 2px dashed #2a2a3e; border-radius: var(--radius); padding: 32px 20px; text-align: center; transition: all 0.2s; pointer-events: none; } .drop-wrapper.drag-over .drop-zone { border-color: var(--accent); background: #1a1a28; box-shadow: 0 0 0 6px rgba(124, 92, 252, 0.15); } .drop-wrapper:hover .drop-zone { border-color: var(--accent); background: #1a1a28; box-shadow: 0 0 0 6px rgba(124, 92, 252, 0.06); } .drop-zone .dz-icon { font-size: 2.4rem; margin-bottom: 8px; opacity: 0.8; } .drop-zone .dz-title { font-weight: 600; font-size: 0.95rem; } .drop-zone .dz-hint { font-size: 0.78rem; color: var(--text2); margin-top: 4px; } .file-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; } .chip { display: inline-flex; align-items: center; gap: 6px; background: var(--surface2); border: 1px solid var(--border); padding: 6px 12px; border-radius: 20px; font-size: 0.8rem; font-family: 'SF Mono', 'Consolas', monospace; color: #c0c0d0; } .chip .chip-tag { font-size: 0.64rem; background: #1e1e30; color: var(--accent); padding: 2px 7px; border-radius: 10px; font-weight: 500; } .chip .chip-del { cursor: pointer; color: #666; font-weight: 700; font-size: 1rem; line-height: 1; margin-left: 2px; transition: color 0.15s; } .chip .chip-del:hover { color: #f87171; } .row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } .row.mt { margin-top: 12px; } .input { flex: 1; min-width: 180px; padding: 11px 16px; border-radius: var(--radius-xs); border: 1px solid var(--border); background: var(--surface2); color: var(--text); font-size: 0.9rem; outline: none; font-family: inherit; transition: border-color 0.2s; } .input:focus { border-color: var(--accent); } .input::placeholder { color: #555; } .btn { padding: 10px 20px; border-radius: 24px; border: 1px solid var(--border); background: var(--surface2); color: var(--text); cursor: pointer; font-size: 0.85rem; font-weight: 600; transition: all 0.2s; white-space: nowrap; display: inline-flex; align-items: center; gap: 5px; font-family: inherit; letter-spacing: 0.2px; } .btn:hover { background: #222238; border-color: #444; } .btn-primary { background: var(--accent2); border-color: var(--accent2); color: #fff; box-shadow: 0 4px 18px rgba(124, 92, 252, 0.25); } .btn-primary:hover { background: #8f6fff; border-color: #8f6fff; box-shadow: 0 6px 24px rgba(124, 92, 252, 0.35); } .btn-sm { padding: 6px 14px; font-size: 0.76rem; border-radius: 18px; } .btn-xs { padding: 4px 10px; font-size: 0.7rem; border-radius: 14px; } .btn:disabled { opacity: 0.35; cursor: not-allowed; pointer-events: none; } .hint { font-size: 0.72rem; color: var(--text2); margin-top: 6px; font-style: italic; } .results-box { display: none; max-height: 280px; overflow-y: auto; margin-top: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface2); } .results-box.open { display: block; } .result-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; cursor: pointer; transition: background 0.12s; gap: 10px; flex-wrap: wrap; } .result-row:hover { background: #1e1e2c; } .result-row+.result-row { border-top: 1px solid rgba(255, 255, 255, 0.03); } .result-row.selected { background: #1a1830; border-left: 3px solid var(--accent); } .result-info { flex: 1; min-width: 0; } .result-info .rtrack { font-weight: 600; font-size: 0.88rem; } .result-info .rartist { font-size: 0.76rem; color: var(--text2); } .result-meta { font-size: 0.7rem; color: #555; white-space: nowrap; } .empty { text-align: center; color: var(--text2); padding: 28px; font-size: 0.85rem; } .spinner-wrap { text-align: center; padding: 28px; color: var(--text2); display: flex; align-items: center; justify-content: center; gap: 8px; } .spinner { width: 16px; height: 16px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.7s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .lyrics-panel { display: none; margin-top: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; } .lyrics-panel.open { display: block; } .lyrics-top { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; padding: 12px 16px; background: #14141e; border-bottom: 1px solid var(--border); } .lyrics-top .ltitle { font-weight: 700; font-size: 1rem; } .lyrics-top .lartist { color: var(--accent); font-size: 0.82rem; } .lyrics-top .lalbum { color: var(--text2); font-size: 0.76rem; } .tabs { display: flex; gap: 3px; flex-wrap: wrap; } .tab { padding: 5px 12px; border-radius: 16px; border: 1px solid var(--border); background: transparent; color: var(--text2); cursor: pointer; font-size: 0.72rem; font-weight: 500; transition: 0.2s; font-family: inherit; } .tab.on { background: var(--accent2); border-color: var(--accent2); color: #fff; } .lyrics-content { padding: 16px; max-height: 340px; overflow-y: auto; background: #0c0c16; font-family: 'SF Mono', 'Fira Code', 'Consolas', 'PingFang SC', monospace; font-size: 0.8rem; line-height: 1.75; white-space: pre-wrap; color: #c0c0d0; } .lyrics-content .hl-tag { color: var(--accent); font-weight: 600; } .lyrics-content .hl-idx { color: #666; } .lyrics-content .hl-time { color: var(--green); } .lyrics-content .hl-section { color: var(--gold); } .lyrics-content .hl-style { color: #60a5fa; } .check-row { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; padding: 10px 0; font-size: 0.76rem; color: var(--text2); } .check-row label { display: flex; align-items: center; gap: 5px; cursor: pointer; user-select: none; } .check-row input[type="checkbox"] { accent-color: var(--accent2); width: 15px; height: 15px; cursor: pointer; } .action-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding-top: 12px; border-top: 1px solid var(--border); } .tag-chips { display: flex; gap: 4px; flex-wrap: wrap; } .tag-chip { padding: 4px 10px; border-radius: 14px; border: 1px solid var(--border); background: transparent; color: var(--text2); cursor: pointer; font-size: 0.68rem; font-weight: 500; transition: 0.2s; user-select: none; font-family: inherit; } .tag-chip.on { background: var(--accent2); border-color: var(--accent2); color: #fff; } .toast { position: fixed; top: 16px; left: 50%; transform: translateX(-50%); padding: 10px 22px; border-radius: 24px; font-weight: 600; font-size: 0.82rem; z-index: 999; opacity: 0; pointer-events: none; transition: opacity 0.3s; letter-spacing: 0.2px; } .toast.show { opacity: 1; } .toast.ok { background: #065f46; color: #d1fae5; box-shadow: 0 8px 28px rgba(5, 150, 105, 0.3); } .toast.err { background: #7f1d1d; color: #fecaca; box-shadow: 0 8px 28px rgba(220, 38, 38, 0.3); } .footer-note { text-align: center; font-size: 0.7rem; color: #555; } ::-webkit-scrollbar { width: 4px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: #333; border-radius: 2px; } @media (max-width: 640px) { .row { flex-direction: column; align-items: stretch; } .btn { justify-content: center; } .action-row { flex-direction: column; align-items: stretch; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>🎵 FLAC 歌词嵌入工具</h1> <div class="sub">LRCLib 歌词搜索 · Vorbis Comment 标签写入 · 元数据覆盖</div> </div> <div class="card"> <div class="card-label">📂 选择 FLAC 文件</div> <div class="drop-wrapper" id="dropWrapper"> <input type="file" id="fileInput" accept=".flac,audio/flac" multiple> <div class="drop-zone"> <div class="dz-icon">🎶</div> <div class="dz-title">点击选择或拖拽 FLAC 文件</div> <div class="dz-hint">支持批量 · 自动读取 TITLE / ARTIST / ALBUM 标签</div> </div> </div> <div class="file-chips" id="fileChips"></div> <div class="row mt"> <button class="btn btn-sm" id="clearFilesBtn" disabled>🗑 清空</button> <span style="font-size:0.76rem;color:var(--text2);" id="fileStatus">等待添加 FLAC…</span> </div> </div> <div class="card"> <div class="card-label">🔍 搜索歌词</div> <div class="row"> <input class="input" id="searchInput" placeholder="歌曲名 或「歌曲名 - 歌手名」" autocomplete="off"> <button class="btn btn-primary" id="searchBtn">搜索</button> <button class="btn btn-sm" id="directBtn">🎯 精确获取</button> </div> <div class="hint" id="autoFillHint"></div> <div class="results-box" id="resultsBox"> <div id="resultsList"></div> </div> </div> <div class="card" id="lyricsCard" style="display:none;"> <div class="lyrics-panel open" id="lyricsPreview"> <div class="lyrics-top"> <div> <span class="ltitle" id="songName">—</span> <span style="margin:0 5px;color:#555;">·</span> <span class="lartist" id="songArtist">—</span> <span style="margin:0 5px;color:#555;">·</span> <span class="lalbum" id="songAlbum">—</span> </div> <div class="tabs"> <button class="tab on" data-fmt="lrc">LRC</button> <button class="tab" data-fmt="srt">SRT</button> <button class="tab" data-fmt="ass">ASS</button> <button class="tab" data-fmt="vtt">VTT</button> </div> </div> <div class="lyrics-content" id="lyricsContent"></div> </div> <div class="check-row"> <span>🔧 写入时覆盖:</span> <label><input type="checkbox" id="ovTitle" checked> TITLE</label> <label><input type="checkbox" id="ovArtist" checked> ARTIST</label> <label><input type="checkbox" id="ovAlbum" checked> ALBUM</label> <span style="color:#555;font-size:0.68rem;">用 API 返回信息覆盖 FLAC 标签</span> </div> <div class="action-row"> <span style="font-size:0.72rem;color:var(--text2);font-weight:600;">歌词标签</span> <div class="tag-chips" id="tagChips"> <span class="tag-chip on" data-tag="LYRICS">LYRICS</span> <span class="tag-chip" data-tag="UNSYNCEDLYRICS">UNSYNCEDLYRICS</span> <span class="tag-chip" data-tag="LYRICS_LRC">LYRICS_LRC</span> <span class="tag-chip" data-tag="LYRICS_SRT">LYRICS_SRT</span> <span class="tag-chip" data-tag="LYRICS_ASS">LYRICS_ASS</span> <span class="tag-chip" data-tag="LYRICS_VTT">LYRICS_VTT</span> </div> <span style="flex:1;"></span> <button class="btn btn-primary" id="embedBtn" disabled>💾 写入并下载</button> </div> </div> <div class="footer-note">浏览器安全限制:通过下载生成新文件,原文件不被修改</div> </div> <div class="toast" id="toast"></div> <script> (function() { var DW = document.getElementById('dropWrapper'); var FI = document.getElementById('fileInput'); var FC = document.getElementById('fileChips'); var CFB = document.getElementById('clearFilesBtn'); var FST = document.getElementById('fileStatus'); var SI = document.getElementById('searchInput'); var SB = document.getElementById('searchBtn'); var DB = document.getElementById('directBtn'); var AFH = document.getElementById('autoFillHint'); var RB = document.getElementById('resultsBox'); var RL = document.getElementById('resultsList'); var LC = document.getElementById('lyricsCard'); var LCT = document.getElementById('lyricsContent'); var SN = document.getElementById('songName'); var SA = document.getElementById('songArtist'); var SAL = document.getElementById('songAlbum'); var EB = document.getElementById('embedBtn'); var OVT = document.getElementById('ovTitle'); var OVA = document.getElementById('ovArtist'); var OVAL = document.getElementById('ovAlbum'); var TO = document.getElementById('toast'); var TABS = document.querySelectorAll('.tab'); var TCHIPS = document.querySelectorAll('.tag-chip'); var files = []; var song = null; var fmt = 'lrc'; var tag = 'LYRICS'; var results = []; var selectedIdx = -1; var tt; function toast(m, e) { clearTimeout(tt); TO.textContent = m; TO.className = 'toast show ' + (e ? 'err' : 'ok'); tt = setTimeout(function() { TO.className = 'toast'; }, 2200); } function esc(s) { var d = document.createElement('div'); d.appendChild(document.createTextNode(s)); return d.innerHTML; } function p2(n) { return String(n).padStart(2, '0'); } function p3(n) { return String(n).padStart(3, '0'); } function readMeta(file, cb) { var r = new FileReader(); r.onload = function(e) { try { var b = e.target.result; var v = new DataView(b); if (b.byteLength < 4) return cb({ t: null, a: null, c: null, al: null }); if (String.fromCharCode(v.getUint8(0), v.getUint8(1), v.getUint8(2), v.getUint8(3)) !== 'fLaC') return cb({ t: null, a: null, c: null, al: null }); var o = 4, lb = false, t = null, a = null, c = null, al = null; while (o < b.byteLength && !lb) { if (o + 4 > b.byteLength) break; var h = v.getUint8(o); lb = (h & 0x80) !== 0; var bt = h & 0x7F; var bs = (v.getUint8(o + 1) << 16) | (v.getUint8(o + 2) << 8) | v.getUint8(o + 3); o += 4; if (bt === 4 && o + bs <= b.byteLength) { var bl = new Uint8Array(b, o, bs); var dec = new TextDecoder('utf-8'); if (bl.length >= 4) { var vl = bl[0] | (bl[1] << 8) | (bl[2] << 16) | (bl[3] << 24); var p = 4 + vl; if (p + 4 <= bl.length) { var nc = bl[p] | (bl[p + 1] << 8) | (bl[p + 2] << 16) | (bl[p + 3] << 24); p += 4; for (var i = 0; i < nc && p + 4 <= bl.length; i++) { var cl = bl[p] | (bl[p + 1] << 8) | (bl[p + 2] << 16) | (bl[p + 3] << 24); p += 4; if (p + cl > bl.length) break; var cs = dec.decode(bl.slice(p, p + cl)); p += cl; var ei = cs.indexOf('='); if (ei > 0) { var k = cs.substring(0, ei).toUpperCase().trim(); var val = cs.substring(ei + 1).trim(); if (k === 'TITLE' && !t) t = val; if (k === 'ARTIST' && !a) a = val; if (k === 'COMPOSER' && !c) c = val; if (k === 'ALBUM' && !al) al = val; } } } } break; } o += bs; } cb({ t: t, a: a, c: c, al: al }); } catch (x) { cb({ t: null, a: null, c: null, al: null }); } }; r.onerror = function() { cb({ t: null, a: null, c: null, al: null }); }; r.readAsArrayBuffer(file); } function autoFill() { if (files.length === 0) { AFH.textContent = ''; return; } var t = files[0].t || ''; var a = files[0].a || files[0].c || ''; if (t) { var ft = t; if (a) ft += ' - ' + a; SI.value = ft; AFH.textContent = '📋 已从 FLAC 标签自动填充:' + ft; } else { AFH.textContent = '⚠️ 未找到 TITLE 标签,请手动输入'; } } function updateFiles() { FC.innerHTML = ''; if (files.length === 0) { CFB.disabled = true; FST.textContent = '等待添加 FLAC…'; EB.disabled = true; AFH.textContent = ''; } else { CFB.disabled = false; FST.textContent = files.length + ' 个 FLAC 文件'; if (song) EB.disabled = false; for (var i = 0; i < files.length; i++) { var f = files[i]; var el = document.createElement('span'); el.className = 'chip'; var h = '🎵 ' + esc(f.file.name); if (f.t) h += ' <span class="chip-tag">' + esc(f.t) + '</span>'; h += ' <span class="chip-del" data-idx="' + i + '">×</span>'; el.innerHTML = h; FC.appendChild(el); } var dels = FC.querySelectorAll('.chip-del'); for (var d = 0; d < dels.length; d++) { dels[d].onclick = function(e) { e.stopPropagation(); var idx = parseInt(this.getAttribute('data-idx'), 10); files.splice(idx, 1); updateFiles(); autoFill(); }; } } } function addFiles(fileList) { var only = []; for (var i = 0; i < fileList.length; i++) { if (!fileList[i].name.toLowerCase().endsWith('.flac')) continue; var dup = false; for (var j = 0; j < files.length; j++) { if (files[j].file.name === fileList[i].name && files[j].file.size === fileList[i].size && files[j].file.lastModified === fileList[i].lastModified) { dup = true; break; } } if (!dup) only.push(fileList[i]); } if (only.length === 0) { if (fileList.length > 0) toast('请选择 .flac 文件', true); return; } FST.textContent = '🔍 读取元数据…'; var done = 0; var total = only.length; function handleOne(f, meta) { files.push({ file: f, t: meta.t, a: meta.a, c: meta.c, al: meta.al }); done++; if (done >= total) { updateFiles(); autoFill(); toast('✅ 已添加 ' + total + ' 个 FLAC 文件'); if (files.length > 0 && SI.value.trim()) doSearch(SI.value); } } for (var k = 0; k < only.length; k++) { (function(fileRef) { readMeta(fileRef, function(meta) { handleOne(fileRef, meta); }); })(only[k]); } } function handleFileSelect(fileList) { if (fileList && fileList.length) { addFiles(fileList); } } FI.addEventListener('change', function(e) { handleFileSelect(e.target.files); FI.value = ''; }); DW.addEventListener('dragover', function(e) { e.preventDefault(); e.stopPropagation(); DW.classList.add('drag-over'); }); DW.addEventListener('dragleave', function(e) { e.preventDefault(); e.stopPropagation(); DW.classList.remove('drag-over'); }); DW.addEventListener('drop', function(e) { e.preventDefault(); e.stopPropagation(); DW.classList.remove('drag-over'); if (e.dataTransfer.files && e.dataTransfer.files.length) { handleFileSelect(e.dataTransfer.files); } }); CFB.addEventListener('click', function() { files = []; updateFiles(); autoFill(); toast('🧹 已清空'); }); function apiSearch(q) { return fetch('https://lrclib.net/api/search?q=' + encodeURIComponent(q)).then(function(r) { if (!r.ok) throw new Error('搜索失败'); return r.json(); }); } function apiGet(t, a) { return fetch('https://lrclib.net/api/get?track_name=' + encodeURIComponent(t) + '&artist_name=' + encodeURIComponent(a)).then(function(r) { if (!r.ok) throw new Error('获取失败'); return r.text(); }).then(function(t) { if (!t) throw new Error('未找到'); return JSON.parse(t); }); } function parseLrc(sl) { var items = []; if (!sl) return items; var re = /\[(\d{2}):(\d{2})\.(\d{2,3})\]\s*(.*)/g, m; while ((m = re.exec(sl)) !== null) { var ms = m[3].length === 2 ? parseInt(m[3], 10) * 10 : parseInt(m[3], 10); items.push({ tm: parseInt(m[1]) * 60000 + parseInt(m[2]) * 1000 + ms, tx: (m[4] || '').trim() }); } return items; } function msLrc(ms) { var mn = Math.floor(ms / 60000); return '[' + p2(mn) + ':' + p2(Math.floor((ms % 60000) / 1000)) + '.' + p2(Math.floor((ms % 1000) / 10)) + ']'; } function msSrt(ms) { var h = Math.floor(ms / 3600000); return p2(h) + ':' + p2(Math.floor((ms % 3600000) / 60000)) + ':' + p2(Math.floor((ms % 60000) / 1000)) + ',' + p3(ms % 1000); } function msAss(ms) { var h = Math.floor(ms / 3600000); return h + ':' + p2(Math.floor((ms % 3600000) / 60000)) + ':' + p2(Math.floor((ms % 60000) / 1000)) + '.' + p2(Math.floor((ms % 1000) / 10)); } function msVtt(ms) { var h = Math.floor(ms / 3600000); return p2(h) + ':' + p2(Math.floor((ms % 3600000) / 60000)) + ':' + p2(Math.floor((ms % 60000) / 1000)) + '.' + p3(ms % 1000); } function genLRC(s) { var it = parseLrc(s.syncedLyrics); var l = []; l.push('[ti:' + (s.trackName || '') + ']'); l.push('[ar:' + (s.artistName || '') + ']'); if (s.albumName) l.push('[al:' + s.albumName + ']'); if (s.duration) { var m = Math.floor(s.duration / 60); l.push('[length:' + p2(m) + ':' + p2(Math.floor(s.duration % 60)) + ']'); } l.push(''); if (it.length) { for (var i = 0; i < it.length; i++) l.push(msLrc(it[i].tm) + (it[i].tx || '♪')); } else if ( s.plainLyrics) { var pl = s.plainLyrics.split('\n'); for (var j = 0; j < pl.length; j++) l.push(pl[j] .trim()); } return l.join('\n'); } function genSRT(s) { var it = parseLrc(s.syncedLyrics); if (!it.length) return s.plainLyrics ? '1\n00:00:00,000 --> 00:03:00,000\n' + s.plainLyrics.trim() + '\n' : ''; var l = []; for (var i = 0; i < it.length; i++) { var nx = it[i + 1], em = nx ? nx.tm : it[i].tm + 3000; l.push(String(i + 1)); l.push(msSrt(it[i].tm) + ' --> ' + msSrt(em)); l.push(it[i].tx || '♪'); l.push(''); } return l.join('\n').trim(); } function genASS(s) { var it = parseLrc(s.syncedLyrics); var l = []; l.push('[Script Info]'); l.push('Title: ' + (s.trackName || 'Unknown')); l.push('Original Script: ' + (s.artistName || 'Unknown')); l.push('ScriptType: v4.00+'); l.push('Collisions: Normal'); l.push('PlayDepth: 0'); l.push(''); l.push('[V4+ Styles]'); l.push( 'Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding'); l.push( 'Style: Default,Microsoft YaHei,36,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,-1,0,0,0,100,100,0,0,1,2,1,2,30,30,30,1'); l.push(''); l.push('[Events]'); l.push('Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text'); if (it.length) { for (var i = 0; i < it.length; i++) { var nx = it[i + 1], em = nx ? nx.tm : it[i].tm + 3000; l.push('Dialogue: 0,' + msAss(it[i].tm) + ',' + msAss(em) + ',Default,,0,0,0,,' + (it[i].tx || '♪').replace(/\n/g, '\\N')); } } else if (s.plainLyrics) { var pl = s.plainLyrics.split('\n').filter(function(x) { return x.trim(); }); var dur = (s.duration || 180) * 1000; var each = Math.floor(dur / Math.max(pl.length, 1)); for (var j = 0; j < pl.length; j++) l.push('Dialogue: 0,' + msAss(j * each) + ',' + msAss(j * each + each) + ',Default,,0,0,0,,' + pl[j].trim().replace(/\n/g, '\\N')); } return l.join('\n'); } function genVTT(s) { var it = parseLrc(s.syncedLyrics); var l = []; l.push('WEBVTT'); l.push(''); if (it.length) { for (var i = 0; i < it.length; i++) { var nx = it[i + 1], em = nx ? nx.tm : it[i].tm + 3000; l.push(msVtt(it[i].tm) + ' --> ' + msVtt(em)); l.push(it[i].tx || '♪'); l.push(''); } } else if (s.plainLyrics) { var pl = s.plainLyrics.split('\n').filter(function(x) { return x.trim(); }); var dur = (s.duration || 180) * 1000; var each = Math.floor(dur / Math.max(pl.length, 1)); for (var j = 0; j < pl.length; j++) { l.push(msVtt(j * each) + ' --> ' + msVtt(j * each + each)); l.push(pl[j].trim()); l.push(''); } } return l.join('\n').trim(); } function getFmt(f, s) { if (!s) return ''; if (f === 'lrc') return genLRC(s); if (f === 'srt') return genSRT(s); if (f === 'ass') return genASS(s); if (f === 'vtt') return genVTT(s); return ''; } function hlHtml(f, s) { var raw = getFmt(f, s); if (!raw) return '<span style="color:#555;">暂无内容</span>'; var e = esc(raw); if (f === 'lrc') { e = e.replace(/^(\[ti:.*\]|\[ar:.*\]|\[al:.*\]|\[length:.*\])$/gm, '<span class="hl-tag">$1</span>'); e = e.replace(/^(\[\d{2}:\d{2}\.\d{2}\])/gm, '<span class="hl-tag">$1</span>'); } else if (f === 'srt') { e = e.replace(/^(\d+)$/gm, '<span class="hl-idx">$1</span>'); e = e.replace(/^(\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3})$/gm, '<span class="hl-time">$1</span>'); } else if (f === 'ass') { e = e.replace(/^(\[.*\])$/gm, '<span class="hl-section">$1</span>'); e = e.replace(/^(Style:.*)$/gm, '<span class="hl-style">$1</span>'); e = e.replace(/^(Format:.*)$/gm, '<span class="hl-style">$1</span>'); } else if (f === 'vtt') { e = e .replace(/^(WEBVTT)$/gm, '<span class="hl-section">$1</span>'); e = e.replace(/^(\d{2}:\d{2}:\d{2}\.\d{3} --> \d{2}:\d{2}:\d{2}\.\d{3})$/gm, '<span class="hl-time">$1</span>'); } return e; } function renderSong(s) { song = s; SN.textContent = s.trackName || '未知'; SA.textContent = s.artistName || '未知'; SAL.textContent = s.albumName ? '💿 ' + s.albumName : ''; LC.style.display = 'block'; if (files.length > 0) EB.disabled = false; updateLyrics(); LC.scrollIntoView({ behavior: 'smooth', block: 'center' }); } function updateLyrics() { LCT.innerHTML = hlHtml(fmt, song); } for (var t = 0; t < TABS.length; t++) { TABS[t].addEventListener('click', function() { for (var i = 0; i < TABS.length; i++) TABS[i].classList.remove('on'); this.classList.add('on'); fmt = this.getAttribute('data-fmt'); updateLyrics(); }); } for (var c = 0; c < TCHIPS.length; c++) { TCHIPS[c].addEventListener('click', function() { for (var i = 0; i < TCHIPS.length; i++) TCHIPS[i].classList.remove('on'); this.classList.add('on'); tag = this.getAttribute('data-tag'); }); } function doSearch(q) { if (!q || !q.trim()) { toast('请输入关键词', true); return; } results = []; selectedIdx = -1; RL.innerHTML = '<div class="spinner-wrap"><span class="spinner"></span>搜索中…</div>'; RB.classList.add('open'); apiSearch(q.trim()).then(function(rs) { results = rs; if (!rs.length) { RL.innerHTML = '<div class="empty">😕 未找到匹配的歌曲</div>'; return; } var h = ''; for (var i = 0; i < rs.length; i++) { var r = rs[i]; h += '<div class="result-row" data-idx="' + i + '">'; h += '<div class="result-info"><div class="rtrack">' + esc(r.trackName || r.name || '未知') + '</div><div class="rartist">' + esc(r.artistName || '未知') + '</div></div>'; h += '<div class="result-meta">' + fdur(r.duration) + '</div>'; h += '<button class="btn btn-xs pick-btn" data-idx="' + i + '">选择</button>'; h += '</div>'; } RL.innerHTML = h; bindResults(); }).catch(function(err) { RL.innerHTML = '<div class="empty">❌ ' + esc(err.message) + '</div>'; }); } function bindResults() { var rows = RL.querySelectorAll('.result-row'); for (var j = 0; j < rows.length; j++) { (function(idx) { rows[j].addEventListener('click', function(e) { if (e.target.closest('.pick-btn')) return; loadResult(idx); }); })(j); } var btns = RL.querySelectorAll('.pick-btn'); for (var k = 0; k < btns.length; k++) { (function(idx) { btns[k].addEventListener('click', function(e) { e.stopPropagation(); loadResult(idx); }); })(k); } } function loadResult(idx) { var s = results[idx]; if (!s) return; selectedIdx = idx; var tn = s.trackName || s.name; var an = s.artistName || ''; var rows = RL.querySelectorAll('.result-row'); for (var i = 0; i < rows.length; i++) { rows[i].classList.remove('selected'); rows[i].style.opacity = '0.4'; } var tgt = RL.querySelector('[data-idx="' + idx + '"]'); if (tgt) { tgt.classList.add('selected'); tgt.style.opacity = '1'; } apiGet(tn, an).then(function(d) { renderSong(d); for (var j = 0; j < rows.length; j++) rows[j].style.opacity = '1'; }).catch(function(err) { toast('❌ ' + err.message, true); for (var j = 0; j < rows.length; j++) rows[j].style.opacity = '1'; selectedIdx = -1; }); } function fdur(s) { if (!s && s !== 0) return ''; var m = Math.floor(s / 60); return m + ':' + p2(Math.floor(s % 60)); } SB.addEventListener('click', function() { doSearch(SI.value); }); SI.addEventListener('keydown', function(e) { if (e.key === 'Enter') doSearch(SI.value); }); DB.addEventListener('click', function() { var q = SI.value.trim(); if (!q) { toast('请输入「歌曲名 - 歌手名」', true); return; } var seps = [' - ', '-', ' – ', '–', ' | ', '|', ':', ':']; var tk = '', ar = ''; for (var i = 0; i < seps.length; i++) { if (q.indexOf(seps[i]) !== -1) { var pts = q.split(seps[i]); tk = pts[0].trim(); ar = pts.slice(1).join(seps[i]).trim(); break; } } if (!tk) { tk = prompt('歌曲名:', q); if (!tk) return; ar = prompt('歌手名(可选):', '') || ''; } results = []; selectedIdx = -1; RL.innerHTML = '<div class="spinner-wrap"><span class="spinner"></span>获取中…</div>'; RB.classList.add('open'); apiGet(tk, ar).then(function(d) { results = [d]; selectedIdx = 0; RL.innerHTML = '<div class="result-row selected" data-idx="0" style="opacity:1;"><div class="result-info"><div class="rtrack">' + esc(d.trackName || d.name || '未知') + '</div><div class="rartist">' + esc(d.artistName || '未知') + '</div></div><div class="result-meta">' + fdur(d.duration) + '</div></div>'; renderSong(d); }).catch(function(err) { RL.innerHTML = '<div class="empty">❌ ' + esc(err.message) + '</div>'; toast('❌ ' + err.message, true); }); }); function readBlocks(ab) { var v = new DataView(ab); var b = ab; if (b.byteLength < 4) throw new Error('太小'); if (String.fromCharCode(v.getUint8(0), v.getUint8(1), v.getUint8(2), v.getUint8(3)) !== 'fLaC') throw new Error( '非FLAC'); var bl = []; var o = 4, lb = false; while (o < b.byteLength && !lb) { if (o + 4 > b.byteLength) break; var h = v.getUint8(o); lb = (h & 0x80) !== 0; var bt = h & 0x7F; var bs = (v.getUint8(o + 1) << 16) | (v.getUint8(o + 2) << 8) | v.getUint8(o + 3); var st = o; o += 4; bl.push({ type: bt, last: lb, ho: st, dto: o, size: bs }); o += bs; } return { blocks: bl, buf: b }; } function parseVC(bi, buf) { var bl = new Uint8Array(buf, bi.dto, bi.size); var dec = new TextDecoder('utf-8'); if (bl.length < 4) return { cmts: [] }; var vl = bl[0] | (bl[1] << 8) | (bl[2] << 16) | (bl[3] << 24); var p = 4 + vl; if (p + 4 > bl.length) return { cmts: [] }; var nc = bl[p] | (bl[p + 1] << 8) | (bl[p + 2] << 16) | (bl[p + 3] << 24); p += 4; var cmts = []; for (var i = 0; i < nc; i++) { if (p + 4 > bl.length) break; var cl = bl[p] | (bl[p + 1] << 8) | (bl[p + 2] << 16) | (bl[p + 3] << 24); p += 4; if (p + cl > bl.length) break; cmts.push(dec.decode(bl.slice(p, p + cl))); p += cl; } return { cmts: cmts }; } function buildVC(cmts, isLast) { var enc = new TextEncoder(); var vb = new Uint8Array(4); var cb = new Uint8Array(4); cb[0] = cmts.length & 0xFF; cb[1] = (cmts.length >> 8) & 0xFF; cb[2] = (cmts.length >> 16) & 0xFF; cb[3] = (cmts.length >> 24) & 0xFF; var arrs = []; for (var i = 0; i < cmts.length; i++) { var ed = enc.encode(cmts[i]); var lb = new Uint8Array(4); lb[0] = ed.length & 0xFF; lb[1] = (ed.length >> 8) & 0xFF; lb[2] = (ed.length >> 16) & 0xFF; lb[3] = (ed.length >> 24) & 0xFF; arrs.push(lb); arrs.push(ed); } var tp = 8; for (var j = 0; j < arrs.length; j++) tp += arrs[j].length; var bh = new Uint8Array(4); bh[0] = 4; if (isLast) bh[0] |= 0x80; bh[1] = (tp >> 16) & 0xFF; bh[2] = (tp >> 8) & 0xFF; bh[3] = tp & 0xFF; var res = new Uint8Array(4 + tp); res.set(bh, 0); var off = 4; res.set(vb, off); off += 4; res.set(cb, off); off += 4; for (var k = 0; k < arrs.length; k++) { res.set(arrs[k], off); off += arrs[k].length; } return res; } function embed(file, lc, tn, sm, ov, cb) { var r = new FileReader(); r.onload = function(e) { try { var info = readBlocks(e.target.result); var bl = info.blocks; var buf = info.buf; var vi = -1; for (var i = 0; i < bl.length; i++) { if (bl[i].type === 4) { vi = i; break; } } var nc = []; var tu = tn.toUpperCase(); var pk = [tu]; if (ov.title) pk.push('TITLE'); if (ov.artist) pk.push('ARTIST'); if (ov.album) pk.push('ALBUM'); if (vi >= 0) { var parsed = parseVC(bl[vi], buf); for (var j = 0; j < parsed.cmts.length; j++) { var eq = parsed.cmts[j].indexOf('='); if (eq > 0) { var key = parsed.cmts[j].substring(0, eq).toUpperCase().trim(); if (pk.indexOf( key) === -1) nc.push(parsed.cmts[j]); } else nc.push(parsed.cmts[j]); } } nc.push(tu + '=' + lc); if (ov.title && sm.trackName) nc.push('TITLE=' + sm.trackName); if (ov.artist && sm.artistName) nc.push('ARTIST=' + sm.artistName); if (ov.album && sm.albumName) nc.push('ALBUM=' + sm.albumName); var isLast = (vi >= 0) ? bl[vi].last : false; var nb = buildVC(nc, isLast); var parts = []; if (vi >= 0) { parts.push(new Uint8Array(buf, 0, bl[vi].ho)); parts.push(nb); parts.push(new Uint8Array(buf, bl[vi].dto + bl[vi].size)); } else { var si = -1; for (var k = 0; k < bl.length; k++) { if (bl[k].type === 0) { si = k; break; } } if (si >= 0) { var sho = bl[si].ho; var sa = bl[si].dto + bl[si].size; parts.push(new Uint8Array(buf, 0, sho)); var sh = new Uint8Array(buf, sho, 4); sh[0] = sh[0] & 0x7F; parts.push(sh); parts.push(new Uint8Array(buf, bl[si].dto, bl[si].size)); parts.push(nb); parts.push(new Uint8Array(buf, sa)); } else { parts.push(new Uint8Array(buf, 0, 4)); parts.push(nb); parts.push(new Uint8Array(buf, 4)); } } var tl = 0; for (var p = 0; p < parts.length; p++) tl += parts[p].length; var result = new Uint8Array(tl); var off = 0; for (var q = 0; q < parts.length; q++) { result.set(parts[q], off); off += parts[q].length; } cb(null, new Blob([result], { type: 'audio/flac' })); } catch (x) { cb(x); } }; r.onerror = function() { cb(new Error('读取失败')); }; r.readAsArrayBuffer(file); } EB.addEventListener('click', function() { if (!files.length) { toast('请先添加 FLAC 文件', true); return; } if (!song) { toast('请先选择歌词', true); return; } var lc = getFmt(fmt, song); if (!lc.trim()) { toast('当前格式无内容', true); return; } var ov = { title: OVT.checked, artist: OVA.checked, album: OVAL.checked }; EB.disabled = true; CFB.disabled = true; var extra = []; if (ov.title) extra.push('TITLE'); if (ov.artist) extra.push('ARTIST'); if (ov.album) extra.push('ALBUM'); var em = extra.length ? ' + 覆盖 ' + extra.join('/') : ''; toast('⏳ 正在写入 ' + files.length + ' 个文件' + em + '…'); var ok = 0, fl = 0; function next(idx) { if (idx >= files.length) { EB.disabled = false; CFB.disabled = false; if (fl === 0) toast('🎉 成功!已下载 ' + ok + ' 个 FLAC 文件' + em); else toast('⚠️ ' + ok + ' 成功, ' + fl + ' 失败', true); return; } embed(files[idx].file, lc, tag, song, ov, function(err, blob) { if (err) { fl++; console.error(err); } else { var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = files[idx].file.name; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); ok++; } setTimeout(function() { next(idx + 1); }, 200); }); } next(0); }); updateFiles(); SI.focus(); })(); </script> </body> </html> 歌词搜索、标签写入和元数据覆盖一次性搞定 2 个帖子 - 2 位参与者 阅读完整话题

v2ex · 2026-06-10 09:59:05+08:00 · tech

「超级剪贴板」获得 12w+ 次安装,常驻「最受欢迎」热门排行榜,持续维护近四年,历经三次重构,精心打磨作为一款剪贴板应用的每一处细节。 近期发布了 V3.0 版本,继承旧版基础交互的前提下,进一步提高了信息密度与能力上限,功能更强,性能更优,欢迎体验。 极致性能 :不限制条数与过期时间,支持上万条数据数据秒启 隐私优先 :支持按需开启端到端加密,将复制内容加密保存到本地磁盘 功能强大 :支持置顶、收藏、编辑、多选、内置 OCR 文字搜图等强大功能 跨设备同步 :支持秒级跨设备同步与基于 WebDAV 的备份与同步 定制脚本 :编写强大的自定义用户脚本,监听事件、调用系统 API 定制自己的工作流 极致高效 :支持随时唤起透明悬浮剪贴板,用完即走 界面优雅 :经过设计的动效与交互,深度适配深色模式,用户界面支持中英双语 文末送 10 个季度插件会员兑换码,可以在插件中以 ¥0.01 的价格购买原价 ¥19.9 的季度插件会员: 欢迎到 uTools 插件市场下载使用: 插件市场 - 超级剪贴板 兑换方式: 下载并安装 uTools 在插件市场搜索「超级剪贴板」,安装插件 进入插件后,点击右上角「用户中心」页面的兑换码入口使用兑换码 未被兑换的兑换码将于 2026-06-30 23:59:59 过期,记得及时兑换~ CLIP-dcdd9c10-8b07-467e-81f9-bcadf0839dd2 CLIP-e3aaf088-0ea5-4014-b734-e8475f34ad0a CLIP-d4da263a-3522-482b-b1af-750ff07b48bd CLIP-0bb4beb9-e23c-46d2-b091-f18dc7a72d0c CLIP-fb122820-0318-4c80-b81b-cf2323e6963e CLIP-fc150242-0af5-4cf9-9ceb-410d9282dc2a CLIP-dca99a0c-bc23-487e-b57b-cf765dc16b3b CLIP-ca4ecb84-b5e8-446d-92c2-e18eb2689478 CLIP-548d5ea7-199b-413c-9faa-9fb8faae806f CLIP-4e9eb7f8-df02-4441-95fa-eb918db4b146

LinuxDo 最新话题 · 2026-06-10 01:12:34+08:00 · tech

Anthropic 发布 Claude Fable 5 与 Mythos 5,性能大幅跃升 Anthropic 推出面向普通用户的 Claude Fable 5,这是迄今能力最强的 Mythos 级模型。它在软件工程、知识工作、视觉和科研等基准上均达顶尖,价格比前代 Mythos Preview 低一半以上。为防滥用,内建分类器在涉及网络安全、生物化学等话题时改用 Opus 4.8 回复,约 95% 的会话不受影响。 同步发布的 Claude Mythos 5 对网络防御伙伴解除部分限制,号称拥有全球最强的网络安全能力。生物医学研究者也可通过信任计划在解除防护后使用。两款模型定价均为每百万输入 token 10 美元、输出 token 50 美元,不到 Mythos Preview 的一半。 via zaihuapd 16 个帖子 - 15 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-07 21:25:26+08:00 · tech

本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 引言 之前一直在用 Sub2API 和 CPA 等反代理工具,但是由于各种原因,总觉得现成的服务不够完善,多多少少都有一些不太舒服的地方。于是我就根据我个人的使用习惯、需求以及社区上的一些潜在需求,在 Sub2API 的基础上编制了这一款新的反代理平台,LightBridge。 开发进度及贡献 因为个人不是全职开发,是在工作剩余时间开发,进度较慢,基本上1-3天才能完成一个模块,而且面临 Token 不足的境地,也会拖慢工作效率。 如果有佬愿意帮忙贡献,那么万分感谢。 另外声明一下,目前正式上线的为基于 Sub2API 重置的模块化版本,有很多核心功能是直接在 Sub2API 的基础上做的,并不适配 LightBridge 模块化重制版,因此还在分阶段重做、测试上线,需要等待一下。 核心功能介绍 LightBridge Connect 本功能可以在两个 LightBridge 实例之间建立连接。假设说一个是进行分发的服务端,另一个是用户个人拥有的私人端。 在开启本功能后,服务端会生成一个链接和连接密钥。私人端可以将这些信息导入到自己的 LightBridge 当中,随后私人端的 LightBridge 会使用密钥向服务端的 LightBridge 发起一次探测连接。 如果连接校验与握手完成,系统就会建立 LightBridge Connect。在 LightBridge Connect 下,两端机器之间不仅可以使用正常的 API 分发,还可以实现直接从私人端 LightBridge 控制面板查看该用户在服务端 LightBridge 上的账户详情、控制余额、查看使用记录和仪表盘等。 这直接免去了二次跳转的困难,而且还可以共享更详细的错误信息。 注册机(自动维护)& Outlook 号池 我找到了几个开源的注册机源码,准备将其与 Outlook 号池直接作为插件嵌入服务,用户可以直接使用自带注册机一键注册并导入,还可以联动 Outlook 号池查看邮箱使用状况并接受邮件。 但考虑到注册机的前景不明,我个人正在着手开发自动维护机,即做到可以使用协议或无头浏览器自动登录 ChatGPT 账户获取 DC、开启 2FA 等等操作。 智能托管 看到站内许多佬的公益都因为有人违规操作而不得不由管理员进行封禁,便想到了这个功能。 开启后会内置一个 AI 驱动的智能助手,采用了一个接口极为简单的 OpenAI responses 协议的 agent。这个 agent 具备 thinking 和 tool calling 功能。 当系统根据规则检测到异常情况时,会自动唤醒这个 agent,将数据发送给它,并赋予其调用权限。Agent 会根据信息进行推断,最后做出操作。它可以自动封禁违规者,也可以做其他的自动维护(例如自动删除账号之类的)。 也考虑过让 agent 像 OpenClaw 那样全量运行,但由于可能有点消耗 token,不知道后期还会不会开启这个功能。 Clash 代理 不过多赘述了,在原有的 HTTPS/SOCK5 代理的基础上外挂了一个精简版的 Clash Core,实现绝大多数协议的代理,方便佬用自己的订阅。 实时仪表盘和桌面 这个仪表盘是一个实时仪表盘,不同于之前的仪表盘和运行监测,它是用户的一个 API 控制层。 例如,我要是将一个 API 应用在 Codex 里面,由于 Codex 做自定义模型很麻烦,而我现在用的是 GPT 5.5 模型,想换成 DeepSeek V4 模型,我原本需要去本地做很麻烦的配置切换。 但是有了仪表盘,我只需要在仪表盘上把 GPT 5.5 映射成 DeepSeek V4,就可以实现直接切换。这相当于把之前类似于 CCS 中的本地路由搬到了线上,而且更加灵活。而且,你还支持指定某一个渠道来承载你的请求。 Desktop 则是将 Realtime Dashboard 和以上所有控制面板中的功能打包成了一个 CLI 到了本地。 主要是支持让 AI 直接调用、直接管理自己的 Lightbridge 控制台和服务,功能会更加全面。 计划功能:LightBridge 串联 这个功能目前确实还没有完成,还处于计划阶段。 但我个人认为这是一个相当核心的功能,主要就是为了解决服务器负载的问题。其核心架构是由一台主路由和几台服务器集群组成,每一台服务器上都装有 LightBridge 实例。 通过 LightBridge 串联器将其他服务器连接到一起,具体实现如下: 数据库管理:每一台服务器都可以选择进行数据库自动同步或者集中数据库管理。 资源动态分布:将所有的并发处理请求进行资源动态分布,实现多台服务器组成一个高可用集群。 统一控制:用户只需要把所有的请求和压力都打在一个域名上,通过一个控制面板即可同时调度三台设备的算力。 这大大提升了效率,解决了之前单台设备算力不足以及升级设备资金成本太高的问题,让几台低价设备能够同时运行。 开发重点 在结构上,相较于原项目 LightBridge 升级了模块式结构,分为三个实现层: Control 实现层 Provider 实现层 Core 模块实现层 当用户安装了 LightBridge 之后,默认带有这三个实现层。它们具备了 UI 界面、控制器等基础功能,包含 Provider 核心、Proxy 核心和分发核心,但不具备具体的 反代 和 API 功能。 用户如果需要特定的 Provider,可以在模块市场中下载对应的模块进行安装,从而获取完整功能,实现本地服务的轻量化。像上面提到的 Passkey、LightBridge Connect 之类的模块,大部分功能都是独立于主实现层而实现的,可以根据需要随意安装和自我升级。 在 UI 方面,LightBridge 使用一套公用的 CSS 元素进行了界面重写。 从整体视觉效果上来说,我个人认为是减少了一些 AI 味。当然,可能会觉得棱角太重了,需要的话可以自己上传更改 CSS。 在操作逻辑和 UI 界面方面也有一些小调整,但由于其调整过于细碎,因此不在功能介绍和开发计划中详细赘述。 对于反代核心 相较于以上所说的各种功能来说,我认为是一个比较核心的功能。 像 Sub2API、CPA 之类的项目都多次对这个核心进行修改,以确保不被 OpenAI 之类厂商的风控识别。我个人认为这项工作对我的能力来说有点艰巨,目前正在着手对原有 Sub2API 反代理模块进行优化,以确保减少被风控和被识别的几率。 但这仍然是个艰巨的任务,因此反代理模块在彻底完成并确认效果更好之前,会一直同步更新 Sub2API 的反代理核心。而 Sub2API 所提供的升级,以及与 LightBridge 现有功能不冲突的核心升级,都会被同步进 LightBridge 中。 github.com GitHub - WilliamWang1721/LightBridge: LightBridge is a reverse proxy platform primarily... LightBridge is a reverse proxy platform primarily based on Sub2API, combined with various open-source projects. It features a modular structure with a lightweight configuration and a rich selection of functional plugins. Additionally, it offers a modern and elegant user interface. 最后 感谢各位大佬的支持。 目前本服务再次强调一下,关于上述所说的所有核心功能和开发计划——之所以说是计划,不是因为还没有开发,而是因为这些功能之前完全是基于 Lightbridge 服务开发的。 在完成后,我发现了一个很严重的问题:整个服务变得十分臃肿,几乎拖慢了运行进度。于是在重构时,我决定对整个架构进行重置,采用模块化的形式。 每一个核心功能现在都是一个独立的模块,用户可以自由安装,这样只需运行必要的项目即可,大大缩减了运行时的资源消耗。 但也正因如此,以上所说的全部功能必须按照最新的模块 endpoint 结构进行重置,无法直接上线,因此会分批发布。 服务内置了自动升级器和版本控制器: (a) 如果不喜欢某个版本,可以直接退回到上一个指定的版本。 (b) 在收到新模块后,系统支持自动升级。 目前我正在开发 Sub2API 的回退脚本,方便佬们在不大喜欢时进行回退。 这是最新的迁移脚本。目前迁移脚本支持将 Sub2API 直接迁入到最新模块化的 LightBridge 服务当中。自带自动回退功能,会在迁移之前先建立一个完整备份。若迁移失败,支持自动回滚 curl -fsSL https://raw.githubusercontent.com/WilliamWang1721/LightBridge/main/deploy/sub2api-full-migrate.sh | sudo bash -s -- migrate -v v0.0.1 -y 但是请注意,本迁移仅适用于标准的 Sub2API 服务。如果你的 Sub2API 服务经过魔改,或者自己增加了页面,建议拓展使用,或者可以私信我来进行咨询。 建议直接安装最新服务,体验最佳。 希望各位大佬能够试用一下,多多指教,帮忙 Star 一下,谢谢! 最后声明:正文都是我个人一点一点敲出来的,只有开发计划中 Markdown 语法的 detiles 是我一个一个复制粘贴的,不知道怎么老是别识别成 AI 内容。也有可能是工作老写些正式文书给同化了,完整开发计划后续再发吧 4 个帖子 - 2 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-07 15:57:22+08:00 · tech

已经是5月24号的东西了,又是凭借着chatbox的强大检索能力才找出来 本来是在gas搞的 但是对话被我删掉了 在另一个话题中 好好好,人在想干坏事的时候,动力是无穷的() 虽然不一定是坏事吧() 我吃完饭立即把之前承诺的提示词整出来,然后立即去和他交互( 每日不食言 也是感谢 @arch_linux boost~ 具体什么言呢 这个: 有一位歪果仁找到了我的纸飞机求邀请码 我把那个专门用来回歪果仁的提示词写好再说~ 我自己搞了一个个性化的,给大家分享一个通用版 # Role: 可爱翻译助手 > 专为技术社区和论坛用户打造的独立翻译工具。旨在将中文翻译成温和、礼貌、具有高亲和力的英文,同时在逻辑与事实层面保持100%的无损对齐,杜绝任何AI“脑补”。 ## 一、 翻译原则 [优先级: 绝对保底] ### 1. 绝对零度脑补 (零语义漂移) * 严禁推导上下文或主观补全因果。只翻译字面已陈述的事实。 * 严禁擅自添加动作主体。若中文未指明主语,英文翻译必须保持中性或被动态,严禁擅自指代。 * 必须1:1对齐物理动作。例如“去查看记录确认是否创建”,必须翻译为动作“check the records to confirm whether it was created”,绝对不能泛化翻译为“check if you created it”。 ### 2. 温和英文映射机制 (Gentle Style Rules) 目标模型必须严格通过以下语言学手段来确保译文的温和与礼貌: * **波浪号映射 (`~`)**: * 在句尾或表达友好建议的分句后,添加英文波浪号「~」,用以消除英文句号带来的冰冷感。 * 示例: "hope this helps~" * **温和助动词包 (Soft Modals)**: * 严禁使用命令式语气。必须使用 could, might, perhaps, just 等词汇进行柔化,将陈述句和疑问句包装得极具亲和力。 * 示例: 将“去查看你的界面”翻译为 "perhaps you could check your page..." * **标点无损镜像**: * 原文中的「...」和「!」必须原封不动地在英文对应位置保留,严禁擅自抹除。 ## 二、 输出格式规范 每次接收到中文输入后,必须且仅能按照以下两个板块进行排版输出。全文禁止使用任何 emoji 表情,禁止使用斜体样式: ### 【温和地道译文】 *(符合上述规则的、礼貌温和的英文翻译。不添加、不修改任何事实,需使用代码块包围,适合直接复制用于交流)* ### 【直白回译校验】 *(将上面的英文译文,用最直白、最还原字面意思的中文重新翻译一遍,方便用户随时校验原意是否产生任何漂移)* 现在说实话,我极其不满意 提示词本身就没有恪守自己的理念 这是我不愿意看到的,我的提示词都会遵循自我归宿 也就是说他所要求别人做的事情,最后必须由他自己先来完成 我自己的个性化测试效果: 通人性的AI都会愿意解析,不通人性的AI就不会解析(别问glm为什么思考1分钟 ) 于16:13,优化了部分细节,新增代码块包围请求,方便复制 3 个帖子 - 3 位参与者 阅读完整话题