using Dpz.Core.Infrastructure.Imaging;
using Dpz.Core.Public.ViewModel.Request;
using Dpz.Core.Public.ViewModel.Response;
namespace Dpz.Core.WebApi.Controllers;
/// <summary>
/// 音乐管理
/// </summary>
[ApiController, Route("api/[controller]")]
public class MusicController(
IMusicService musicService,
IObjectStorageOperation objectStorageService,
ILogger<MusicController> logger,
IImageFormatDetector imageFormatDetector,
IFusionCache fusionCache
) : ControllerBase
{
/// <summary>
/// 音乐列表
/// </summary>
/// <returns></returns>
[HttpGet]
[ProducesResponseType<List<MusicResponse>>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetMusics([FromQuery] MusicQueryParameterDto parameter)
{
var musics = await musicService.GetPagesAsync(
parameter.PageIndex,
parameter.PageSize,
parameter.Title
);
musics.AddPaginationMetadata(Response.Headers);
return Ok(musics);
}
/// <summary>
/// 单个音乐
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}")]
[ProducesResponseType<MusicResponse>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetMusic(string id)
{
var music = await musicService.GetAsync(id);
return Ok(music);
}
/// <summary>
/// 获取所有分组
/// </summary>
/// <returns></returns>
[HttpGet("groups")]
[ProducesResponseType<List<string>>(StatusCodes.Status200OK)]
public async Task<ActionResult<List<string>>> GetGroups()
{
var groups = await musicService.GetGroupsAsync();
return Ok(groups);
}
/// <summary>
/// 获取歌词
/// </summary>
/// <param name="id"></param>
/// <param name="httpClientFactory"></param>
/// <returns></returns>
[HttpGet("lrc/{id}")]
[ProducesResponseType<string>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> GetLyric(
string id,
[FromServices] IHttpClientFactory httpClientFactory
)
{
var lrcCacheKey = $"music-lrc:{id}";
var cacheValue = await fusionCache.TryGetAsync<string>(lrcCacheKey);
if (cacheValue.HasValue)
{
return Content(cacheValue.Value, "application/lrc;charset=utf-8;");
}
if (string.IsNullOrEmpty(id))
{
return NotFound();
}
var music = await musicService.GetAsync(id);
if (music == null)
{
return NotFound();
}
if (string.IsNullOrEmpty(music.LyricUrl))
{
return NoContent();
}
string lrc;
var httpClient = httpClientFactory.CreateClient("edge");
try
{
var request = new HttpRequestMessage(HttpMethod.Get, music.LyricUrl);
var response = await httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
return NoContent();
}
lrc = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
logger.LogError(e, "get lrc fail");
lrc = music.LyricContent ?? "";
}
return Content(lrc, "application/lrc;charset=utf-8;");
}
/// <summary>
/// 更改音乐信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPatch("information"), Authorize(Policy = "System")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> EditInformation([FromForm] ChangeMusicRequest model)
{
var information = new EditMusicInformationRequest
{
Id = model.Id,
Lyric = model.Lyric,
Cover = model.Cover,
Group = model.Group,
UploadLyric = async (bytes, music) =>
{
if (!string.IsNullOrEmpty(music.LyricUrl))
{
await objectStorageService.DeleteAsync(music.LyricUrl);
}
return await HandleUploadAsync(bytes, $"{Guid.NewGuid():N}.lrc,", "lyric");
},
UploadCover = async (bytes, music) =>
{
if (!string.IsNullOrEmpty(music.CoverUrl))
{
await objectStorageService.DeleteAsync(music.CoverUrl);
}
string coverExt;
try
{
var info = imageFormatDetector.Detect(bytes);
coverExt = info.IsKnown ? info.DefaultExtension : "jpg";
}
catch (Exception ex)
{
coverExt = "jpg";
logger.LogError(ex, "get image format fail");
}
return await HandleUploadAsync(bytes, $"{Guid.NewGuid():N}.{coverExt}", "cover");
},
};
await musicService.EditMusicInformationAsync(information);
return NoContent();
}
/// <summary>
/// 新增音乐
/// </summary>
/// <param name="upload"></param>
/// <returns></returns>
[HttpPost, Authorize(Policy = "System")]
[RequestSizeLimit(104_857_600)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Save([FromForm] UploadMusicRequest upload)
{
var from = string.IsNullOrWhiteSpace(upload.From) ? "Web Api" : upload.From;
var request = new MusicUploadActionRequest
{
From = from,
Lyric = upload.Lyrics,
Cover = upload.Cover,
Music = upload.Music,
UploadMusic = async (bytes, filename) => await HandleUploadAsync(bytes, filename, null),
UploadCover = async (bytes, filename) =>
await HandleUploadAsync(bytes, filename, "cover"),
UploadLyric = async (bytes, filename) =>
await HandleUploadAsync(bytes, filename, "lyric"),
Group = upload.Group,
};
await musicService.SaveAsync(request);
return NoContent();
}
[NonAction]
private async Task<string> HandleUploadAsync(byte[] bytes, string filename, string? type)
{
#if DEBUG
var list = new List<string> { "Test", "music" };
#else
var list = new List<string> { "music" };
#endif
if (!string.IsNullOrEmpty(type))
{
list.Add(type);
}
var result = await objectStorageService.UploadAsync(bytes, list, filename);
return result.Url;
}
/// <summary>
/// 删除音乐
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete("{id}"), Authorize(Policy = "System")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Delete(string id)
{
await musicService.DeleteAsync(
id,
async x => await objectStorageService.DeleteMusicAsync(x)
);
return NoContent();
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个 ASP.NET Core Web API 控制器,用于管理音乐相关的操作。以下是详细解释:
控制器概述
MusicController - 音乐管理控制器,使用主构造函数(C# 12特性)注入了5个依赖项:
IMusicService- 音乐业务服务IObjectStorageOperation- 对象存储服务ILogger- 日志记录器IImageFormatDetector- 图片格式检测器IFusionCache- 融合缓存服务
API 接口
1. GetMusics - 获取音乐列表
[HttpGet]
- 支持分页查询(页码、页大小、标题筛选)
- 返回音乐列表,并将分页元数据添加到响应头
2. GetMusic - 获取单个音乐
[HttpGet("{id}")]
- 根据ID获取音乐详情
3. GetGroups - 获取所有分组
[HttpGet("groups")]
- 返回所有音乐分组列表
4. GetLyric - 获取歌词
[HttpGet("lrc/{id}")]
- 先尝试从缓存中获取歌词
- 若缓存未命中,则从数据库获取音乐信息
- 通过HTTP客户端从外部URL下载歌词文件
- 如果下载失败,使用数据库存储的歌词内容
- 返回LRC格式的歌词文本
5. EditInformation - 更改音乐信息
[HttpPatch("information"), Authorize(Policy = "System")]
- 需要系统权限认证
- 支持更新:歌词、封面、分组
- 上传歌词时:
- 删除旧的歌词文件
- 生成新的GUID文件名上传
- 上传封面时:
- 删除旧的封面文件
- 检测图片格式(默认jpg)
- 生成新文件名上传
6. Save - 新增音乐
[HttpPost, Authorize(Policy = "System")]
[RequestSizeLimit(104_857_600)] // 限制100MB
- 需要系统权限认证
- 限制请求体大小为100MB
- 支持上传:音乐文件、封面、歌词
- 记录上传来源(默认"Web Api")
- 将文件上传到对象存储
7. Delete - 删除音乐
[HttpDelete("{id}"), Authorize(Policy = "System")]
- 需要系统权限认证
- 删除音乐记录及关联的对象存储文件
辅助方法
HandleUploadAsync - 处理文件上传
[NonAction]
- 根据编译模式设置存储路径(Debug模式包含"Test"目录)
- 将文件上传到对象存储
- 支持可选的类型分类(如"cover"、"lyric")
- 返回上传后的文件URL
技术特点
- 依赖注入:使用主构造函数简化依赖注入
- 授权策略:使用"System"策略保护敏感操作
- 缓存机制:歌词使用FusionCache缓存
- 文件管理:自动删除旧文件,避免存储浪费
- 异常处理:优雅处理HTTP请求失败和图片格式检测失败
- 文档化:使用XML注释和ProducesResponseType标注返回类型
AI 正在分析代码…
评论加载中...