Blazor+PWA技术打造全平台音乐播放器-从音频缓存到离线播放的实践之路



开局三张图…
0.起源
主要是自己现在用的是苹果手机,虽然手机很高级,但是想听自己喜欢的歌曲确是不容易,在线app都要付费,免费的本地播放器都不太好用(收费的也不太行),基础功能都不满足。此外苹果的限制众多,传音乐也是比较麻烦的事。就想着做一款理想的音乐播放器:
- 跨平台运行,在Windows、iOS甚至Linux上保持一致体验
- 界面简洁直观,没有花哨但无用的功能
- 支持将在线音乐缓存到本地,实现离线播放
- 无需经过繁琐的应用商店审核和安装流程
首先考虑的是原生应用开发。Flutter、React Native等跨平台框架挺流行的,但是并不容易,需要花费大量时间学习新的技术栈,更关键的是,在iOS平台上发布应用仍然需要经过App Store的审核流程,还需要支付年费。 MD,我就想安静地听个音乐,至于这么麻烦吗? 请教了万能的gpt后,发现了pwa这种技术,想想之前也是学习了blazor相关的技术,就想着用blazor做一下了。
1.PWA:跨平台音乐应用的理想选择
PWA(渐进式Web应用)是一种结合Web和原生应用优势的技术,旨在提供类似原生应用的用户体验。PWA可以在任何支持现代浏览器的设备上运行,实现跨平台兼容性。通过Service Worker,PWA支持离线访问,允许用户在无网络连接时继续使用应用。用户可以将PWA安装到设备上,享受全屏体验,并通过推送通知保持互动。PWA采用响应式设计,确保在不同设备上提供一致的用户体验。由于通过HTTPS提供服务,PWA还具备较高的安全性。对于希望快速构建跨平台应用的开发者来说,PWA是一个理想的选择。
1.1.音频流API与离线缓存:PWA的核心能力
PWA(渐进式Web应用)技术通过Service Worker实现离线运行,使得应用在无网络连接时依然能够正常使用。这对于音乐播放器尤为重要,因为用户可以在离线状态下继续播放已缓存的音乐。IndexedDB则提供了强大的本地存储能力,允许应用将音频数据和相关元数据保存到用户设备中。通过IndexedDB,音乐播放器可以高效地管理和检索本地存储的数据,确保用户在离线时也能访问完整的音乐库。这种结合使得PWA成为构建跨平台音乐应用的理想选择,提供了流畅的用户体验和可靠的数据存储。
在实现PWA音乐播放器时,服务端的音频流API是基础设施:
[HttpGet("{id}")]
public IActionResult GetMusicStream(string id)
{try{// 安全处理文件路径string safeId = Path.GetFileNameWithoutExtension(id);string filePath = Path.Combine("D:\\music", $"{safeId}.mp3");// 返回文件流,启用范围处理return PhysicalFile(filePath, "audio/mpeg", enableRangeProcessing: true);}catch (Exception ex){_logger.LogError(ex, "流式播放失败");return StatusCode(500, "处理请求时发生错误");}
}
1.2.通过Service Worker,我们可以拦截网络请求,实现复杂的缓存逻辑:
// service-worker.js
self.addEventListener('fetch', event => {// 检查请求是否为音频文件if (event.request.url.includes('/api/music/')) {event.respondWith(caches.match(event.request).then(cachedResponse => {// 返回缓存响应或从网络获取return cachedResponse || fetch(event.request).then(response => {// 克隆响应并缓存const responseToCache = response.clone();caches.open('audio-cache').then(cache => {cache.put(event.request, responseToCache);});return response;});}));}
});
1.3.IndexedDB:增强PWA的离线音乐库
PWA的一个核心特性是能够在完全离线状态下工作。我们使用IndexedDB来存储音频数据和元数据,这比简单的Cache API提供了更强大的功能:
export async function cacheAudioWithMetadata(key, url, metadataJson) {try {// 检查是否已缓存if (await isAudioCached(key)) {return await getCachedAudio(key);}// 获取并存储音频数据const response = await fetch(url);const arrayBuffer = await response.arrayBuffer();const base64Data = arrayBufferToBase64(arrayBuffer);const dataUrl = `data:audio/mpeg;base64,${base64Data}`;// 存储音频和元数据await cacheAudioData(key, dataUrl, JSON.parse(metadataJson));return dataUrl;} catch (error) {// 网络错误时尝试返回缓存数据return await getCachedAudio(key);}
}
1.4.核心功能
- 在设备首次访问时下载并缓存用户喜爱的音乐
- 在离线环境(如飞行模式或无信号区域)继续播放
- 智能管理存储空间,避免缓存过度占用设备存储
- 保存用户的播放列表和偏好设置
2.自适应UI:真正的全平台体验
PWA的另一个强大特性是响应式设计。通过CSS媒体查询和弹性布局,我们能够创建适应从手机到桌面各种设备的用户界面:
/* 移动设备优先的样式 */
.music-player {display: flex;flex-direction: column;
}/* 平板和桌面布局 */
@media (min-width: 768px) {.music-player {flex-direction: row;}.playlist {width: 300px;}.player-controls {flex: 1;}
}/* 大屏幕设备优化 */
@media (min-width: 1200px) {.playlist {width: 350px;}
}
3.安装体验优化:从网页到应用
PWA的一大亮点是可安装性。通过配置Web App Manifest,我们可以创建一个能够像原生应用一样被安装的音乐播放器:
{"name": "全平台音乐播放器","short_name": "音乐播放器","start_url": "/","display": "standalone","background_color": "#ffffff","theme_color": "#4285f4","icons": [{"src": "icons/icon-192.png","sizes": "192x192","type": "image/png"},{"src": "icons/icon-512.png","sizes": "512x512","type": "image/png"}]
}
这使得用户可以:
- 在手机主屏幕上添加我们的应用图标
- 在桌面浏览器中点击"安装"按钮将其添加到开始菜单或桌面
- 在没有地址栏的全屏模式下使用应用
- 通过操作系统任务切换器访问应用
相关文章:
Blazor+PWA技术打造全平台音乐播放器-从音频缓存到离线播放的实践之路
开局三张图… 0.起源 主要是自己现在用的是苹果手机,虽然手机很高级,但是想听自己喜欢的歌曲确是不容易,在线app都要付费,免费的本地播放器都不太好用(收费的也不太行),基础功能都不满足。此外…...
使用LangChain开发智能问答系统
代码地址见文末 1. 项目配置 1.1 Neo4j 数据库配置 1. 安装与环境变量 解压路径:将neo4j-community-5.x.x.zip解压至D:\neo4j-community-5.x.x环境变量: NEO4J_HOME: D:\neo4j-community-5.x.xJAVA_HOME: D:\neo4j-community-5.x.x\jdk(注意:需指向 JDK 目录)Path 变量…...
Centos操作系统安装及优化
Centos操作系统安装及优化 零、环境概述 主机名 centos版本 cpu 内存 Vmware版本 ip地址 test CentOS Linux release 7.6.1810 (Core) 2C 2G 15.5.1 10.0.0.10 一、介质下载 1、7.6版本下载 CentOS7.6标准版下载链接: https://archive.kernel.org/centos-vault/7.6.1810/i…...
游戏引擎学习第177天
仓库:https://gitee.com/mrxiao_com/2d_game_4 今日计划 调试代码有时可能会非常困难,尤其是在面对那些难以发现的 bug 时。显然,调试工具是其中一个非常重要的工具,但在游戏开发中,另一个非常常见的工具就是自定义的调试工具&a…...
springCloud集成tdengine(原生和mapper方式) 其一
第一种 mapper方式,原生方式在主页看第二章 一、添加pom文件 <!-- HikariCP 连接池 --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency><!-- TDengine 连接器--><de…...
数据结构知识点1
目录 一、时间复杂度和空间复杂度 1.1时间复杂度: 1.2空间复杂度: 二、装箱和拆箱 三、泛型 3.1泛型类的使用: 3.2泛型的上界: 3.3泛型方法: 一、时间复杂度和空间复杂度 1.1时间复杂度: 时间复杂…...
时序数据库QuestDB在Winform窗体应用
以下是QuestDB在Winform使用的代码: //初始化 private void Init() { //创建数据库对象 (用法和EF Dappper一样通过new保证线程安全) SqlSugarClient Db new SqlSugarClient(new ConnectionConfig() { ConnectionString “host10.3.5.227;port8812;usernameadmin;…...
从零开始学习 Go 语言
Go 语言(又称 Golang)是由 Google 开发的一种静态强类型、编译型、并发型编程语言。它以其简洁的语法、高效的并发支持和强大的标准库而闻名,非常适合开发高性能的服务器端应用、分布式系统和云计算工具。本文将从零开始,详细介绍…...
自由学习记录(45)
顶点片元着色器(important) 1.需要在Pass渲染通道中编写着色器逻辑 2.可以使用cG或HLSL两种shader语言去编写Shader逻辑 3.代码量较多,灵活性较强,性能消耗更可控,可以实现更多渲染细节 4.适用于光照处理较少…...
数据源支持远程Excel/CSV,数据集支持分组字段功能,DataEase开源BI工具v2.10.6 LTS版本发布
2025年3月17日,人人可用的开源BI工具DataEase正式发布v2.10.6 LTS版本。 这一版本的功能变动包括:数据源方面,新增支持远程Excel/CSV数据源,支持以HTTP、HTTPS、FTP协议获取远程服务器上的Excel和CSV数据文件,并且可以…...
SpringBoot3使用CompletableFuture时java.util.ConcurrentModificationException异常解决方案
问题描述 在Spring Boot 3项目中,使用CompletableFuture进行异步编程时,偶发{"code":500,"msg":"java.util.ConcurrentModificationException"}异常,但代码中并未直接操作List或CopyOnWriteArrayList等集合类…...
【Nodejs】2024 汇总现状
之前已经调研了容器、nexus-public,实现了本地构建应用镜像和基础设施的镜像。为实现分布式一体化协作开发的目标,还需要配套的线上协作开发环境。故而重回前端调研现状,比较 5 年前的 nodejs 快好的啊。 以下是针对 Node.js 工具链的深度解析…...
LeetCode 每日一题 2025/3/17-2025/3/23
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 3/17 1963. 使字符串平衡的最小交换次数3/18 2614. 对角线上的质数3/19 2610. 转换二维数组3/20 2612. 最少翻转操作数3/21 2680. 最大或值3/22 2643. 一最多的行3/23 2116…...
STM32__红外避障模块的使用
目录 一、红外避障模块 概述 二、直接读取OUT引脚电平 三、使用中断方式触发 一、红外避障模块 概述 引脚解释: VCC接3.3V 或 5.0VGND接开发板的GNDOUT数字量输出(0或1); 低电平时表示前方有障碍 ; 通过可调电阻调整检测距离 产品特点: …...
android 音量调节
安卓音频数据的最终音量由三部分组成,分别是master volume(全局音量,对整个系统所有的音频数据生效),stream volume(流音量,只针对特定类型的音频数据生效)和track volume(track音量,只针对某个audiotrack的…...
Redis JSON 用id读取content总结(sendCommand())
Redis JSON 读取总结(方法 2 - sendCommand()) 💡 背景 在 Redis 中,我们存储了 JSON 数据,并希望通过 Jedis sendCommand() 方式读取 JSON 里的 "content" 字段。由于 jedis.jsonGet() 可能在旧版本不支持…...
使用Qdrant等其他向量数据库时需要将将numpy 数组转换为列表 确保数据能被正确处理和序列化,避免类型不兼容的问题。
在使用Qdrant等其他向量数据库时需要 转换 numpy 数组为列表主要是为了确保数据能被正确处理和序列化,避免类型不兼容的问题。具体原因如下: 序列化兼容性: 很多数据库接口、API 或者 JSON 序列化工具只能处理 Python 的内置类型(…...
[AI速读]如何构建高效的AMBA协议检查器(Checker IP)
在芯片验证过程中,检查器(Checker)是确保设计符合协议规范的关键工具。本文基于一篇技术论文,分享如何为AMBA协议(如AXI、AHB)构建可重用的检查器IP(Checker IP,简称CIP),并简化其核心思路,帮助工程师快速上手。 一、什么是Checker IP? Checker IP是一组用SystemVe…...
基于3DMax与Vray引擎的轻量级室内场景渲染实践
欢迎踏入3DMAX室内渲染的沉浸式学习之旅!在这个精心设计的实战教程中,我们将携手揭开3DMAX与Vray这对黄金搭档在打造现实室内场景时的核心奥秘。无论您是渴望入门的3D新手,还是追求极致效果的专业设计师,这里都将为您呈现从场景蓝图构建到光影魔法施加的完整技术图谱。我们…...
浅谈Qt事件子系统——以可拖动的通用Widget为例子
浅谈Qt事件子系统——以可拖动的通用Widget为例子 这一篇文章是一个通过实现可拖动的通用Widget为引子简单介绍一下我们的事件对象子系统的事情 代码和所有的文档 1:Qt侧的API介绍和说明 这个是每一个小项目的惯例,我会介绍大部分Qt程序中使用到的…...
QT Quick(C++)跨平台应用程序项目实战教程 2 — 环境搭建和项目创建
目录 引言 1. 安装Qt开发环境 1.1 下载Qt安装包 1.2 安装Qt 1.3 安装MSVC编译器 2. 创建Qt Quick项目 2.1 创建新项目 2.2 项目结构 2.3 运行项目 3. 理解项目代码 3.1 main.cpp文件 3.2 Main.qml文件 引言 在上一篇文章中,我们介绍了本教程的目标和结…...
登山第二十梯:无人机实时自主探索——我是一只小小小鸟
文章目录 一 摘要 二 资源 三 内容 一 摘要 自主探索是无人机 (UAV) 各种应用的基本问题。最近,基于 LiDAR 的探索因其能够生成大规模环境的高精度点云地图而受到广泛关注。虽然点云本身就为导航提供了信息,但许多现有的勘探方…...
Pytorch使用手册—扩展 TorchScript 使用自定义 C++ 操作符(专题五十三)
提示 本教程自 PyTorch 2.4 起已弃用。有关 PyTorch 自定义操作符的最新指南,请参阅 PyTorch 自定义操作符。 PyTorch 1.0 版本引入了一种名为 TorchScript 的新编程模型。TorchScript 是 Python 编程语言的一个子集,可以被 TorchScript 编译器解析、编译和优化。此外,编译后…...
word插入Mathtype公式居中和自动更新
word插入公式自动更新 前提:安装Mathtype 1.word中查看页的宽度 出现如下 2.设置样式 出现这个窗口 给样式随便起个名字 3.修改样式 3.1 设置两个制表位 第二个 3.2 修改公式字体 如下所示 4. 修改公式格式 4.1在word中打开 Mathtype 4.2 修改公式的格式 变成…...
网络层之IP协议
在讨论传输层时, 我们都只讨论了发送方和接收方的问题, 而没有讨论中间的网络形态的问题. 也就是数据包如何从主机传送到主机的? 如图, 主机B发送数据到主机C, 发送报文需要进行路径选择, 主机B-> F-> G-> H-> C-> D -> 主机C 这条路径是如何被选择出来的?…...
基于springboot的旅游网站(013)
摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势,旅游网站当然也不能排除在外,随着旅游网站的不断成熟,它彻底改变了过去传统的旅游网站方式,不仅使旅游管理…...
人工智能 - 在 Spring Boot 中调用 AnythingLLM+DeepSeek 的知识库获取消息接口
整体逻辑: 自建系统的web UI界面调用接口: 1.SpringBoot接口:/anything/chatMessageAnything 2.调用anythingLLM - 调用知识库deepseek r1 . 部署 AnythingLLM DeepSeek 本地知识库 的环境要求如下: 一、硬件要求 CPU 最低:4核&#x…...
体育直播模板nba英超直播欧洲杯直播模板手机自适应
源码名称:体育直播模板nba英超直播欧洲杯直播模板手机自适应帝国cms 7.5模板 开发环境:帝国cms7.5 空间支持:phpmysql 带软件采集,可以挂着自动采集发布,无需人工操作! 模板特点: 程序伪静态…...
STM32-ARM
一、体系架构 ARM里有37个寄存器ALU算数逻辑单元PC程序计数器:指向哪里执行哪里SP栈指针寄存器LR链接寄存器:保存函数入口地址CPSR(current program status register)当前程序状态寄存器:SOSR(CPSR的备份)MMU(内存管理单元)Cache高速缓冲(iCa…...
ripro 主题激活 问题写入授权Token失败,可能无文件写入权限
ripro 主题激活 问题 写入授权Token失败,可能无文件写入权限 找到主题下面的functions.php文件,给其他写入权限。就好了。...
