From b9782acd7ffa18677e1bf10e07e5ec25121c940f Mon Sep 17 00:00:00 2001 From: pakxe Date: Thu, 3 Oct 2024 21:39:17 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20html=EC=82=BD=EC=9E=85=EC=9D=B4=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B3=B3=EC=97=90=20=ED=94=8C?= =?UTF-8?q?=EB=9E=98=EA=B7=B8=20=EA=BD=82=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/views/index.html | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/ssr/views/index.html b/ssr/views/index.html index a052396..d4dd4b7 100644 --- a/ssr/views/index.html +++ b/ssr/views/index.html @@ -31,34 +31,7 @@

MovieList

From 5d43ea250e215035ea6bf93b2166c41484b39124 Mon Sep 17 00:00:00 2001 From: pakxe Date: Thu, 3 Oct 2024 21:39:31 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20ssr=EC=97=90=EC=84=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=A0=20=EC=83=81=EC=88=98=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/constant.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 ssr/server/constant.js diff --git a/ssr/server/constant.js b/ssr/server/constant.js new file mode 100644 index 0000000..36f374f --- /dev/null +++ b/ssr/server/constant.js @@ -0,0 +1,26 @@ +export const PATH_LIST = { + POPULAR: '/popular', + UPCOMING: '/upcoming', + TOP_RATED: '/top_rated', + NOW_PLAYING: '/now_playing', +}; + +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 + PATH_LIST.POPULAR + '?language=ko-KR&page=1', + NOW_PLAYING: BASE_URL + PATH_LIST.NOW_PLAYING + '?language=ko-KR&page=1', + TOP_RATED: BASE_URL + PATH_LIST.TOP_RATED + '?language=ko-KR&page=1', + UPCOMING: BASE_URL + PATH_LIST.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 f1de258d7c31632d0583d41c923dd4601eb6ec37 Mon Sep 17 00:00:00 2001 From: pakxe Date: Thu, 3 Oct 2024 21:40:56 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20response=EA=B0=92=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8A=94=20=ED=8C=8C=EC=8B=B1=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/parse.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 ssr/server/parse.js diff --git a/ssr/server/parse.js b/ssr/server/parse.js new file mode 100644 index 0000000..e72cdd5 --- /dev/null +++ b/ssr/server/parse.js @@ -0,0 +1,26 @@ +import { round } from '../../csr/src/utils.js'; +import { TMDB_ORIGINAL_URL } from './constant.js'; + +export const parseMovieItem = (movieItemData) => { + return { + id: movieItemData.id, + title: movieItemData.title, + rate: movieItemData.vote_average, + background: movieItemData.backdrop_path, + }; +}; + +export const parseMovieList = (movieList) => { + return movieList.results.map((item) => parseMovieItem(item)); +}; + +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, 1), + }; +}; From 1d2056831fe7e5b27146b203de66d3f8cebb36ff Mon Sep 17 00:00:00 2001 From: pakxe Date: Thu, 3 Oct 2024 21:41:08 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20path=EB=A1=9C=20=EB=B0=94=EA=BE=B8?= =?UTF-8?q?=EB=8A=94=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/utils.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ssr/server/utils.js diff --git a/ssr/server/utils.js b/ssr/server/utils.js new file mode 100644 index 0000000..0b74b8f --- /dev/null +++ b/ssr/server/utils.js @@ -0,0 +1,3 @@ +export const convertToPath = (key) => { + return '/' + key.toLowerCase(); +}; From 90095b900b2542d7a31f996ad7a23f8713a392c1 Mon Sep 17 00:00:00 2001 From: pakxe Date: Thu, 3 Oct 2024 21:41:19 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=EC=82=AC=EC=A0=84=20=EB=AF=B8?= =?UTF-8?q?=EC=85=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ssr/server/routes/index.js | 197 +++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 10 deletions(-) diff --git a/ssr/server/routes/index.js b/ssr/server/routes/index.js index 84d32f2..eef91a9 100644 --- a/ssr/server/routes/index.js +++ b/ssr/server/routes/index.js @@ -1,21 +1,198 @@ -import { Router } from "express"; -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; +import { Router } from 'express'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { + FETCH_OPTIONS, + PATH_LIST, + TMDB_BANNER_URL, + TMDB_MOVIE_DETAIL_URL, + TMDB_MOVIE_LISTS, + TMDB_THUMBNAIL_URL, +} from '../constant.js'; +import { parseMovieDetail, parseMovieList } from '../parse.js'; +import { convertToPath } from '../utils.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const router = Router(); -router.get("/", (_, res) => { - const templatePath = path.join(__dirname, "../../views", "index.html"); - const moviesHTML = "

들어갈 본문 작성

"; +const fetchMovies = async (type) => { + const response = await fetch(TMDB_MOVIE_LISTS[type], FETCH_OPTIONS); + const data = await response.json(); - const template = fs.readFileSync(templatePath, "utf-8"); - const renderedHTML = template.replace("", moviesHTML); + return parseMovieList(data); +}; - res.send(renderedHTML); +const renderMovieList = (movieList = []) => { + return movieList.map( + ({ id, title, background, rate }) => /*html*/ ` +
  • + +
    + ${title} +
    +

    + + ${rate}

    + ${title} +
    +
    +
    +
  • + `, + ); +}; + +const getFile = (filePath, fileName) => { + const compositedFilePate = path.join(__dirname, filePath, fileName); + return fs.readFileSync(compositedFilePate, 'utf-8'); +}; + +const renderTabList = (type) => { + const curPath = convertToPath(type); + const tabList = [ + { path: PATH_LIST.NOW_PLAYING, name: '상영중' }, + { path: PATH_LIST.POPULAR, name: '인기순' }, + { path: PATH_LIST.TOP_RATED, name: '평점순' }, + { path: PATH_LIST.UPCOMING, name: '상영 예정' }, + ]; + + return tabList.map( + ({ path, name }) => /*html*/ ` +
  • + +
    +

    ${name}

    +
    +
    +
  • + `, + ); +}; + +const renderMovieListPage = async (type) => { + const movieList = await fetchMovies(type); + const topRatedMovie = movieList[0]; + + let HTMLTemplate = getFile('../../views', 'index.html'); + + const movieListHTML = renderMovieList(movieList).join(''); + const tabListHTML = renderTabList(type).join(''); + + HTMLTemplate = HTMLTemplate.replace('', movieListHTML); + HTMLTemplate = HTMLTemplate.replace('', tabListHTML); + HTMLTemplate = HTMLTemplate.replace('${background-container}', TMDB_BANNER_URL + topRatedMovie.background); + HTMLTemplate = HTMLTemplate.replace('${bestMovie.rate}', topRatedMovie.rate); + HTMLTemplate = HTMLTemplate.replace('${bestMovie.title}', topRatedMovie.title); + + return HTMLTemplate; +}; + +const fetchMovieDetail = async (movieId) => { + const response = await fetch(TMDB_MOVIE_DETAIL_URL + movieId, FETCH_OPTIONS); + const data = await response.json(); + + return parseMovieDetail(data); +}; + +const renderMovieDetailModalHTML = ({ bannerUrl, title, releaseYear, description, genres, rate }) => { + return /*html*/ ` + +`; +}; +const renderMovieDetailModal = async (movieId) => { + const movieDetail = await fetchMovieDetail(movieId); + + let template = await renderMovieListPage('NOW_PLAYING'); + template = template.replace('', renderMovieDetailModalHTML(movieDetail)); + + return template; +}; + +router.get('/', async (_, res) => { + try { + res.send(await renderMovieListPage('NOW_PLAYING')); + } catch (error) { + console.error('Error fetching movies:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.get(PATH_LIST.NOW_PLAYING, async (_, res) => { + try { + res.send(await renderMovieListPage('NOW_PLAYING')); + } catch (error) { + console.error('Error fetching movies:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.get(PATH_LIST.TOP_RATED, async (_, res) => { + try { + res.send(await renderMovieListPage('TOP_RATED')); + } catch (error) { + console.error('Error fetching movies for TOP_RATED:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.get(PATH_LIST.UPCOMING, async (_, res) => { + try { + res.send(await renderMovieListPage('UPCOMING')); + } catch (error) { + console.error('Error fetching movies for UPCOMING:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.get(PATH_LIST.POPULAR, async (_, res) => { + try { + res.send(await renderMovieListPage('POPULAR')); + } catch (error) { + console.error('Error fetching movies for POPULAR:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.get('/detail/:id', async (req, res) => { + const { id } = req.params; // URL 파라미터에서 id 추출 + + try { + console.log(`Fetching details for movie with ID: ${id}`); + // 예: 특정 영화의 상세 정보를 가져오는 함수를 호출할 수 있습니다. + res.send(await renderMovieDetailModal(id)); // ID를 전달하는 경우 + } catch (error) { + console.error('Error fetching movies for DETAIL:', error); + res.status(500).send('Internal Server Error'); + } }); export default router;