From f9bafd09ecc27ccbc55d6ab87a1b161f50f880d6 Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 17:19:31 +0900 Subject: [PATCH 1/7] =?UTF-8?q?chore:=20tmdb=20=ED=86=B5=EC=8B=A0=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/src/apis/apis.js | 6 ++++++ ssr/server/routes/src/constants/constant.js | 22 +++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 ssr/server/routes/src/apis/apis.js create mode 100644 ssr/server/routes/src/constants/constant.js diff --git a/ssr/server/routes/src/apis/apis.js b/ssr/server/routes/src/apis/apis.js new file mode 100644 index 0000000..28ff519 --- /dev/null +++ b/ssr/server/routes/src/apis/apis.js @@ -0,0 +1,6 @@ +import { FETCH_OPTIONS } from '../constants/constant.js'; + +export const fetchMovies = async (type) => { + const response = await fetch(type, FETCH_OPTIONS); + return await response.json(); +}; diff --git a/ssr/server/routes/src/constants/constant.js b/ssr/server/routes/src/constants/constant.js new file mode 100644 index 0000000..8b31402 --- /dev/null +++ b/ssr/server/routes/src/constants/constant.js @@ -0,0 +1,22 @@ +export const BASE_URL = 'https://api.themoviedb.org/3/movie'; + +export const TMDB_THUMBNAIL_URL = + 'https://media.themoviedb.org/t/p/w440_and_h660_face/'; +export const TMDB_ORIGINAL_URL = 'https://image.tmdb.org/t/p/original/'; +export const TMDB_BANNER_URL = + 'https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/'; +export const TMDB_MOVIE_LISTS = { + POPULAR: BASE_URL + '/popular?language=ko-KR&page=1', + NOW_PLAYING: BASE_URL + '/now_playing?language=ko-KR&page=1', + TOP_RATED: BASE_URL + '/top_rated?language=ko-KR&page=1', + UPCOMING: BASE_URL + '/upcoming?language=ko-KR&page=1', +}; +export const TMDB_MOVIE_DETAIL_URL = 'https://api.themoviedb.org/3/movie/'; + +export const FETCH_OPTIONS = { + method: 'GET', + headers: { + accept: 'application/json', + Authorization: 'Bearer ' + process.env.TMDB_TOKEN, + }, +}; From ec1a45b190fad941a6515526d604a41e05726ac7 Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 17:20:29 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=ED=83=AD=20=EB=B3=84=20=EC=98=81?= =?UTF-8?q?=ED=99=94=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EB=9E=9C=EB=8D=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/src/renderMovieItems.js | 24 ++++++++++++++ ssr/server/routes/src/renderMoviePage.js | 40 +++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 ssr/server/routes/src/renderMovieItems.js create mode 100644 ssr/server/routes/src/renderMoviePage.js diff --git a/ssr/server/routes/src/renderMovieItems.js b/ssr/server/routes/src/renderMovieItems.js new file mode 100644 index 0000000..a6b86c1 --- /dev/null +++ b/ssr/server/routes/src/renderMovieItems.js @@ -0,0 +1,24 @@ +import { round } from './utils/round.js'; + +export const renderMovieItems = (movieItems = []) => + movieItems.map( + ({ id, title, poster_path, vote_average }) => /*html*/ ` +
  • + +
    + ${title} +
    +

    ${round( + vote_average + )}

    + ${title} +
    +
    +
    +
  • + ` + ); diff --git a/ssr/server/routes/src/renderMoviePage.js b/ssr/server/routes/src/renderMoviePage.js new file mode 100644 index 0000000..555d212 --- /dev/null +++ b/ssr/server/routes/src/renderMoviePage.js @@ -0,0 +1,40 @@ +import fs from 'fs'; +import path from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +import { renderMovieItems } from './renderMovieItems.js'; +import { parseMovieItems } from './utils/parseMovieItems.js'; +import { fileURLToPath } from 'url'; +import { round } from './utils/round.js'; +import { renderTabs } from './renderTabs.js'; + +export const renderMoviePage = (moviesData, currentPath) => { + const movieItems = parseMovieItems(moviesData); + const bestMovieItem = movieItems[0]; + const moviesHTML = renderMovieItems(movieItems).join(''); + + const templatePath = path.join(__dirname, '../../../views', 'index.html'); + let template = fs.readFileSync(templatePath, 'utf-8'); + + // tabs + template = renderTabs(template, currentPath); + + // movie list + template = template.replace('', moviesHTML); + + // best movie + template = template.replace( + '${background-container}', + 'https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/' + + bestMovieItem.backdrop_path + ); + template = template.replace( + '${bestMovie.rate}', + round(bestMovieItem.vote_average) + ); + template = template.replace('${bestMovie.title}', bestMovieItem.title); + + return template; +}; From 9f67cb8c7ebc492e7fd5aeb75f329ab78f270200 Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 17:20:53 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9A=B0=ED=84=B0?= =?UTF-8?q?=EB=B3=84=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/index.js | 48 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 84d32f2..307187b 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -1,21 +1,43 @@ -import { Router } from "express"; -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +import { Router } from 'express'; +import { fetchMovies } from './src/apis/apis.js'; +import { renderMoviePage } from './src/renderMoviePage.js'; +import { TMDB_MOVIE_LISTS } from './src/constants/constant.js'; const router = Router(); -router.get("/", (_, res) => { - const templatePath = path.join(__dirname, "../../views", "index.html"); - const moviesHTML = "

    들어갈 본문 작성

    "; +router.get('/', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.NOW_PLAYING); + const moviesHTML = renderMoviePage(movies, req.path); + + res.send(moviesHTML); +}); + +router.get('/now-playing', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.NOW_PLAYING); + const moviesHTML = renderMoviePage(movies, req.path); + + res.send(moviesHTML); +}); + +router.get('/popular', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.POPULAR); + const moviesHTML = renderMoviePage(movies, req.path); + + res.send(moviesHTML); +}); + +router.get('/top-rated', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.TOP_RATED); + const moviesHTML = renderMoviePage(movies, req.path); + + res.send(moviesHTML); +}); - const template = fs.readFileSync(templatePath, "utf-8"); - const renderedHTML = template.replace("", moviesHTML); +router.get('/upcoming', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.UPCOMING); + const moviesHTML = renderMoviePage(movies, req.path); - res.send(renderedHTML); + res.send(moviesHTML); }); export default router; From 6c327fee0df5100f3bb81eabdb0dfbc5a8402cf3 Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 17:21:15 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=ED=83=AD=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=B4=EC=84=9C=20=EB=9E=9C=EB=8D=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/src/renderTabs.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 ssr/server/routes/src/renderTabs.js diff --git a/ssr/server/routes/src/renderTabs.js b/ssr/server/routes/src/renderTabs.js new file mode 100644 index 0000000..e47b014 --- /dev/null +++ b/ssr/server/routes/src/renderTabs.js @@ -0,0 +1,11 @@ +export const renderTabs = (template, currentPath) => { + template = template.replace( + new RegExp( + `]*>`, + 'g' + ), + `
    ` + ); + + return template; +}; From c6a2094943a636a09aca8bcd12c046d77a4c8522 Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 17:21:25 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20round=20=EC=9C=A0=ED=8B=B8=ED=95=A8?= =?UTF-8?q?=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/src/utils/parseMovieItems.js | 3 +++ ssr/server/routes/src/utils/round.js | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 ssr/server/routes/src/utils/parseMovieItems.js create mode 100644 ssr/server/routes/src/utils/round.js diff --git a/ssr/server/routes/src/utils/parseMovieItems.js b/ssr/server/routes/src/utils/parseMovieItems.js new file mode 100644 index 0000000..1393eab --- /dev/null +++ b/ssr/server/routes/src/utils/parseMovieItems.js @@ -0,0 +1,3 @@ +export const parseMovieItems = (moviesData) => { + return moviesData.results; +}; diff --git a/ssr/server/routes/src/utils/round.js b/ssr/server/routes/src/utils/round.js new file mode 100644 index 0000000..d7e232c --- /dev/null +++ b/ssr/server/routes/src/utils/round.js @@ -0,0 +1,4 @@ +export const round = (value) => { + const factor = 10; + return Math.round(value * factor) / factor; +}; From 6ab6c6ace7b3d02ee78888caae67c923db1291ad Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 18:02:56 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=EC=98=81=ED=99=94=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=AA=A8=EB=8B=AC=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/index.js | 11 ++++- ssr/server/routes/src/apis/apis.js | 11 ++++- ssr/server/routes/src/renderMovieModal.js | 49 +++++++++++++++++++ .../routes/src/utils/parseMovieDetail.js | 13 +++++ 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 ssr/server/routes/src/renderMovieModal.js create mode 100644 ssr/server/routes/src/utils/parseMovieDetail.js diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 307187b..696ed38 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -1,7 +1,8 @@ import { Router } from 'express'; -import { fetchMovies } from './src/apis/apis.js'; +import { fetchMovieDetail, fetchMovies } from './src/apis/apis.js'; import { renderMoviePage } from './src/renderMoviePage.js'; import { TMDB_MOVIE_LISTS } from './src/constants/constant.js'; +import { renderMovieModal } from './src/renderMovieModal.js'; const router = Router(); @@ -40,4 +41,12 @@ router.get('/upcoming', async (req, res) => { res.send(moviesHTML); }); +router.get('/detail/:movieId', async (req, res) => { + const movies = await fetchMovies(TMDB_MOVIE_LISTS.NOW_PLAYING); + const movieDetail = await fetchMovieDetail(req.params.movieId); + const moviesHTML = renderMovieModal(movies, movieDetail); + + res.send(moviesHTML); +}); + export default router; diff --git a/ssr/server/routes/src/apis/apis.js b/ssr/server/routes/src/apis/apis.js index 28ff519..c68a81c 100644 --- a/ssr/server/routes/src/apis/apis.js +++ b/ssr/server/routes/src/apis/apis.js @@ -1,6 +1,15 @@ -import { FETCH_OPTIONS } from '../constants/constant.js'; +import { FETCH_OPTIONS, TMDB_MOVIE_DETAIL_URL } from '../constants/constant.js'; export const fetchMovies = async (type) => { const response = await fetch(type, FETCH_OPTIONS); return await response.json(); }; + +export const fetchMovieDetail = async (id) => { + const url = TMDB_MOVIE_DETAIL_URL + id; + const params = new URLSearchParams({ + language: 'ko-KR', + }); + const response = await fetch(url + '?' + params, FETCH_OPTIONS); + return await response.json(); +}; diff --git a/ssr/server/routes/src/renderMovieModal.js b/ssr/server/routes/src/renderMovieModal.js new file mode 100644 index 0000000..d199336 --- /dev/null +++ b/ssr/server/routes/src/renderMovieModal.js @@ -0,0 +1,49 @@ +import { renderMoviePage } from './renderMoviePage.js'; +import { parseMovieDetail } from './utils/parseMovieDetail.js'; +import { round } from './utils/round.js'; + +export const renderMovieModal = (moviesData, movieDetailItem) => { + const movieDetail = parseMovieDetail(movieDetailItem); + + const moviesPageTemplate = renderMoviePage(moviesData); + return moviesPageTemplate.replace( + '', + /*html*/ ` + + + + ` + ); +}; diff --git a/ssr/server/routes/src/utils/parseMovieDetail.js b/ssr/server/routes/src/utils/parseMovieDetail.js new file mode 100644 index 0000000..c094de5 --- /dev/null +++ b/ssr/server/routes/src/utils/parseMovieDetail.js @@ -0,0 +1,13 @@ +import { TMDB_ORIGINAL_URL } from '../constants/constant.js'; +import { round } from './round.js'; + +export const parseMovieDetail = (movieDetail) => { + return { + title: movieDetail.title, + bannerUrl: TMDB_ORIGINAL_URL + movieDetail.poster_path, + releaseYear: movieDetail.release_date.split('-')[0], + description: movieDetail.overview, + genres: movieDetail.genres.map(({ name }) => name), + rate: round(movieDetail.vote_average), + }; +}; From 26b4449f3e848327fc94b731cc0d71d3cbfc266e Mon Sep 17 00:00:00 2001 From: Hyelim Choi Date: Thu, 3 Oct 2024 18:11:51 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=EC=83=81=EC=98=81=20=EC=A4=91=20?= =?UTF-8?q?=EB=A7=8C=20=EC=84=A0=ED=83=9D=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=95=88=EB=A8=B9=ED=9E=88=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/index.js | 2 +- ssr/views/index.html | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 696ed38..0846a85 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -8,7 +8,7 @@ const router = Router(); router.get('/', async (req, res) => { const movies = await fetchMovies(TMDB_MOVIE_LISTS.NOW_PLAYING); - const moviesHTML = renderMoviePage(movies, req.path); + const moviesHTML = renderMoviePage(movies, '/now-playing'); res.send(moviesHTML); }); diff --git a/ssr/views/index.html b/ssr/views/index.html index a052396..56c9192 100644 --- a/ssr/views/index.html +++ b/ssr/views/index.html @@ -14,10 +14,15 @@