Skip to content

Commit

Permalink
Merge pull request #13 from Likelion-YeungNam-Univ/feat/#8-home-playlist
Browse files Browse the repository at this point in the history
Feat/#8 home playlist
  • Loading branch information
jjjjjinseo authored Jul 24, 2024
2 parents fcf9fc0 + e7814fa commit e6c5d62
Show file tree
Hide file tree
Showing 27 changed files with 978 additions and 24 deletions.
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand All @@ -39,6 +39,12 @@ dependencies {

//s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//youtube api
implementation 'com.google.api-client:google-api-client:1.33.0'
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
implementation 'com.google.apis:google-api-services-youtube:v3-rev20230816-2.0.0'
implementation 'com.google.http-client:google-http-client-jackson2:1.39.2'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class BeginnerFitBeApplication {

public static void main(String[] args) {
SpringApplication.run(BeginnerFitBeApplication.class, args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.example.beginnerfitbe.category.domain.Category;
import com.example.beginnerfitbe.category.repository.CategoryRepository;
import com.example.beginnerfitbe.post.domain.Post;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ public class SecurityConfig {
"/auth/sign-in",
"/auth/sign-up",
"/users/emailcheck",
"/video",
"/playlist",
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.example.beginnerfitbe.playlist.controller;

import com.example.beginnerfitbe.jwt.util.JwtUtil;
import com.example.beginnerfitbe.playlist.service.PlaylistService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/playlists")
@RequiredArgsConstructor
public class PlaylistController {

private final JwtUtil jwtUtil;
private final PlaylistService playlistService;

@GetMapping("")
@Operation(summary = "플레이리스트 전체 조회 메소드", description = "전체 플레이리스트를 조회합니다.")
public ResponseEntity<?> list(){
return ResponseEntity.ok(playlistService.list());
}

@GetMapping("/{playlistId}")
@Operation(summary = "플레이리스트 상세 조회 메소드", description = "플레이리스트 상세 정보를 조회합니다.")
public ResponseEntity<?> read(@PathVariable Long playlistId){
return ResponseEntity.ok(playlistService.read(playlistId));
}

@GetMapping("/me")
@Operation(summary = "사용자의 플레이리스트 목록을 조회합니다.", description = "사용자의 플레이리스트 목록을 조회합니다.")
public ResponseEntity<?> me(HttpServletRequest request){
Long userId = jwtUtil.getUserId(jwtUtil.resolveToken(request).substring(7));
return ResponseEntity.ok(playlistService.me(userId));
}

@GetMapping("/recent")
@Operation(summary = "홈화면에 뜰 플레이리스트를 조회합니다.", description = "가장 최신 플레이리스트를 조회합니다.")
public ResponseEntity<?> getRecentPlaylist(HttpServletRequest request){
Long userId = jwtUtil.getUserId(jwtUtil.resolveToken(request).substring(7));
return ResponseEntity.ok(playlistService.getRecentPlaylist(userId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.example.beginnerfitbe.playlist.domain;

import com.example.beginnerfitbe.user.domain.User;
import com.example.beginnerfitbe.youtube.domain.YoutubeVideo;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;
import java.util.List;

@Entity
@NoArgsConstructor
@Getter
public class Playlist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String title;

@Column(nullable = false)
private String totalTime;

@Column(nullable = false)
private Boolean isCompleted;

@CreatedDate
@Column(nullable = false)
private LocalDateTime createdAt;

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;

@OneToMany(mappedBy = "playlist", fetch = FetchType.LAZY)
private List<YoutubeVideo> videos;

@Builder
public Playlist(String title, String totalTime, Boolean isCompleted, LocalDateTime createdAt, User user, List<YoutubeVideo> videos) {
this.title = title;
this.totalTime = totalTime;
this.isCompleted = isCompleted;
this.createdAt = createdAt;
this.user = user;
this.videos = videos;
}

public void setCompleted(boolean isCompleted) {
this.isCompleted = isCompleted;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.beginnerfitbe.playlist.dto;

import com.example.beginnerfitbe.user.domain.User;
import com.example.beginnerfitbe.youtube.domain.YoutubeVideo;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

@Data
@NoArgsConstructor
public class PlaylistCreateDto {
private String title;
private String description;
private int totalTime;
private Boolean isWatched;
private LocalDateTime createdAt;
private User user;
private List<YoutubeVideo> youtubeVideos;

@Builder
public PlaylistCreateDto(String title, String description, int totalTime, Boolean isWatched, LocalDateTime createdAt, User user, List<YoutubeVideo> youtubeVideos) {
this.title = title;
this.description = description;
this.totalTime = totalTime;
this.isWatched = isWatched;
this.createdAt = createdAt;
this.user = user;
this.youtubeVideos = youtubeVideos;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.beginnerfitbe.playlist.dto;

import com.example.beginnerfitbe.playlist.domain.Playlist;
import com.example.beginnerfitbe.youtube.dto.YoutubeVideoDto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Getter
@NoArgsConstructor
public class PlaylistDto {
private Long id;
private String title;
private String totalTime;
private Boolean isCompleted;
private LocalDateTime createdAt;
private Long userId;
private List<YoutubeVideoDto> videos;

@Builder
public PlaylistDto(Long id, String title, String totalTime, Boolean isCompleted, LocalDateTime createdAt, Long userId, List<YoutubeVideoDto> videos) {
this.id = id;
this.title = title;
this.totalTime = totalTime;
this.isCompleted = isCompleted;
this.createdAt = createdAt;
this.userId = userId;
this.videos = videos;
}

public static PlaylistDto fromEntity(Playlist playlist) {
return PlaylistDto.builder()
.id(playlist.getId())
.title(playlist.getTitle())
.totalTime(playlist.getTotalTime())
.isCompleted(playlist.getIsCompleted())
.createdAt(playlist.getCreatedAt())
.userId(playlist.getUser().getId())
.videos(playlist.getVideos().stream()
.map(YoutubeVideoDto::fromEntity)
.collect(Collectors.toList()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.beginnerfitbe.playlist.repository;

import com.example.beginnerfitbe.playlist.domain.Playlist;
import com.example.beginnerfitbe.user.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
List<Playlist> findByUserOrderByCreatedAtDesc(User user);
Optional<Playlist> findFirstByUserOrderByCreatedAtDesc(User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.example.beginnerfitbe.playlist.service;

import com.example.beginnerfitbe.playlist.domain.Playlist;
import com.example.beginnerfitbe.playlist.dto.PlaylistDto;
import com.example.beginnerfitbe.playlist.repository.PlaylistRepository;
import com.example.beginnerfitbe.youtube.dto.SelectedVideoDto;
import com.example.beginnerfitbe.user.domain.User;
import com.example.beginnerfitbe.user.repository.UserRepository;
import com.example.beginnerfitbe.youtube.dto.YoutubeVideoDto;
import com.example.beginnerfitbe.youtube.service.YoutubeVideoService;
import com.example.beginnerfitbe.youtube.util.YoutubeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class PlaylistService {

private static final Logger logger = LoggerFactory.getLogger(PlaylistService.class);

private final PlaylistRepository playlistRepository;
private final UserRepository userRepository;
private final YoutubeVideoService youtubeVideoService;
private final YoutubeUtil youtubeUtil;

public PlaylistDto create(User user) throws IOException {
String query = searchKeyword(user);
String requestTime = String.valueOf(user.getExerciseTime());
SelectedVideoDto selectVideoDto = youtubeUtil.selectVideos(query, requestTime);

Playlist playlist = Playlist.builder()
.title(query + " 집중 공략하기 플리")
.createdAt(LocalDateTime.now())
.isCompleted(false)
.totalTime(selectVideoDto.getTotalTime())
.user(user)
.videos(selectVideoDto.getYoutubeVideos())
.build();

playlist = playlistRepository.save(playlist);

youtubeVideoService.create(selectVideoDto, playlist);
return PlaylistDto.fromEntity(playlist);
}


// 매일 자정에 실행
@Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul")
public void createPlaylistDaily() {
userRepository.findAll().forEach(user -> {
try {
create(user);
} catch (IOException e) {
logger.error("플레이리스트 생성 중 오류 발생", e);
}
});
}

private String searchKeyword(User user) {

String query= null;
if(user.getExerciseIntensity()<=3){
query = user.getExercisePart() + " " + user.getExercisePurpose() +" 쉬운 운동";
}
else if(user.getExerciseIntensity()>=7){
query = user.getExercisePart() + " " + user.getExercisePurpose() +" 매운맛 운동";
}
else{
query = user.getExercisePart() + " " + user.getExercisePurpose()+" 운동";
}
return query;
}

@Transactional
public void update(Long playlistId) {
List<YoutubeVideoDto> samePlaylistVideos = youtubeVideoService.getYoutubeVideosByPlaylist(playlistId); // 비디오 상태 확인

boolean allWatched = samePlaylistVideos.stream().allMatch(YoutubeVideoDto::getIsWatched);

if (allWatched) {
Playlist playlist = playlistRepository.findById(playlistId)
.orElseThrow(() -> new IllegalArgumentException("Playlist not found"));
playlist.setCompleted(true);
playlistRepository.save(playlist);
}
}
//재생목록 조회
public List<PlaylistDto> list(){
return playlistRepository.findAll().stream()
.map(PlaylistDto::fromEntity)
.collect(Collectors.toList());
}

public PlaylistDto read(Long playlistId){
Playlist playlist = playlistRepository.findById(playlistId).orElseThrow(() -> new IllegalArgumentException("Playlist not found"));
return PlaylistDto.fromEntity(playlist);
}

//사용자 플레이리스트 목록
public List<PlaylistDto> me(Long userId) {
User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("User not found"));
return playlistRepository.findByUserOrderByCreatedAtDesc(user).stream()
.map(PlaylistDto::fromEntity)
.collect(Collectors.toList());
}

//가장 최신 플레이리스트 (홈화면에 뜰 플레이리스트 )
public PlaylistDto getRecentPlaylist(Long userId) {
User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("User not found"));
Playlist playlist = playlistRepository.findFirstByUserOrderByCreatedAtDesc(user).orElseThrow(() -> new IllegalArgumentException("Playlist not found"));
return PlaylistDto.fromEntity(playlist);
}

}
Loading

0 comments on commit e6c5d62

Please sign in to comment.