1、去重

2、分享
3、视频播放
4、批量删除,重新下载
5、自定义标题(仅博主视频)
6、授权页面去掉博主添加,新增关注列表
7、图文视频合成优化
8、其他优化
This commit is contained in:
jianzhichu
2025-11-30 00:42:25 +08:00
parent 63b51d211e
commit e6e9ff3cc3
94 changed files with 8155 additions and 1544 deletions
+105 -37
View File
@@ -1,4 +1,5 @@
using dy.net.dto;
using dy.net.model;
using dy.net.service;
using dy.net.utils;
using Microsoft.AspNetCore.Authorization;
@@ -14,10 +15,12 @@ namespace dy.net.Controllers
public class VideoController : ControllerBase
{
private readonly DouyinVideoService dyCollectVideoService;
private readonly DouyinQuartzJobService douyinQuartzJobService;
public VideoController(DouyinVideoService dyCollectVideoService)
public VideoController(DouyinVideoService dyCollectVideoService,DouyinQuartzJobService douyinQuartzJobService)
{
this.dyCollectVideoService = dyCollectVideoService;
this.douyinQuartzJobService = douyinQuartzJobService;
}
/// <summary>
/// 分页查询收藏视频
@@ -26,7 +29,7 @@ namespace dy.net.Controllers
[HttpPost("paged")]
public async Task<IActionResult> GetPagedAsync(DouyinVideoPageRequestDto dto)
{
var (list, totalCount) = await dyCollectVideoService.GetPagedAsync(dto.PageIndex, dto.PageSize, dto.Tag, dto.Author,dto.ViedoType,dto.Dates);
var (list, totalCount) = await dyCollectVideoService.GetPagedAsync(dto);
return Ok(new
{
code = 0,
@@ -67,48 +70,87 @@ namespace dy.net.Controllers
{
var viedo = await dyCollectVideoService.GetById(vid);
if(viedo == null)
if (viedo == null)
{
return NotFound($"视频不存在:{vid}");
}
return PlayViedo(viedo);
}
catch (Exception ex)
{
return StatusCode(500, $"视频加载失败:{ex.Message}");
}
}
private IActionResult PlayViedo(DouyinVideo viedo)
{
// 1. 拼接完整物理路径(配置路径 + 文件名)
string videoFullPath = viedo.VideoSavePath;
// 2. 验证文件是否存在
if (!System.IO.File.Exists(videoFullPath))
{
return NotFound($"视频文件不存在:{videoFullPath}");
}
// 3. 获取文件信息(大小、类型)
var fileInfo = new FileInfo(videoFullPath);
long fileSize = fileInfo.Length;
string contentType = GetContentType(videoFullPath); // 自动识别视频 MIME 类型
// 4. 处理分片请求(前端视频标签自动发起,支持断点续传)
if (Request.Headers.ContainsKey("Range") && long.TryParse(Request.Headers.Range.ToString().Split('=')[1].Split('-')[0], out long start))
{
// 分片起始位置(前端请求的起始字节)
long end = Math.Min(start + 1024 * 1024 * 2, fileSize - 1); // 每片 2MB(可调整)
long chunkSize = end - start + 1;
// 5. 设置分片响应头
Response.StatusCode = StatusCodes.Status206PartialContent;
Response.Headers.Add("Content-Range", $"bytes {start}-{end}/{fileSize}");
Response.Headers.Add("Accept-Ranges", "bytes");
Response.Headers.Add("Content-Length", chunkSize.ToString());
// 6. 读取分片并返回流
var stream = new FileStream(videoFullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
stream.Seek(start, SeekOrigin.Begin);
return new FileStreamResult(stream, contentType);
}
else
{
// 完整文件请求(兼容旧浏览器)
return PhysicalFile(videoFullPath, contentType, enableRangeProcessing: true);
}
}
/// <summary>
/// 播放视频
/// </summary>
/// <param name="vid"></param>
/// <param name="k"></param>
/// <returns></returns>
[HttpGet("/share/{vid}/{k}")]
[AllowAnonymous]
public async Task<IActionResult> Share([FromRoute] string vid, [FromRoute] string k)
{
try
{
var viedo = await dyCollectVideoService.GetById(vid);
if (viedo == null)
{
return NotFound($"视频不存在:{vid}");
}
// 1. 拼接完整物理路径(配置路径 + 文件名)
string videoFullPath = viedo.VideoSavePath;
// 2. 验证文件是否存在
if (!System.IO.File.Exists(videoFullPath))
var expectedKey = (viedo.FileHash + viedo.AuthorId).Md5();
if (expectedKey != k)
{
return NotFound($"视频文件不存在:{videoFullPath}");
return NotFound($"视频地址无效");
}
// 3. 获取文件信息(大小、类型)
var fileInfo = new FileInfo(videoFullPath);
long fileSize = fileInfo.Length;
string contentType = GetContentType(videoFullPath); // 自动识别视频 MIME 类型
// 4. 处理分片请求(前端视频标签自动发起,支持断点续传)
if (Request.Headers.ContainsKey("Range") && long.TryParse(Request.Headers.Range.ToString().Split('=')[1].Split('-')[0], out long start))
{
// 分片起始位置(前端请求的起始字节)
long end = Math.Min(start + 1024 * 1024 * 2, fileSize - 1); // 每片 2MB(可调整)
long chunkSize = end - start + 1;
// 5. 设置分片响应头
Response.StatusCode = StatusCodes.Status206PartialContent;
Response.Headers.Add("Content-Range", $"bytes {start}-{end}/{fileSize}");
Response.Headers.Add("Accept-Ranges", "bytes");
Response.Headers.Add("Content-Length", chunkSize.ToString());
// 6. 读取分片并返回流
var stream = new FileStream(videoFullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
stream.Seek(start, SeekOrigin.Begin);
return new FileStreamResult(stream, contentType);
}
else
{
// 完整文件请求(兼容旧浏览器)
return PhysicalFile(videoFullPath, contentType, enableRangeProcessing: true);
}
return PlayViedo(viedo);
}
catch (Exception ex)
{
@@ -133,6 +175,32 @@ namespace dy.net.Controllers
};
}
/// <summary>
/// 重新下载
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("redown")]
public async Task<IActionResult> ReDownload(ReDownViedoDto dto)
{
if (dto == null)
{
return Ok(new { code = -1, data = false });
}
else
{
var result = await dyCollectVideoService.ReDownloadViedoAsync(dto);
if (result)
{
//douyinQuartzJobService.StartReDownJobOnceAsync();...无法实现。。逆向失败
return Ok(new { code = 0, data = true });
}
else
{
return Ok(new { code = -1, data = false });
}
}
}
}
}