macOS 菜单栏歌词工具,读取波点音乐客户端本地歌曲缓存和日志,再请求歌词并显示当前歌词行。
波点歌词macOS 菜单栏歌词工具读取波点音乐客户端本地歌曲缓存和日志再请求歌词并显示当前歌词行。构建要求 macOS、Xcode Command Line Tools以及已安装并运行的波点音乐客户端。./build.shopenbuild/波点歌词.app也可以直接使用发布包中的波点歌词.app。说明支持 Apple Silicon 和 Intel Mac。不截取屏幕不需要辅助功能权限。只读取当前用户的波点音乐缓存目录。波点客户端的本地文件格式或歌词接口变化后工具可能需要调整。本项目与波点音乐及酷我音乐无隶属关系。请遵守相关服务条款和适用的版权规定。mportCocoaimportFoundationstructSong{letid:Stringletname:Stringletartist:Stringletstarted:Date}structLyricLine{lettime:TimeIntervallettext:String}finalclassAppDelegate:NSObject,NSApplicationDelegate{privatevaritem:NSStatusItem!privatevartimer:Timer!privatevarsongIDprivatevarlines:[LyricLine][]privatevarstartedDate()privatevarcacheRoot:String{NSHomeDirectory()/Library/Caches/cn.wenyu.bodian.bodianPc}funcapplicationDidFinishLaunching(_notification:Notification){NSApp.setActivationPolicy(.accessory)itemNSStatusBar.system.statusItem(withLength:NSStatusItem.variableLength)item.length240setTitle(波点歌词)letmenuNSMenu()menu.addItem(NSMenuItem(title:刷新歌词,action:#selector(refresh),keyEquivalent:r))menu.addItem(.separator())menu.addItem(NSMenuItem(title:退出,action:#selector(quit),keyEquivalent:q))item.menumenu timerTimer.scheduledTimer(timeInterval:1,target:self,selector:#selector(refresh),userInfo:nil,repeats:true)refresh()}objcprivatefuncrefresh(){guardletsongcurrentSong()else{setTitle(波点歌词)return}ifsong.id!songID{songIDsong.id startedsong.started lines[]fetchLyrics(song)}letelapsedDate().timeIntervalSince(started)letcurrentlines.last(where:{$0.timeelapsed})?.text??song.namesetTitle(current.isEmpty?song.name:current)}privatefuncsetTitle(_value:String){lettextvalue.replacingOccurrences(of:\n,with: ).trimmingCharacters(in:.whitespacesAndNewlines)item.button?.imagenilitem.button?.titletext item.button?.attributedTitleNSAttributedString(string:text,attributes:[.font:NSFont.systemFont(ofSize:13)])item.button?.toolTiptext}privatefunccurrentSong()-Song?{letpathcacheRoot/database/songDB.dbletpProcess()letoutPipe()p.executableURLURL(fileURLWithPath:/usr/bin/sqlite3)p.arguments[path,select id || | || json_extract(json, $.name) || | || json_extract(json, $.artist) || | || time from hist_song order by ord desc limit 1;]p.standardOutputouttry?p.run()p.waitUntilExit()guardletvalueString(data:out.fileHandleForReading.readDataToEndOfFile(),encoding:.utf8)else{returnnil}letpartsvalue.trimmingCharacters(in:.whitespacesAndNewlines).split(separator:|,maxSplits:3).map(String.init)letformatterDateFormatter()formatter.localeLocale(identifier:en_US_POSIX)formatter.dateFormatyyyy-MM-dd HH:mm:ss.SSSSSSguardparts.count4,letdateformatter.date(from:parts[3])else{returnnil}returnSong(id:parts[0],name:parts[1],artist:parts[2],started:date)}privatefuncfetchLyrics(_song:Song){letlogPathcacheRoot/bdlog/log_1.logguardletlogtry?String(contentsOfFile:logPath,encoding:.utf8),letlinelog.split(separator:\n).last(where:{$0.contains(uri: http://mlyric.kuwo.cn/mobi.s)}),leturlTextline.split(separator:uri: ,maxSplits:1).last,letoldURLURL(string:String(urlText).trimmingCharacters(in:.whitespacesAndNewlines)),letoldQueryURLComponents(url:oldURL,resolvingAgainstBaseURL:false)?.queryItems,letuidoldQuery.first(where:{$0.nameuid})?.value,lettokenoldQuery.first(where:{$0.nametoken})?.valueelse{return}letrawtypelyricreq2lrcx1rid\(song.id)songname\(song.name)artist\(song.artist)corpkuwofromchannelbodianletqData(raw.utf8).base64EncodedString()varcomponentsURLComponents(string:https://mlyric.kuwo.cn/mobi.s)!components.queryItems[URLQueryItem(name:f,value:bodian),URLQueryItem(name:q,value:q),URLQueryItem(name:uid,value:uid),URLQueryItem(name:token,value:token)]guardleturlcomponents.urlelse{return}URLSession.shared.dataTask(with:url){[weakself]data,_,_inguardletdata,letjsontry?JSONSerialization.jsonObject(with:data)as?[String:Any],letpayloadjson[data]as?[String:Any],letencodedpayload[content]as?String,letlyricDataData(base64Encoded:encoded),letlyricString(data:lyricData,encoding:.utf8)else{return}letparsedlyric.split(separator:\n).compactMap{line-LyricLine?inletsString(line)guardletmatchs.range(of:#\[(\d):(\d(?:\.\d)?)\](.*)#,options:.regularExpression)else{returnnil}letpartss[match].dropFirst().split(separator:],maxSplits:1).map(String.init)guardparts.count2else{returnnil}letclockparts[0].split(separator::).map(String.init)guardclock.count2,letminDouble(clock[0]),letsecDouble(clock[1])else{returnnil}lettextparts[1].replacingOccurrences(of:#[-0-9],[-0-9]#,with:,options:.regularExpression).trimmingCharacters(in:.whitespaces)returnLyricLine(time:min*60sec,text:text)}DispatchQueue.main.async{self?.linesparsed}}.resume()}objcprivatefuncquit(){NSApp.terminate(nil)}}letappNSApplication.sharedletdelegateAppDelegate()app.delegatedelegate app.run()俺还不会贴app。。网盘分享了通过网盘分享的文件软件包相关.zip链接: https://pan.baidu.com/s/1ojUcjMpIeCyyZ77RxmsGFQ?pwdcu9x 提取码: cu9x 复制这段内容后打开百度网盘手机App操作更方便哦

相关新闻

深入解析ADS7851EVM-PDK:从SAR ADC评估到高速数据采集系统设计

深入解析ADS7851EVM-PDK:从SAR ADC评估到高速数据采集系统设计

1. 项目概述:为什么需要一套完整的ADC评估平台? 在嵌入式系统、精密测量或者高速数据采集的项目里,选型一颗合适的模数转换器(ADC)往往是决定项目成败的关键一步。数据手册上的参数琳琅满目——信噪比(SNR&…

2026/7/24 12:54:50阅读更多 →
AI工具链协同增效:从零搭建属于你的自动化办公系统(附2024最新兼容性矩阵)

AI工具链协同增效:从零搭建属于你的自动化办公系统(附2024最新兼容性矩阵)

更多请点击: https://intelliparadigm.com 第一章:AI工具链协同增效:从零搭建属于你的自动化办公系统(附2024最新兼容性矩阵) 现代办公效率的跃迁,不再依赖单一AI工具的“单点突破”,而在于多工…

2026/7/24 12:54:50阅读更多 →
LangChain中Agent工具选择优化与Todo List机制实践

LangChain中Agent工具选择优化与Todo List机制实践

1. 项目概述:当Agent遇上工具选择困境在LangChain生态中构建DeepAgents时,开发者最常遇到的痛点莫过于工具调用混乱问题。想象一个场景:你的Agent需要处理用户查询"帮我查天气然后写首诗",它可能同时触发天气API调用、诗…

2026/7/24 12:54:50阅读更多 →
字节大模型Agent岗面试:Self-Attention与多智能体系统实战

字节大模型Agent岗面试:Self-Attention与多智能体系统实战

1. 面试背景与核心考察维度字节跳动大模型Agent算法岗的二面通常聚焦于候选人对前沿技术的理解深度和工程实现能力。作为经历过完整面试流程的过来人,我发现面试官特别关注三个维度的能力:基础算法功底(如Self-Attention的数学推导&#xff0…

2026/7/24 14:31:17阅读更多 →
AI驱动快消品创新:需求预测与概念测试实战

AI驱动快消品创新:需求预测与概念测试实战

1. 项目背景与行业痛点快消品行业正面临前所未有的创新压力。根据第三方市场研究数据显示,2022年全球快消品新品上市失败率高达85%,平均每个新品研发周期长达18-24个月。这种低效的创新模式让企业承担着巨大的试错成本。作为全球领先的家用清洁及健康产品…

2026/7/24 14:31:17阅读更多 →
AI工具提升学术专著创作效率的实战方案

AI工具提升学术专著创作效率的实战方案

1. 学术专著创作的痛点与AI解决方案写学术专著向来是件让人头疼的事。去年我帮导师整理材料时,光是文献综述就花了整整三个月,每天对着电脑屏幕写到眼睛发酸。直到偶然发现AI工具可以辅助创作,效率直接提升了三倍不止。现在市面上确实有不少号…

2026/7/24 14:31:17阅读更多 →
AI辅助毕业论文写作:四步速成法与智能工具链

AI辅助毕业论文写作:四步速成法与智能工具链

1. 毕业论文写作的痛点与破局之道凌晨三点的大学图书馆里,总能看到盯着黑眼圈的学生对着电脑屏幕发呆。毕业论文这座大山压在每个人心头,从选题迷茫到文献焦虑,从框架混乱到格式崩溃,每个环节都能让写作进度停滞不前。去年指导本科…

2026/7/24 14:31:17阅读更多 →
TDA2P-ACD引脚配置实战:VIP、DSS、EMIF接口设计与避坑指南

TDA2P-ACD引脚配置实战:VIP、DSS、EMIF接口设计与避坑指南

1. 项目概述与核心价值在嵌入式硬件开发,尤其是涉及复杂视频处理与多传感器融合的领域,比如我们常见的ADAS(高级驾驶辅助系统)、工业视觉检测设备或者多路视频录像机,硬件工程师和底层驱动工程师面临的首要挑战往往不是…

2026/7/24 14:31:17阅读更多 →
深入解析音频Codec抽取与插值滤波器:从理论到TLV320AIC3254实战

深入解析音频Codec抽取与插值滤波器:从理论到TLV320AIC3254实战

1. 项目概述与核心挑战 在音频系统设计的江湖里,ADC(模数转换器)和DAC(数模转换器)的性能,直接决定了声音的“灵魂”能否被无损地捕捉与重现。从业十多年,我经手过无数音频编解码器(…

2026/7/24 14:29:17阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 0:58:53阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 0:58:53阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 0:58:53阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:06阅读更多 →
【LeetCode 54】螺旋矩阵

【LeetCode 54】螺旋矩阵

问题描述: 解法: 1、模拟(参考自【LeetCode 54】螺旋矩阵-CSDN博客) int *spiralOrder(int **matrix, int matrixSize, int *matrixColSize, int *returnSize) {static const int dirs[4][2] {{0, 1}, {1, 0}, {0, -1}, {-1, …

2026/7/24 0:00:06阅读更多 →
2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

知春路不相信模型领先今年WAIC大会,昔日AI六小龙来了五家,分别是Kimi、阶跃星辰、Minimax、百川智能、零一万物。连放弃基模的百川和零一万物都来了,唯一缺席的竟是近几个月来风光无限的智谱。(DeepSeek一直不参加)WAI…

2026/7/24 0:00:06阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/23 22:58:43阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/23 18:58:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/23 18:58:18阅读更多 →