feat(watch): 支持设备观看与登录合并
This commit is contained in:
1 parent
4b0fbd73d3
commit
848c746505
14 files changed
+613
-70
No files matched your search
+8
-2
@@ -59,9 +59,15 @@ public class AppFavoriteController {
|
||||
@GetMapping
|
||||
public Result<PageResult<AppDramaCardVO>> list(
|
||||
@RequestParam(defaultValue = "1") int pageIndex,
|
||||
@RequestParam(defaultValue = "20") int pageSize) {
|
||||
@RequestParam(defaultValue = "20") int pageSize,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
deviceId);
|
||||
PageResult<Drama> page = favoriteService.page(
|
||||
SecurityUtils.getAppUserId(), pageIndex, pageSize);
|
||||
identity, pageIndex, pageSize);
|
||||
return Result.ok(new PageResult<>(
|
||||
page.getTotal(), appCatalogService.toCards(page.getList())));
|
||||
}
|
||||
|
||||
+50
-10
@@ -4,6 +4,9 @@ package com.fruitshorts.app.controller;
|
||||
|
||||
import com.fruitshorts.common.pojo.PageResult;
|
||||
import com.fruitshorts.common.pojo.Result;
|
||||
import com.fruitshorts.common.interaction.InteractionIdentity;
|
||||
import com.fruitshorts.app.service.AnonymousInteractionRateLimiter;
|
||||
import com.fruitshorts.framework.interaction.InteractionIdentityResolver;
|
||||
import com.fruitshorts.framework.security.SecurityUtils;
|
||||
import com.fruitshorts.playback.service.WatchProgressService;
|
||||
import com.fruitshorts.playback.vo.ProgressRespVO;
|
||||
@@ -11,6 +14,7 @@ import com.fruitshorts.playback.vo.ProgressSaveReqVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -29,19 +33,34 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class AppWatchController {
|
||||
|
||||
private final WatchProgressService progressService;
|
||||
private final InteractionIdentityResolver identityResolver;
|
||||
private final AnonymousInteractionRateLimiter anonymousRateLimiter;
|
||||
|
||||
/** 上报进度:客户端每 10 秒一次,切集时立即上报一次。 */
|
||||
@Operation(summary = "上报观看进度(客户端每 10 秒一次)")
|
||||
@PostMapping("/progress")
|
||||
public Result<ProgressRespVO> save(@Valid @RequestBody ProgressSaveReqVO req) {
|
||||
return Result.ok(progressService.save(SecurityUtils.getAppUserId(), req));
|
||||
public Result<ProgressRespVO> save(@Valid @RequestBody ProgressSaveReqVO req,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
req.getDeviceId());
|
||||
anonymousRateLimiter.check(identity, "watch");
|
||||
return Result.ok(progressService.save(identity, req));
|
||||
}
|
||||
|
||||
/** 某部剧的续看位置,进详情页时用它决定"续看第 N 集"。 */
|
||||
@Operation(summary = "某部剧的续看位置")
|
||||
@GetMapping("/progress")
|
||||
public Result<ProgressRespVO> ofDrama(@RequestParam Long dramaId) {
|
||||
return Result.ok(progressService.ofDrama(SecurityUtils.getAppUserId(), dramaId));
|
||||
public Result<ProgressRespVO> ofDrama(
|
||||
@RequestParam Long dramaId,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
deviceId);
|
||||
return Result.ok(progressService.ofDrama(identity, dramaId));
|
||||
}
|
||||
|
||||
/** 最近观看分页,契约与 /app/favorites 一致:pageIndex/pageSize。 */
|
||||
@@ -49,22 +68,43 @@ public class AppWatchController {
|
||||
@GetMapping("/recent")
|
||||
public Result<PageResult<ProgressRespVO>> recent(
|
||||
@RequestParam(defaultValue = "1") int pageIndex,
|
||||
@RequestParam(defaultValue = "20") int pageSize) {
|
||||
@RequestParam(defaultValue = "20") int pageSize,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
deviceId);
|
||||
return Result.ok(progressService.recentPage(
|
||||
SecurityUtils.getAppUserId(), pageIndex, pageSize));
|
||||
identity, pageIndex, pageSize));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除某部剧的观看记录")
|
||||
@DeleteMapping("/progress/{dramaId}")
|
||||
public Result<Void> remove(@PathVariable Long dramaId) {
|
||||
progressService.remove(SecurityUtils.getAppUserId(), dramaId);
|
||||
public Result<Void> remove(
|
||||
@PathVariable Long dramaId,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
deviceId);
|
||||
anonymousRateLimiter.check(identity, "watch");
|
||||
progressService.remove(identity, dramaId);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "清空观看记录")
|
||||
@DeleteMapping("/progress")
|
||||
public Result<Void> clear() {
|
||||
progressService.clear(SecurityUtils.getAppUserId());
|
||||
public Result<Void> clear(
|
||||
@RequestParam(required = false) String deviceId,
|
||||
HttpServletRequest request) {
|
||||
InteractionIdentity identity = identityResolver.resolve(
|
||||
SecurityUtils.getUserIdOrNull(),
|
||||
request.getHeader("X-Device-Id"),
|
||||
deviceId);
|
||||
anonymousRateLimiter.check(identity, "watch");
|
||||
progressService.clear(identity);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -5,6 +5,7 @@ package com.fruitshorts.app.service;
|
||||
import com.fruitshorts.interaction.service.CommentService;
|
||||
import com.fruitshorts.interaction.service.LikeService;
|
||||
import com.fruitshorts.playback.service.FavoriteService;
|
||||
import com.fruitshorts.playback.service.WatchProgressService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -19,6 +20,7 @@ public class InteractionAccountMergeService {
|
||||
private final LikeService likeService;
|
||||
private final FavoriteService favoriteService;
|
||||
private final CommentService commentService;
|
||||
private final WatchProgressService watchProgressService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void merge(Long userId, String deviceId) {
|
||||
@@ -27,11 +29,15 @@ public class InteractionAccountMergeService {
|
||||
favoriteService.mergeDeviceIntoUser(userId, deviceId);
|
||||
CommentService.MergeResult comments =
|
||||
commentService.mergeDeviceIntoUser(userId, deviceId);
|
||||
WatchProgressService.MergeResult watch =
|
||||
watchProgressService.mergeDeviceIntoUser(userId, deviceId);
|
||||
log.info(
|
||||
"interaction-merge userId={} deviceId={} "
|
||||
+ "likeMigrated={} likeDuplicates={} "
|
||||
+ "favoriteMigrated={} favoriteDuplicates={} "
|
||||
+ "commentMigrated={} commentDuplicates={}",
|
||||
+ "commentMigrated={} commentDuplicates={} "
|
||||
+ "watchProgressMigrated={} watchProgressIgnored={} "
|
||||
+ "watchHistoryMigrated={} watchHistoryIgnored={}",
|
||||
userId,
|
||||
deviceId,
|
||||
likes.migrated(),
|
||||
@@ -39,6 +45,10 @@ public class InteractionAccountMergeService {
|
||||
favorites.migrated(),
|
||||
favorites.duplicates(),
|
||||
comments.migrated(),
|
||||
comments.duplicates());
|
||||
comments.duplicates(),
|
||||
watch.progressMigrated(),
|
||||
watch.progressIgnored(),
|
||||
watch.historyMigrated(),
|
||||
watch.historyIgnored());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user