feat: 文件搜索、视频续播与目录文件过滤
- 前端 Header 新增搜索栏,接入已有 SearchFiles API,结果支持列表/网格视图 - 新增 PlaybackPosition 数据库列与 /api/files/progress 端点,播放进度存服务端 - 播放中每 5 秒自动保存进度,再次打开视频时弹出"继续播放"提示 - 目录浏览新增媒体类型过滤条(全部/视频/音频/文本),前端即时过滤 - 新增 4 种数据库迁移(AddPlaybackPosition)
This commit is contained in:
@@ -77,6 +77,10 @@ namespace FileShare_Services.Endpoints
|
||||
.WithOpenApi("FileLibrary", "标记文件已播放。")
|
||||
.WithName("MarkFilePlayed");
|
||||
|
||||
endpoints.MapPost<IFileLibraryEndpointService, SaveFileProgressRequest>("api/files/progress", (service, request, _) => service.SaveFileProgressAsync(request))
|
||||
.WithOpenApi("FileLibrary", "保存文件播放进度。")
|
||||
.WithName("SaveFileProgress");
|
||||
|
||||
endpoints.MapGet<IFileLibraryEndpointService, FileQueryRequest>("api/files/detail", (service, request, _) => service.GetFileAsync(request))
|
||||
.WithOpenApi("FileLibrary", "查询文件详情。")
|
||||
.WithName("GetFileDetail");
|
||||
|
||||
@@ -59,6 +59,13 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
public sealed record MarkFilePlayedRequest(
|
||||
[property: JsonPropertyName("id")] int Id);
|
||||
|
||||
/// <summary>
|
||||
/// 保存文件播放进度的请求。
|
||||
/// </summary>
|
||||
public sealed record SaveFileProgressRequest(
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("position")] double Position);
|
||||
|
||||
/// <summary>
|
||||
/// 分页搜索已扫描文件的请求。
|
||||
/// </summary>
|
||||
@@ -121,7 +128,8 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
bool BrowserPlayable,
|
||||
string? ThumbnailUrl = null,
|
||||
double? VideoDuration = null,
|
||||
DateTime? LastPlayedAt = null);
|
||||
DateTime? LastPlayedAt = null,
|
||||
double? PlaybackPosition = null);
|
||||
|
||||
/// <summary>
|
||||
/// 浏览文件库目录结构的请求。
|
||||
|
||||
@@ -101,6 +101,13 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
return ResponseHelper.Succeed();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IApiResponse> SaveFileProgressAsync(SaveFileProgressRequest request)
|
||||
{
|
||||
await fileLibrary.SaveFileProgressAsync(request.Id, request.Position);
|
||||
return ResponseHelper.Succeed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件 ID 是否有效,无效时抛出 <see cref="ArgumentException"/>。
|
||||
/// </summary>
|
||||
|
||||
@@ -404,6 +404,17 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task SaveFileProgressAsync(int id, double position, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var record = await db.ManagedFileRecords.FindAsync([id], cancellationToken);
|
||||
if (record is not null)
|
||||
{
|
||||
record.PlaybackPosition = Math.Max(0, position);
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 深度优先遍历目录树,枚举所有被 <see cref="MediaFileTypes"/> 支持的媒体文件路径。
|
||||
/// 遇到无权限的目录时跳过该分支继续遍历。
|
||||
@@ -559,7 +570,8 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
MediaFileTypes.IsBrowserPlayable(file.Extension),
|
||||
file.ThumbnailId is null ? null : $"/api/thumbnails/{file.ThumbnailId}",
|
||||
file.VideoDuration,
|
||||
file.LastPlayedAt);
|
||||
file.LastPlayedAt,
|
||||
file.PlaybackPosition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,5 +98,12 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
/// <param name="request">包含文件 ID 的请求。</param>
|
||||
/// <returns>API 响应。</returns>
|
||||
Task<IApiResponse> MarkFilePlayedAsync(MarkFilePlayedRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 保存文件播放进度位置。
|
||||
/// </summary>
|
||||
/// <param name="request">包含文件 ID 和播放位置的请求。</param>
|
||||
/// <returns>API 响应。</returns>
|
||||
Task<IApiResponse> SaveFileProgressAsync(SaveFileProgressRequest request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,5 +113,13 @@ namespace FileShare_Services.Services.FileLibrary
|
||||
/// <param name="id">文件记录 ID。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
Task MarkFilePlayedAsync(int id, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 保存文件的播放进度位置。
|
||||
/// </summary>
|
||||
/// <param name="id">文件记录 ID。</param>
|
||||
/// <param name="position">播放位置(秒)。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
Task SaveFileProgressAsync(int id, double position, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user