diff --git a/src/main/java/site/youtogether/config/WebConfig.java b/src/main/java/site/youtogether/config/WebConfig.java index b323db8..4edf6a5 100644 --- a/src/main/java/site/youtogether/config/WebConfig.java +++ b/src/main/java/site/youtogether/config/WebConfig.java @@ -26,7 +26,11 @@ public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOrigins("http://localhost:3000", "https://you-together-web.vercel.app", "https://localhost:3001") + .allowedOrigins("http://localhost:3000", + "https://you-together-web.vercel.app", + "https://localhost:3001", + "https://you-together.site", + "https://www.you-together.site") .allowedMethods("*") .allowCredentials(true) .exposedHeaders(HttpHeaders.AUTHORIZATION) diff --git a/src/main/java/site/youtogether/config/WebSocketConfig.java b/src/main/java/site/youtogether/config/WebSocketConfig.java index 4a87b79..efa4bc2 100644 --- a/src/main/java/site/youtogether/config/WebSocketConfig.java +++ b/src/main/java/site/youtogether/config/WebSocketConfig.java @@ -27,7 +27,11 @@ public void configureMessageBroker(MessageBrokerRegistry registry) { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(STOMP_ENDPOINT) - .setAllowedOriginPatterns("http://localhost:3000", "https://you-together-web.vercel.app", "https://localhost:3001") + .setAllowedOriginPatterns("http://localhost:3000", + "https://you-together-web.vercel.app", + "https://localhost:3001", + "https://you-together.site", + "https://www.you-together.site") .addInterceptors(stompHandshakeInterceptor) .withSockJS(); } diff --git a/src/main/java/site/youtogether/message/VideoSyncInfoMessage.java b/src/main/java/site/youtogether/message/VideoSyncInfoMessage.java index 763a1b8..4a66228 100644 --- a/src/main/java/site/youtogether/message/VideoSyncInfoMessage.java +++ b/src/main/java/site/youtogether/message/VideoSyncInfoMessage.java @@ -1,11 +1,13 @@ package site.youtogether.message; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; -import site.youtogether.playlist.PlayerState; +import site.youtogether.player.PlayingVideo; +import site.youtogether.player.handler.PlayerState; -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PACKAGE) @Getter public class VideoSyncInfoMessage { @@ -19,4 +21,37 @@ public class VideoSyncInfoMessage { private final double playerCurrentTime; private final double playerRate; + public static VideoSyncInfoMessage ofPlay(PlayingVideo playingVideo, double currentTime) { + return new VideoSyncInfoMessage( + playingVideo.roomCode(), + playingVideo.number(), + playingVideo.id(), + PlayerState.PLAY, + currentTime, + playingVideo.rate() + ); + } + + public static VideoSyncInfoMessage ofPause(PlayingVideo playingVideo) { + return new VideoSyncInfoMessage( + playingVideo.roomCode(), + playingVideo.number(), + playingVideo.id(), + PlayerState.PAUSE, + playingVideo.startTime(), + playingVideo.rate() + ); + } + + public static VideoSyncInfoMessage ofEnd(PlayingVideo playingVideo) { + return new VideoSyncInfoMessage( + playingVideo.roomCode(), + playingVideo.number(), + playingVideo.id(), + PlayerState.END, + playingVideo.duration(), + playingVideo.rate() + ); + } + } diff --git a/src/main/java/site/youtogether/message/presentation/MessageController.java b/src/main/java/site/youtogether/message/presentation/MessageController.java index 3b84951..70eaeeb 100644 --- a/src/main/java/site/youtogether/message/presentation/MessageController.java +++ b/src/main/java/site/youtogether/message/presentation/MessageController.java @@ -13,7 +13,7 @@ import site.youtogether.message.ChatMessage; import site.youtogether.message.VideoSyncInfoMessage; import site.youtogether.message.application.MessageService; -import site.youtogether.playlist.application.PlayingVideoService; +import site.youtogether.player.application.VideoPlayerService; import site.youtogether.user.User; import site.youtogether.user.infrastructure.UserStorage; import site.youtogether.util.RandomUtil; @@ -24,7 +24,7 @@ public class MessageController { private final UserStorage userStorage; private final MessageService messageService; - private final PlayingVideoService playingVideoService; + private final VideoPlayerService videoPlayerService; @MessageMapping("/messages/chat") public void handleChatMessage(ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) { @@ -53,7 +53,7 @@ public void handleVideoSyncMessage(VideoSyncInfoMessage videoSyncInfoMessage, Si } videoSyncInfoMessage.setRoomCode(user.getCurrentRoomCode()); - playingVideoService.manageVideo(videoSyncInfoMessage); + videoPlayerService.control(videoSyncInfoMessage); } } diff --git a/src/main/java/site/youtogether/message/presentation/MessageEventListener.java b/src/main/java/site/youtogether/message/presentation/MessageEventListener.java index 1cc2883..8c691bb 100644 --- a/src/main/java/site/youtogether/message/presentation/MessageEventListener.java +++ b/src/main/java/site/youtogether/message/presentation/MessageEventListener.java @@ -36,7 +36,7 @@ public void handleWebSocketSubscriberListener(SessionSubscribeEvent event) { Long userId = (Long)headerAccessor.getSessionAttributes().get(USER_ID); User user = userStorage.findById(userId) .orElseThrow(UserNoExistenceException::new); - log.info("--USER {} 웹 소켓 구독 시작--", userId); + log.info("--USER {} ROOM {} 웹 소켓 구독 시작--", userId, roomCode); messageService.sendParticipants(roomCode); messageService.sendPlaylist(roomCode); @@ -52,7 +52,7 @@ public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) { User user = userStorage.findById(userId) .orElseThrow(UserNoExistenceException::new); - log.info("--USER {} 웹 소켓 커넥션 종료 시도--", userId); + log.info("--USER {} ROOM {} 웹 소켓 커넥션 종료 시도--", userId, roomCode); roomService.leave(userId); messageService.sendParticipants(roomCode); } diff --git a/src/main/java/site/youtogether/player/PlayingVideo.java b/src/main/java/site/youtogether/player/PlayingVideo.java new file mode 100644 index 0000000..d307d33 --- /dev/null +++ b/src/main/java/site/youtogether/player/PlayingVideo.java @@ -0,0 +1,47 @@ +package site.youtogether.player; + +import site.youtogether.playlist.Video; + +public record PlayingVideo( + String roomCode, + String id, + Long number, + double startTime, + double rate, + double duration) { + + private static final double ZERO_SECOND = 0.0; + private static final double DEFAULT_RATE = 1.0; + + public static PlayingVideo updateStartTime(PlayingVideo playingVideo, double startTime) { + return new PlayingVideo( + playingVideo.roomCode(), + playingVideo.id(), + playingVideo.number(), + startTime, + playingVideo.rate(), + playingVideo.duration()); + } + + public static PlayingVideo updateRate(PlayingVideo playingVideo, double rate) { + return new PlayingVideo( + playingVideo.roomCode(), + playingVideo.id(), + playingVideo.number(), + playingVideo.startTime(), + rate, + playingVideo.duration()); + } + + public static PlayingVideo from(String roomCode, Video video) { + return new PlayingVideo( + roomCode, + video.id(), + video.number(), + ZERO_SECOND, + DEFAULT_RATE, + video.duration() + ); + } + +} diff --git a/src/main/java/site/youtogether/player/VideoPlayer.java b/src/main/java/site/youtogether/player/VideoPlayer.java new file mode 100644 index 0000000..83612a1 --- /dev/null +++ b/src/main/java/site/youtogether/player/VideoPlayer.java @@ -0,0 +1,69 @@ +package site.youtogether.player; + +import static site.youtogether.player.handler.PlayerState.*; + +import java.util.Timer; + +import site.youtogether.player.application.VideoSynchronizer; +import site.youtogether.player.handler.PlayerState; + +public class VideoPlayer { + + private final String roomCode; + private final VideoSynchronizer videoSynchronizer; + private final Timer timer; + private PlayerState state; + private PlayingVideo playingVideo; + + public VideoPlayer(String roomCode, VideoSynchronizer videoSynchronizer) { + this.roomCode = roomCode; + this.videoSynchronizer = videoSynchronizer; + this.timer = new Timer(); + this.state = END; + } + + // 영상을 일시정지합니다 + public void pauseVideo(PlayingVideo playingVideo) { + if (playingVideo == null) + return; + + videoSynchronizer.pause(timer, playingVideo); + state = PAUSE; + } + + // 영상을 재생합니다 + public void playVideo(PlayingVideo playingVideo) { + switchVideo(playingVideo); + videoSynchronizer.play(timer, playingVideo); + state = PLAY; + } + + public void stopVideo() { + if (playingVideo != null) { + videoSynchronizer.stop(timer, playingVideo); + state = END; + playingVideo = null; + } + } + + public void switchVideo(PlayingVideo playingVideo) { + boolean wasPlaying = state == PLAY; + boolean isNewVideo = !this.playingVideo.number().equals(playingVideo.number()); + // 재생 중인 영상이 있다면 우선 중지합니다 + stopVideo(); + this.playingVideo = playingVideo; + + if (wasPlaying || isNewVideo) { + playVideo(playingVideo); + } + } + + public String getRoomCode() { + return this.roomCode; + } + + public PlayingVideo getPlayingVideo() { + return playingVideo; + } + +} diff --git a/src/main/java/site/youtogether/player/application/SynchronizerTask.java b/src/main/java/site/youtogether/player/application/SynchronizerTask.java new file mode 100644 index 0000000..c018a1d --- /dev/null +++ b/src/main/java/site/youtogether/player/application/SynchronizerTask.java @@ -0,0 +1,36 @@ +package site.youtogether.player.application; + +import java.util.TimerTask; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.PlayingVideo; + +public abstract class SynchronizerTask extends TimerTask { + + private static final double EMPTY = 0.0; + + private final PlayingVideo playingVideo; + private double currentTime; + + public SynchronizerTask(PlayingVideo playingVideo) { + this.playingVideo = playingVideo; + this.currentTime = playingVideo.startTime(); + } + + public VideoSyncInfoMessage getSyncMessage() { + return VideoSyncInfoMessage.ofPlay(playingVideo, currentTime); + } + + public boolean isLiveStream() { + return playingVideo.duration() == EMPTY; + } + + public void incrementTime() { + ++currentTime; + } + + public double getCurrentTime() { + return currentTime; + } + +} diff --git a/src/main/java/site/youtogether/player/application/VideoPlayerService.java b/src/main/java/site/youtogether/player/application/VideoPlayerService.java new file mode 100644 index 0000000..81590a6 --- /dev/null +++ b/src/main/java/site/youtogether/player/application/VideoPlayerService.java @@ -0,0 +1,22 @@ +package site.youtogether.player.application; + +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.VideoPlayer; +import site.youtogether.player.handler.PlayerState; +import site.youtogether.player.infrastructure.VideoPlayerStorage; + +@Service +@RequiredArgsConstructor +public class VideoPlayerService { + + private final VideoPlayerStorage videoPlayerStorage; + + public void control(VideoSyncInfoMessage message) { + VideoPlayer videoPlayer = videoPlayerStorage.findByRoomCode(message.getRoomCode()); + PlayerState.handlerOf(message.getPlayerState()).handle(videoPlayer, message); + } + +} diff --git a/src/main/java/site/youtogether/player/application/VideoSynchronizer.java b/src/main/java/site/youtogether/player/application/VideoSynchronizer.java new file mode 100644 index 0000000..5c1b1cd --- /dev/null +++ b/src/main/java/site/youtogether/player/application/VideoSynchronizer.java @@ -0,0 +1,49 @@ +package site.youtogether.player.application; + +import java.util.Timer; + +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.message.application.MessageService; +import site.youtogether.player.PlayingVideo; + +@Component +@RequiredArgsConstructor +public class VideoSynchronizer { + + private static final long NO_DELAY = 0; + private static final long ONE_SECOND = 1_000; + + private final MessageService messageService; + + public void pause(Timer timer, PlayingVideo playingVideo) { + timer.cancel(); + + // 일시정지 메세지를 1회 전송합니다 + messageService.sendVideoSyncInfo(VideoSyncInfoMessage.ofPause(playingVideo)); + } + + public void play(Timer timer, PlayingVideo playingVideo) { + // 1초마다 재생 메세지를 전송합니다 + timer.scheduleAtFixedRate(new SynchronizerTask(playingVideo) { + @Override + public void run() { + if (this.isLiveStream() || this.getCurrentTime() < playingVideo.duration()) { + messageService.sendVideoSyncInfo(this.getSyncMessage()); + } + + this.incrementTime(); + } + }, NO_DELAY, Math.round(ONE_SECOND / playingVideo.rate())); + } + + public void stop(Timer timer, PlayingVideo playingVideo) { + timer.cancel(); + + // 종료 메세지를 1회 전송합니다 + messageService.sendVideoSyncInfo(VideoSyncInfoMessage.ofEnd(playingVideo)); + } + +} diff --git a/src/main/java/site/youtogether/player/handler/EndStateHandler.java b/src/main/java/site/youtogether/player/handler/EndStateHandler.java new file mode 100644 index 0000000..5ab8651 --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/EndStateHandler.java @@ -0,0 +1,13 @@ +package site.youtogether.player.handler; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.VideoPlayer; + +public class EndStateHandler implements PlayerStateHandler { + + @Override + public void handle(VideoPlayer videoPlayer, VideoSyncInfoMessage message) { + videoPlayer.stopVideo(); + } + +} diff --git a/src/main/java/site/youtogether/player/handler/PauseStateHandler.java b/src/main/java/site/youtogether/player/handler/PauseStateHandler.java new file mode 100644 index 0000000..0464b9e --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/PauseStateHandler.java @@ -0,0 +1,16 @@ +package site.youtogether.player.handler; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.PlayingVideo; +import site.youtogether.player.VideoPlayer; + +public class PauseStateHandler implements PlayerStateHandler { + + @Override + public void handle(VideoPlayer videoPlayer, VideoSyncInfoMessage message) { + PlayingVideo playingVideo = PlayingVideo.updateStartTime(videoPlayer.getPlayingVideo(), message.getPlayerCurrentTime()); + + videoPlayer.pauseVideo(playingVideo); + } + +} diff --git a/src/main/java/site/youtogether/player/handler/PlayStateHandler.java b/src/main/java/site/youtogether/player/handler/PlayStateHandler.java new file mode 100644 index 0000000..36a735e --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/PlayStateHandler.java @@ -0,0 +1,16 @@ +package site.youtogether.player.handler; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.PlayingVideo; +import site.youtogether.player.VideoPlayer; + +public class PlayStateHandler implements PlayerStateHandler { + + @Override + public void handle(VideoPlayer videoPlayer, VideoSyncInfoMessage message) { + PlayingVideo playingVideo = PlayingVideo.updateStartTime(videoPlayer.getPlayingVideo(), message.getPlayerCurrentTime()); + + videoPlayer.playVideo(playingVideo); + } + +} diff --git a/src/main/java/site/youtogether/player/handler/PlayerState.java b/src/main/java/site/youtogether/player/handler/PlayerState.java new file mode 100644 index 0000000..62a26db --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/PlayerState.java @@ -0,0 +1,20 @@ +package site.youtogether.player.handler; + +public enum PlayerState { + + PLAY(new PlayStateHandler()), + PAUSE(new PauseStateHandler()), + END(new EndStateHandler()), + RATE(new RateStateHandler()); + + private final PlayerStateHandler handler; + + PlayerState(PlayerStateHandler handler) { + this.handler = handler; + } + + public static PlayerStateHandler handlerOf(PlayerState playerState) { + return playerState.handler; + } + +} diff --git a/src/main/java/site/youtogether/player/handler/PlayerStateHandler.java b/src/main/java/site/youtogether/player/handler/PlayerStateHandler.java new file mode 100644 index 0000000..5fb2026 --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/PlayerStateHandler.java @@ -0,0 +1,10 @@ +package site.youtogether.player.handler; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.VideoPlayer; + +public interface PlayerStateHandler { + + void handle(VideoPlayer videoPlayer, VideoSyncInfoMessage message); + +} diff --git a/src/main/java/site/youtogether/player/handler/RateStateHandler.java b/src/main/java/site/youtogether/player/handler/RateStateHandler.java new file mode 100644 index 0000000..ef33a73 --- /dev/null +++ b/src/main/java/site/youtogether/player/handler/RateStateHandler.java @@ -0,0 +1,16 @@ +package site.youtogether.player.handler; + +import site.youtogether.message.VideoSyncInfoMessage; +import site.youtogether.player.PlayingVideo; +import site.youtogether.player.VideoPlayer; + +public class RateStateHandler implements PlayerStateHandler { + + @Override + public void handle(VideoPlayer videoPlayer, VideoSyncInfoMessage message) { + PlayingVideo playingVideo = PlayingVideo.updateRate(videoPlayer.getPlayingVideo(), message.getPlayerRate()); + + videoPlayer.switchVideo(playingVideo); + } + +} diff --git a/src/main/java/site/youtogether/player/infrastructure/VideoPlayerStorage.java b/src/main/java/site/youtogether/player/infrastructure/VideoPlayerStorage.java new file mode 100644 index 0000000..a536a35 --- /dev/null +++ b/src/main/java/site/youtogether/player/infrastructure/VideoPlayerStorage.java @@ -0,0 +1,44 @@ +package site.youtogether.player.infrastructure; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Repository; + +import lombok.RequiredArgsConstructor; +import site.youtogether.player.VideoPlayer; +import site.youtogether.player.application.VideoSynchronizer; + +@Repository +@RequiredArgsConstructor +public class VideoPlayerStorage { + + // key: String roomCode - value: VideoPlayer + private final Map storage = new ConcurrentHashMap<>(); + private final VideoSynchronizer videoSynchronizer; + + public boolean existsByRoomCode(String roomCode) { + return storage.containsKey(roomCode); + } + + public VideoPlayer findByRoomCode(String roomCode) { + return Optional.ofNullable(storage.get(roomCode)) + .orElseGet(() -> new VideoPlayer(roomCode, videoSynchronizer)); + } + + public VideoPlayer save(VideoPlayer videoPlayer) { + // VideoPlayer를 덮어 쓰기 전에 동작 중인 타이머가 있다면 종료해야 합니다 + deleteByRoomCode(videoPlayer.getRoomCode()); + storage.put(videoPlayer.getRoomCode(), videoPlayer); + + return videoPlayer; + } + + public void deleteByRoomCode(String roomCode) { + // VideoPlayer를 지울 때 동작 중인 타이머가 있다면 종료해야 합니다 + Optional.ofNullable(storage.remove(roomCode)) + .ifPresent(VideoPlayer::stopVideo); + } + +} diff --git a/src/main/java/site/youtogether/playlist/PlayerState.java b/src/main/java/site/youtogether/playlist/PlayerState.java deleted file mode 100644 index b8ff336..0000000 --- a/src/main/java/site/youtogether/playlist/PlayerState.java +++ /dev/null @@ -1,7 +0,0 @@ -package site.youtogether.playlist; - -public enum PlayerState { - - PLAY, PAUSE, END, RATE - -} diff --git a/src/main/java/site/youtogether/playlist/PlayingDefaultVideo.java b/src/main/java/site/youtogether/playlist/PlayingDefaultVideo.java deleted file mode 100644 index 893e3c9..0000000 --- a/src/main/java/site/youtogether/playlist/PlayingDefaultVideo.java +++ /dev/null @@ -1,43 +0,0 @@ -package site.youtogether.playlist; - -import java.util.Timer; -import java.util.TimerTask; - -import site.youtogether.exception.playlist.PlaylistEmptyException; -import site.youtogether.message.VideoSyncInfoMessage; -import site.youtogether.message.application.MessageService; -import site.youtogether.playlist.application.PlaylistService; - -public class PlayingDefaultVideo extends PlayingVideo { - - private final long totalTime; - - public PlayingDefaultVideo(String roomCode, Video video, MessageService messageService, PlaylistService playlistService) { - super(roomCode, video, messageService, playlistService); - this.totalTime = video.getDuration(); - } - - @Override - protected void createTimer(double playerRate) { - timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - if (currentTime >= totalTime) { - try { - playlistService.callNextVideoByTimer(roomCode); - } catch (PlaylistEmptyException ignored) { - } - timer.cancel(); - timer.purge(); - return; - } - messageService.sendVideoSyncInfo( - new VideoSyncInfoMessage(roomCode, videoNumber, videoId, PlayerState.PLAY, currentTime, playerRate) - ); - currentTime += 1; - } - }, 0, timerPeriod); - } - -} diff --git a/src/main/java/site/youtogether/playlist/PlayingLiveVideo.java b/src/main/java/site/youtogether/playlist/PlayingLiveVideo.java deleted file mode 100644 index 9292885..0000000 --- a/src/main/java/site/youtogether/playlist/PlayingLiveVideo.java +++ /dev/null @@ -1,30 +0,0 @@ -package site.youtogether.playlist; - -import java.util.Timer; -import java.util.TimerTask; - -import site.youtogether.message.VideoSyncInfoMessage; -import site.youtogether.message.application.MessageService; -import site.youtogether.playlist.application.PlaylistService; - -public class PlayingLiveVideo extends PlayingVideo { - - public PlayingLiveVideo(String roomCode, Video video, MessageService messageService, PlaylistService playlistService) { - super(roomCode, video, messageService, playlistService); - } - - @Override - protected void createTimer(double playerRate) { - timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - messageService.sendVideoSyncInfo( - new VideoSyncInfoMessage(roomCode, videoNumber, videoId, PlayerState.PLAY, currentTime, playerRate) - ); - currentTime += 1; - } - }, 0, timerPeriod); - } - -} diff --git a/src/main/java/site/youtogether/playlist/PlayingVideo.java b/src/main/java/site/youtogether/playlist/PlayingVideo.java deleted file mode 100644 index 237635b..0000000 --- a/src/main/java/site/youtogether/playlist/PlayingVideo.java +++ /dev/null @@ -1,92 +0,0 @@ -package site.youtogether.playlist; - -import java.util.Timer; - -import lombok.Getter; -import site.youtogether.exception.playlist.InvalidVideoRateException; -import site.youtogether.message.VideoSyncInfoMessage; -import site.youtogether.message.application.MessageService; -import site.youtogether.playlist.application.PlaylistService; - -@Getter -public abstract class PlayingVideo { - - protected PlayerState playerState; - protected final String roomCode; - protected final String videoId; - protected final Long videoNumber; - protected final String videoTitle; - protected final String channelTitle; - protected final String thumbnail; - protected final MessageService messageService; - protected final PlaylistService playlistService; - - protected double currentTime = 0.0; - protected Timer timer = new Timer(); - protected double playerRate = 1.0; - protected long timerPeriod = 1000; - - public PlayingVideo(String roomCode, Video video, MessageService messageService, PlaylistService playlistService) { - this.roomCode = roomCode; - this.videoId = video.getVideoId(); - this.videoNumber = video.getVideoNumber(); - this.videoTitle = video.getVideoTitle(); - this.channelTitle = video.getChannelTitle(); - this.thumbnail = video.getThumbnail(); - - this.messageService = messageService; - this.playlistService = playlistService; - } - - public void startAt(double time) { - timer.cancel(); - timer.purge(); - currentTime = Math.round(time * 100) / 100.0; - playerState = PlayerState.PLAY; - - createTimer(playerRate); - } - - public void pauseAt(double time) { - timer.cancel(); - timer.purge(); - currentTime = Math.round(time * 100) / 100.0; - playerState = PlayerState.PAUSE; - - messageService.sendVideoSyncInfo( - new VideoSyncInfoMessage(roomCode, videoNumber, videoId, playerState, currentTime, playerRate) - ); - } - - public void stop() { - timer.cancel(); - timer.purge(); - playerState = PlayerState.END; - - messageService.sendVideoSyncInfo( - new VideoSyncInfoMessage(roomCode, videoNumber, videoId, playerState, currentTime, playerRate) - ); - } - - public void changeRate(double time, double playerRate) { - if (playerRate < 0.25 || playerRate > 2 || (int)(playerRate * 100) % 5 != 0) { - throw new InvalidVideoRateException(); - } - timer.cancel(); - timer.purge(); - - this.playerRate = playerRate; - this.timerPeriod = Math.round(1000 / playerRate); - - if (playerState == PlayerState.PLAY) { - createTimer(playerRate); - } else if (playerState == PlayerState.PAUSE) { - messageService.sendVideoSyncInfo( - new VideoSyncInfoMessage(roomCode, videoNumber, videoId, playerState, time, playerRate) - ); - } - } - - protected abstract void createTimer(double playerRate); - -} diff --git a/src/main/java/site/youtogether/playlist/Playlist.java b/src/main/java/site/youtogether/playlist/Playlist.java index 49dd10a..78d0ae0 100644 --- a/src/main/java/site/youtogether/playlist/Playlist.java +++ b/src/main/java/site/youtogether/playlist/Playlist.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import org.springframework.data.annotation.Id; @@ -16,57 +15,69 @@ import site.youtogether.exception.playlist.PlaylistEmptyException; @Document(value = "playlist") -@NoArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PRIVATE) @Getter public class Playlist { + /** + * 재생 목록 + *

key : roomCode + *

- 재생 목록 조회 + *

- 재생 목록에 영상 추가 + *

- 재생 목록의 영상 순서 변경 + *

- 재생 목록의 영상 삭제 + */ + + private static final int FIRST = 0; + @Id private String roomCode; - private List