feat: add fnOS packaging, storage workflows and release pipeline
This commit is contained in:
@@ -4,6 +4,7 @@ using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using dy.net.storage;
|
||||
|
||||
namespace dy.net.Controllers
|
||||
{
|
||||
@@ -13,11 +14,13 @@ namespace dy.net.Controllers
|
||||
{
|
||||
private readonly DouyinVideoService douyinVideoService;
|
||||
private readonly DouyinCommonService douyinCommonService;
|
||||
private readonly MediaStorageRouter _storageRouter;
|
||||
|
||||
public VideoController(DouyinVideoService dyCollectVideoService, DouyinCommonService douyinCommonService)
|
||||
public VideoController(DouyinVideoService dyCollectVideoService, DouyinCommonService douyinCommonService, MediaStorageRouter storageRouter)
|
||||
{
|
||||
this.douyinVideoService = dyCollectVideoService;
|
||||
this.douyinCommonService = douyinCommonService;
|
||||
_storageRouter = storageRouter;
|
||||
}
|
||||
/// <summary>
|
||||
/// 分页查询收藏视频
|
||||
@@ -88,6 +91,9 @@ namespace dy.net.Controllers
|
||||
return ApiResult.Fail("视频信息不能为空");
|
||||
}
|
||||
|
||||
if (video.StorageType.IsRemote())
|
||||
return await PlayRemoteVideoAsync(video);
|
||||
|
||||
// 1. 获取完整物理路径并校验
|
||||
string videoFullPath = video.VideoSavePath;
|
||||
if (string.IsNullOrWhiteSpace(videoFullPath))
|
||||
@@ -153,6 +159,34 @@ namespace dy.net.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IActionResult> PlayRemoteVideoAsync(DouyinVideo video)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(video.VideoSavePath)) return ApiResult.Fail("远端视频路径不能为空");
|
||||
|
||||
long? from = null;
|
||||
long? to = null;
|
||||
var range = Request.Headers.Range.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(range) && range.StartsWith("bytes=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var parts = range[6..].Split('-', 2);
|
||||
if (long.TryParse(parts[0], out var parsedFrom)) from = parsedFrom;
|
||||
if (parts.Length > 1 && long.TryParse(parts[1], out var parsedTo)) to = parsedTo;
|
||||
}
|
||||
|
||||
await using var remote = await _storageRouter.Resolve(video.StorageType)
|
||||
.OpenReadAsync(video.VideoSavePath, from, to, HttpContext.RequestAborted);
|
||||
|
||||
Response.StatusCode = remote.StatusCode;
|
||||
Response.ContentType = remote.ContentType ?? GetContentType(video.VideoSavePath);
|
||||
Response.Headers.AcceptRanges = "bytes";
|
||||
if (remote.ContentLength.HasValue) Response.ContentLength = remote.ContentLength.Value;
|
||||
if (!string.IsNullOrWhiteSpace(remote.ContentRange)) Response.Headers.ContentRange = remote.ContentRange;
|
||||
|
||||
await remote.Stream.CopyToAsync(Response.Body, 81920, HttpContext.RequestAborted);
|
||||
await Response.Body.FlushAsync(HttpContext.RequestAborted);
|
||||
return new EmptyResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理分片请求(Range),异步安全处理流
|
||||
/// </summary>
|
||||
@@ -275,6 +309,7 @@ namespace dy.net.Controllers
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpPost("redown")]
|
||||
public async Task<IActionResult> ReDownload(ReDownViedoDto dto)
|
||||
{
|
||||
@@ -301,6 +336,7 @@ namespace dy.net.Controllers
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpPost("vdelete/batch")]
|
||||
public async Task<IActionResult> BathRealDelete(ReDownViedoDto dto)
|
||||
{
|
||||
@@ -321,6 +357,7 @@ namespace dy.net.Controllers
|
||||
/// </summary>
|
||||
/// <param name="vid"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpGet("vdelete/{vid}")]
|
||||
public async Task<IActionResult> DeleteVideo([FromRoute] string vid)
|
||||
{
|
||||
@@ -346,6 +383,7 @@ namespace dy.net.Controllers
|
||||
/// 查询已删除视频列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpGet("vdelete/get")]
|
||||
public async Task<IActionResult> GetDeleteVideo()
|
||||
{
|
||||
@@ -356,6 +394,7 @@ namespace dy.net.Controllers
|
||||
/// </summary>
|
||||
/// <param name="uperUid"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpGet("vdelete/byauthor/{uperUid}")]
|
||||
public async Task<IActionResult> DeleteByAuthor([FromRoute] string uperUid)
|
||||
{
|
||||
@@ -396,6 +435,7 @@ namespace dy.net.Controllers
|
||||
/// 删除无效视频记录
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
[HttpGet("removeInvalid")]
|
||||
public async Task<IActionResult> RemoveInvalidVideo()
|
||||
{
|
||||
@@ -463,6 +503,7 @@ namespace dy.net.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("/Move")]
|
||||
public async Task<IActionResult> Move()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user