272 lines
10 KiB
C#
272 lines
10 KiB
C#
using dy.net.model.dto;
|
|
using dy.net.model.entity;
|
|
using dy.net.service;
|
|
using dy.net.utils;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Serilog;
|
|
|
|
namespace dy.net.Controllers
|
|
{
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
[Authorize]
|
|
public class FollowController : ControllerBase
|
|
{
|
|
private readonly DouyinFollowService _douyinFollowService;
|
|
private readonly DouyinQuartzJobService _douyinQuartzJobService;
|
|
private readonly DouyinUserLookupService _douyinUserLookupService;
|
|
private readonly DouyinLiveStatusService _douyinLiveStatusService;
|
|
|
|
public FollowController(
|
|
DouyinFollowService douyinFollowService,
|
|
DouyinQuartzJobService douyinQuartzJobService,
|
|
DouyinUserLookupService douyinUserLookupService,
|
|
DouyinLiveStatusService douyinLiveStatusService)
|
|
{
|
|
this._douyinFollowService = douyinFollowService;
|
|
_douyinQuartzJobService = douyinQuartzJobService;
|
|
_douyinUserLookupService = douyinUserLookupService;
|
|
_douyinLiveStatusService = douyinLiveStatusService;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 分页查询
|
|
/// </summary>
|
|
/// <returns>分页结果</returns>
|
|
[HttpPost("paged")]
|
|
public async Task<IActionResult> GetPagedAsync(
|
|
FollowRequestDto dto)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(dto.MySelfId))
|
|
{
|
|
return ApiResult.Success(new { });
|
|
}
|
|
var (list, totalCount) = await _douyinFollowService.GetPagedAsync(dto);
|
|
|
|
return ApiResult.Success(new
|
|
{
|
|
data = list,
|
|
total = totalCount,
|
|
pageIndex = dto.PageIndex,
|
|
pageSize = dto.PageSize
|
|
});
|
|
}
|
|
/// <summary>
|
|
/// 重新同步-单次
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("sync")]
|
|
public async Task<IActionResult> SyncFollowList()
|
|
{
|
|
try
|
|
{
|
|
var started = await _douyinQuartzJobService.StartFollowJobOnceAsync();
|
|
return started
|
|
? ApiResult.Success(new { message = "关注列表更新任务已启动" })
|
|
: ApiResult.Fail("关注列表更新任务启动失败,请查看错误日志。");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "手动启动关注列表更新任务失败");
|
|
return ApiResult.Fail("关注列表更新任务启动失败:" + ex.GetBaseException().Message);
|
|
}
|
|
}
|
|
[HttpPost("add")]
|
|
public async Task<IActionResult> AddFollow(DouyinFollowed followed)
|
|
{
|
|
if (followed == null)
|
|
{
|
|
return ApiResult.Fail("新增信息不能为空");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(followed.mySelfId))
|
|
{
|
|
return ApiResult.Fail("请先配置抖音授权信息,抖音授权配置里面填写你的uid");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(followed.SecUid))
|
|
{
|
|
return ApiResult.Fail("博主 SecUid 不能为空");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(followed.UperId))
|
|
{
|
|
return ApiResult.Fail("博主 UID 不能为空");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(followed.UperName))
|
|
{
|
|
return ApiResult.Fail("博主姓名不能为空");
|
|
}
|
|
|
|
followed.mySelfId = followed.mySelfId.Trim();
|
|
followed.SecUid = followed.SecUid.Trim();
|
|
followed.UperId = followed.UperId.Trim();
|
|
followed.UperName = followed.UperName.Trim();
|
|
followed.DouyinNo = followed.DouyinNo?.Trim();
|
|
followed.SavePath = followed.SavePath?.Trim();
|
|
followed.Signature = Limit(followed.Signature, 500);
|
|
followed.UperAvatar = Limit(followed.UperAvatar, 1000);
|
|
followed.Enterprise = Limit(followed.Enterprise, 200);
|
|
followed.FullSync = followed.OpenSync && followed.FullSync;
|
|
|
|
if (followed.mySelfId.Length > 200 || followed.SecUid.Length > 500 ||
|
|
followed.UperId.Length > 100 || followed.UperName.Length > 200)
|
|
{
|
|
return ApiResult.Fail("新增信息长度超出限制,请检查 UID、SecUid 和博主姓名");
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(followed.DouyinNo) && followed.DouyinNo.Length > 100)
|
|
{
|
|
return ApiResult.Fail("抖音号长度不能超过 100 个字符");
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(followed.SavePath))
|
|
{
|
|
if (followed.SavePath.Length > 20)
|
|
{
|
|
return ApiResult.Fail("保存文件夹名称最长 20 个字符");
|
|
}
|
|
if (!DouyinFileNameHelper.IsValidWithoutSpecialChars(followed.SavePath))
|
|
{
|
|
return ApiResult.Fail("保存文件夹名称只能包含字母、数字或中文");
|
|
}
|
|
}
|
|
|
|
var result = await _douyinFollowService.TryAddAsync(followed);
|
|
return result switch
|
|
{
|
|
AddFollowResult.Added => ApiResult.Success("新增非关注博主成功"),
|
|
AddFollowResult.AlreadyExists => ApiResult.Fail("该博主已存在,无需重复添加"),
|
|
_ => ApiResult.Fail("添加失败,请稍后重试")
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 使用展示在抖音资料页上的抖音号查找博主。结果需要用户确认后再调用 add。
|
|
/// </summary>
|
|
[HttpPost("resolve-by-douyin-no")]
|
|
public async Task<IActionResult> ResolveByDouyinNo(
|
|
DouyinFollowLookupRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var result = await _douyinUserLookupService.ResolveAsync(request, cancellationToken);
|
|
return ApiResult.Success(result);
|
|
}
|
|
catch (InvalidOperationException ex)
|
|
{
|
|
return ApiResult.Fail(ex.Message);
|
|
}
|
|
}
|
|
|
|
private static string Limit(string value, int maxLength)
|
|
{
|
|
value = value?.Trim();
|
|
return value != null && value.Length > maxLength ? value[..maxLength] : value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 修改关注同步状态
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("openOrCloseSync")]
|
|
public async Task<IActionResult> OpenOrCloseSync(FollowUpdateDto dto)
|
|
{
|
|
|
|
if (dto.OpenSync)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(dto.SavePath))
|
|
{
|
|
if (!DouyinFileNameHelper.IsValidWithoutSpecialChars(dto.SavePath))
|
|
{
|
|
return ApiResult.Fail("请输入有效文件夹名称(字母数字中文简体)");
|
|
}
|
|
|
|
if (dto.SavePath.Length > 20)
|
|
{
|
|
return ApiResult.Fail("请输入有效文件夹名称(最长20)");
|
|
}
|
|
}
|
|
}
|
|
var result = await _douyinFollowService.OpenOrCloseSync(dto);
|
|
return ApiResult.SuccOrFail(result, result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 修改关注全量同步状态
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("openOrCloseFullSync")]
|
|
public async Task<IActionResult> OpenOrCloseFullSync(FollowUpdateDto dto)
|
|
{
|
|
return await OpenOrCloseSync(dto);
|
|
}
|
|
|
|
[HttpPost("live-monitor")]
|
|
public async Task<IActionResult> UpdateLiveMonitor(
|
|
FollowLiveMonitorUpdateDto dto,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
return ApiResult.Success(await _douyinLiveStatusService.SetMonitorAsync(dto, cancellationToken));
|
|
}
|
|
catch (Exception ex) when (ex is InvalidOperationException or KeyNotFoundException)
|
|
{
|
|
return ApiResult.Fail(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("live-status/refresh")]
|
|
public async Task<IActionResult> RefreshLiveStatus(
|
|
FollowLiveStatusRefreshDto dto,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
if (dto == null || string.IsNullOrWhiteSpace(dto.Id))
|
|
return ApiResult.Fail("博主记录不能为空");
|
|
return ApiResult.Success(await _douyinLiveStatusService.RefreshAsync(dto.Id, cancellationToken));
|
|
}
|
|
catch (Exception ex) when (ex is InvalidOperationException or KeyNotFoundException)
|
|
{
|
|
return ApiResult.Fail(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("live-status/query")]
|
|
public async Task<IActionResult> QueryLiveStatus(FollowLiveStatusQueryDto dto)
|
|
{
|
|
if (dto?.Ids == null || dto.Ids.Count == 0)
|
|
return ApiResult.Success(Array.Empty<FollowLiveStatusDto>());
|
|
return ApiResult.Success(await _douyinLiveStatusService.QueryAsync(dto.Ids));
|
|
}
|
|
|
|
[HttpPost("live-email")]
|
|
public async Task<IActionResult> UpdateLiveEmail(FollowLiveEmailUpdateDto dto)
|
|
{
|
|
try
|
|
{
|
|
return ApiResult.Success(await _douyinLiveStatusService.SetEmailNotificationAsync(dto));
|
|
}
|
|
catch (Exception ex) when (ex is InvalidOperationException or KeyNotFoundException)
|
|
{
|
|
return ApiResult.Fail(ex.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除关注对象
|
|
/// </summary>
|
|
/// <param name="dto"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("delete")]
|
|
public async Task<IActionResult> DeleteFollow(FollowUpdateDto dto)
|
|
{
|
|
var result = await _douyinFollowService.DeleteFollow(dto);
|
|
return ApiResult.SuccOrFail(result, result);
|
|
}
|
|
}
|
|
}
|