0848ebc272
部署到群晖 / deploy (push) Successful in 32s
新增 DyQrCodeService,调用 sso.douyin.com 二维码接口; ConfigController 新增 qrcode/qrstatus/qrbind 三个接口; 前端账号列表每行增加"扫码登录"按钮,展示二维码弹窗并自动轮询绑定。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
300 lines
10 KiB
C#
300 lines
10 KiB
C#
using ClockSnowFlake;
|
|
using dy.net.dto;
|
|
using dy.net.model;
|
|
using dy.net.service;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Newtonsoft.Json;
|
|
using static Dm.net.buffer.ByteArrayBuffer;
|
|
|
|
namespace dy.net.Controllers
|
|
{
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
public class ConfigController : ControllerBase
|
|
{
|
|
private readonly DyCookieService dyCookieService;
|
|
|
|
private readonly CommonService commonService;
|
|
private readonly QuartzJobService quartzJobService;
|
|
private readonly DyQrCodeService _qrCodeService;
|
|
|
|
public ConfigController(DyCookieService dyCookieService, CommonService commonService, QuartzJobService quartzJobService, DyQrCodeService qrCodeService)
|
|
{
|
|
this.dyCookieService = dyCookieService;
|
|
this.commonService = commonService;
|
|
this.quartzJobService = quartzJobService;
|
|
_qrCodeService = qrCodeService;
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 分页查询
|
|
/// </summary>
|
|
/// <returns>分页结果(视频列表和总数)</returns>
|
|
[HttpPost("paged")]
|
|
public async Task<IActionResult> GetPagedAsync(
|
|
PageRequestDto dto)
|
|
{
|
|
var (list, totalCount) = await dyCookieService.GetPagedAsync(dto.PageIndex, dto.PageSize);
|
|
return Ok(new
|
|
{
|
|
code = 0,
|
|
data = new
|
|
{
|
|
data = list,
|
|
total=totalCount,
|
|
pageIndex= dto.PageIndex,
|
|
pageSize= dto.PageSize
|
|
}
|
|
}
|
|
);
|
|
}
|
|
/// <summary>
|
|
/// 新增用户Cookie
|
|
/// </summary>
|
|
[HttpPost("add")]
|
|
public async Task<IActionResult> AddAsync([FromBody] DyUserCookies dyUserCookies)
|
|
{
|
|
if(dyUserCookies.UpSecUserIdsJson!=null)
|
|
{
|
|
dyUserCookies.UpSecUserIds = JsonConvert.SerializeObject( dyUserCookies.UpSecUserIdsJson);
|
|
}
|
|
var result = await dyCookieService.Add(dyUserCookies);
|
|
if (result)
|
|
{
|
|
await ReStartJob();
|
|
return Ok(new { code = 0 });
|
|
}
|
|
return BadRequest(new { code=-1, message = "添加失败" });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新用户Cookie
|
|
/// </summary>
|
|
[HttpPost("update")]
|
|
public async Task<IActionResult> UpdateAsync([FromBody] DyUserCookies dyUserCookies)
|
|
{
|
|
|
|
if (dyUserCookies.UpSecUserIdsJson != null )
|
|
{
|
|
dyUserCookies.UpSecUserIds = JsonConvert.SerializeObject(dyUserCookies.UpSecUserIdsJson);
|
|
}
|
|
|
|
if (dyUserCookies.Id == "0")
|
|
{
|
|
dyUserCookies.Id=IdGener.GetLong().ToString();
|
|
var result = await dyCookieService.Add(dyUserCookies);
|
|
if (result)
|
|
{
|
|
await ReStartJob();
|
|
return Ok(new { code = 0 });
|
|
}
|
|
return BadRequest(new { code = -1, message = "添加失败" });
|
|
}
|
|
else {
|
|
var result = await dyCookieService.UpdateAsync(dyUserCookies);
|
|
if (result)
|
|
{
|
|
await ReStartJob();
|
|
return Ok(new { code = 0 });
|
|
}
|
|
return BadRequest(new { code = -1, message = "更新失败" });
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量删除用户Cookie
|
|
/// </summary>
|
|
[HttpGet("delete")]
|
|
public async Task<IActionResult> DeleteAsync(string id)
|
|
{
|
|
var count = await dyCookieService.DeleteByIdsAsync(new List<string> { id});
|
|
if (count > 0) {
|
|
await ReStartJob();
|
|
}
|
|
return Ok(new { code = 0, deletedCount = count });
|
|
}
|
|
|
|
[HttpGet("GetConfig")]
|
|
public IActionResult GetConfig()
|
|
{
|
|
var data = commonService.GetConfig();
|
|
return Ok(new { code = 0, data = data });
|
|
}
|
|
|
|
[HttpPost("UpdateConfig")]
|
|
public async Task<IActionResult> UpdateConfig(AppConfig config)
|
|
{
|
|
var data = await commonService.UpdateConfig(config);
|
|
if (data) {
|
|
await ReStartJob();
|
|
}
|
|
return Ok(new { code = 0, data = data });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 立即执行同步任务
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("ExecuteJobNow")]
|
|
[Authorize]
|
|
public async Task<IActionResult> ExecuteJobNow()
|
|
{
|
|
var config = commonService.GetConfig();
|
|
await quartzJobService.StartJob(config.Cron);
|
|
return Ok(new { code = 0 , error = "" });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置指定Cookie的同步状态,强制重新同步
|
|
/// </summary>
|
|
/// <param name="id">Cookie ID</param>
|
|
/// <param name="type">重置类型:collect=收藏, favorite=喜欢, all=全部</param>
|
|
/// <returns></returns>
|
|
[Authorize]
|
|
[HttpPost("ResetSyncStatus")]
|
|
public async Task<IActionResult> ResetSyncStatus(string id, string type = "all")
|
|
{
|
|
try
|
|
{
|
|
var cookie = await dyCookieService.GetByIdAsync(id);
|
|
if (cookie == null)
|
|
{
|
|
return BadRequest(new { code = -1, error = "Cookie不存在" });
|
|
}
|
|
|
|
if (type == "collect" || type == "all")
|
|
{
|
|
cookie.CollHasSyncd = 0;
|
|
}
|
|
if (type == "favorite" || type == "all")
|
|
{
|
|
cookie.FavHasSyncd = 0;
|
|
}
|
|
if (type == "all")
|
|
{
|
|
cookie.UperSyncd = 0;
|
|
}
|
|
|
|
var result = await dyCookieService.UpdateAsync(cookie);
|
|
if (result)
|
|
{
|
|
Serilog.Log.Information($"重置Cookie[{cookie.UserName}]的同步状态,类型: {type}");
|
|
return Ok(new { code = 0, message = "同步状态已重置" });
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(new { code = -1, error = "重置失败" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Serilog.Log.Error(ex, "重置同步状态失败");
|
|
return StatusCode(500, new { code = -1, error = "重置失败:" + ex.Message });
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取抖音扫码登录二维码
|
|
/// </summary>
|
|
[HttpGet("qrcode")]
|
|
[Authorize]
|
|
public async Task<IActionResult> GetQrCode()
|
|
{
|
|
try
|
|
{
|
|
var (token, qrBase64) = await _qrCodeService.GetQrCodeAsync();
|
|
return Ok(new { code = 0, data = new { token, qrBase64 } });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Serilog.Log.Error($"获取二维码失败: {ex.Message}");
|
|
return Ok(new { code = -1, error = "获取二维码失败:" + ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 轮询扫码状态(前端每2秒调一次)
|
|
/// status: 1=待扫码, 2=已扫码待确认, 3=登录成功, -1=已过期
|
|
/// </summary>
|
|
[HttpGet("qrstatus")]
|
|
[Authorize]
|
|
public async Task<IActionResult> GetQrStatus([FromQuery] string token)
|
|
{
|
|
try
|
|
{
|
|
var (status, cookies, secUserId) = await _qrCodeService.CheckStatusAsync(token);
|
|
return Ok(new { code = 0, data = new { status, hasCookies = !string.IsNullOrEmpty(cookies), secUserId } });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Serilog.Log.Error($"查询扫码状态失败: {ex.Message}");
|
|
return Ok(new { code = -1, error = "查询失败:" + ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 扫码成功后,将 Cookie 绑定到指定账号
|
|
/// </summary>
|
|
[HttpPost("qrbind")]
|
|
[Authorize]
|
|
public async Task<IActionResult> BindQrCode([FromQuery] string token, [FromQuery] string id)
|
|
{
|
|
try
|
|
{
|
|
var (cookies, secUserId) = _qrCodeService.GetSessionResult(token);
|
|
if (string.IsNullOrEmpty(cookies))
|
|
return Ok(new { code = -1, error = "扫码尚未完成或已过期" });
|
|
|
|
var account = await dyCookieService.GetByIdAsync(id);
|
|
if (account == null)
|
|
return Ok(new { code = -1, error = "账号不存在" });
|
|
|
|
account.Cookies = cookies;
|
|
if (!string.IsNullOrEmpty(secUserId))
|
|
account.SecUserId = secUserId;
|
|
account.Status = 1;
|
|
|
|
var result = await dyCookieService.UpdateAsync(account);
|
|
_qrCodeService.RemoveSession(token);
|
|
|
|
if (result)
|
|
{
|
|
await ReStartJob();
|
|
return Ok(new { code = 0, data = new { secUserId } });
|
|
}
|
|
return Ok(new { code = -1, error = "保存失败" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Serilog.Log.Error($"绑定Cookie失败: {ex.Message}");
|
|
return Ok(new { code = -1, error = "绑定失败:" + ex.Message });
|
|
}
|
|
}
|
|
|
|
private async Task ReStartJob() {
|
|
var config= commonService.GetConfig();
|
|
|
|
//var cookies = await dyCookieService.GetAllCookies();
|
|
//重置同步状态
|
|
//foreach (var cookie in cookies)
|
|
//{
|
|
// cookie.CollHasSyncd = 0;
|
|
// cookie.FavHasSyncd = 0;
|
|
// cookie.UperSyncd = 0;
|
|
// await dyCookieService.UpdateAsync(cookie);
|
|
//}
|
|
|
|
if (config!=null)
|
|
quartzJobService.StartJob(config.Cron);
|
|
//避免前端等待
|
|
}
|
|
}
|
|
}
|