网站首页 网站源码
using Dpz.Core.Web.Cache;
namespace Dpz.Core.WebApi.Controllers;
/// <summary>
/// 音乐管理
/// </summary>
[ApiController, Route("api/[controller]")]
public class MusicController(
IMusicService musicService,
IObjectStorageOperation objectStorageService,
ILogger<MusicController> logger
) : ControllerBase
{
/// <summary>
/// 音乐列表
/// </summary>
/// <returns></returns>
[HttpGet]
[ProducesResponseType<List<VmMusic>>(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<VmMusic>(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}"), CacheOutput(ServerTimeSpan = 30 * 24 * 60 * 60)]
[ProducesResponseType<string>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> GetLyric(
string id,
[FromServices] IHttpClientFactory httpClientFactory
)
{
if (string.IsNullOrEmpty(id))
return NotFound();
var music = await musicService.GetAsync(id);
if (music == null)
return NotFound();
if (string.IsNullOrEmpty(music.LyricUrl))
{
return NoContent();
}
var httpClient = httpClientFactory.CreateClient("edge");
HttpResponseMessage response;
try
{
var request = new HttpRequestMessage(HttpMethod.Get, music.LyricUrl);
response = await httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
return NoContent();
}
}
catch (Exception e)
{
logger.LogError(e, "get lrc fail");
return NotFound();
}
var lrc = await response.Content.ReadAsStringAsync();
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] VmChangeMusic model)
{
var information = new VmEditMusicInformation
{
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
{
using var stream = new MemoryStream(bytes);
using var image = await Image.LoadAsync(stream);
coverExt =
image.Metadata.DecodedImageFormat?.FileExtensions.FirstOrDefault() ?? "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] UploadMusicViewModel upload)
{
var from = string.IsNullOrWhiteSpace(upload.From) ? "Web Api" : upload.From;
var model = new VmMusicUpload
{
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(model);
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.ToArray(), filename);
return result.AccessUrl;
}
/// <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();
}
}
上述代码是一个 ASP.NET Core Web API 控制器,名为 MusicController
,用于管理音乐相关的操作。以下是对代码中各个部分的详细解释:
MusicController
继承自 ControllerBase
,并使用了 ApiController
和 Route
特性来定义 API 的路由。IMusicService
(音乐服务)、IObjectStorageOperation
(对象存储操作服务)和 ILogger<MusicController>
(日志记录器)。GetMusics
GetMusic
GetGroups
GetLyric
CacheOutput
特性缓存结果 30 天。若找不到歌词 URL 或请求失败,则返回相应的状态码。EditInformation
Save
HandleUploadAsync
Delete
这个控制器提供了一整套音乐管理的 API,包括获取音乐列表、单个音乐信息、分组、歌词、更新音乐信息、新增音乐和删除音乐的功能。它使用了依赖注入来管理服务,并通过异步编程提高性能。控制器还实现了基本的错误处理和日志记录。