diff --git a/README.md b/README.md index 8388f4e..91c8bc0 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,241 @@ `#node.js` `#master-in-software-engineering` +# node-moviedb-cli - - -[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) - - - -# Assembler School: Node.js MovieDB CLI App +## Table of Contents -In this project you will learn how to create a cli app with Node.js. +- [node-moviedb-cli](#node-moviedb-cli) + - [Description](#description) + - [Getting Started](#getting-started) + - [1. Clone repository](#1-clone-repository) + - [2. npm install](#2-npm-install) + - [3. Create API_KEY](#3-create-api_key) + - [4. Create .env file with API_KEY](#4-create-env-file-with-api_key) + - [The Project](#the-project) + - [Requirements](#requirements) + - [Deliverables](#deliverables) + - [Technologies used](#technologies-used) + - [Resources](#resources) + - [License](#license) + - [Authors](#authors) -## Table of Contents +
-- [Getting Started](#getting-started) -- [The Project](#the-project) -- [Project requirements](#project-requirements) -- [Project delivery](#project-delivery) -- [Resources](#resources) +## Description +- In this project we developed a CLI program with node.js. +- You will be able to run the program using a terminal application. +- The program is connected to a third-party API(the movie db). +- We connected the program to a third-party API(https://www.themoviedb.org) to show the data using node.js. -## Getting Started -These instructions will get you a copy of the project up and running on your -local machine for development and testing purposes. +
-See deployment for notes on how to deploy the project on a live system. +## Getting Started -### The repository +### 1. Clone repository First, you will need to `clone` or `fork` the repository into your Github account: -Fork on GitHub ``` -$ git clone https://github.com/assembler-school/node-moviedb-cli.git +$ git clone https://github.com/labietelabiete/node-moviedb-cli.git ``` -## Contents and Branches Naming Strategy - -The repository is made up of several branches that include the contents of each -section. +### 2. npm install +Then, you will need to install the dependencies with: `npm install`. -The branches follow a naming strategy like the following: - -- `main`: includes the main contents and the instructions -- `assembler-solution`: includes the solution - -### Fetching All the Branches - -In order to fetch all the remote branches in the repository, you can use the -following command: +Run the following command in your terminal after cloning the main repo: ```sh -$ git fetch --all +$ npm install ``` -### List Both Remote Tracking Branches and Local Branches +### 3. Create API_KEY +- Go to The Movie Database (TMDb) :point_right: https://www.themoviedb.org/signup +- Sign up and Sign in +- Get your API KEY -```sh -$ git branch --all +### 4. Create .env file with API_KEY +Include this line below in .env file ``` - -Then, you can create a local branch based on a remote branch with the following -command: - -```sh -$ git checkout -b +API_KEY = YOUR API KEY HERE ``` -### Installing +

-First, you will need to install the dependencies with: `npm install`. +## The Project -Run the following command in your terminal after cloning the main repo: +In this project we built a CLI App similar to the following screenshot. -```sh -$ npm install -``` + -### Running the Tests +### 1. Popular Persons + ---------------- + 1.1 URL: https://api.themoviedb.org/3/person/popular?page=1 + - Required fields: + - description: "Make a network request to fetch the most popular persons" + - options: + - --popular (-p) REQUIRED ("Fetch the popular persons") + - --page (none) (input type: number) REQUIRED ("The page of persons data results to fetch") + + 1.2 Start terminal spinner using ora (https://github.com/sindresorhus/ora) that renders the following message until the request has finished: "Fetching the popular person's data..." -The tests that validate your solution can be executed by runing the following -command: + 1.3 Create https request file (https://nodejs.org/api/https.html#https_https_request_options_callback) -``` -$ npm run test -``` + 1.4 ERROR HANDLER -> ora.fail() -### Git `precommit` and `prepush` Hooks + 1.5 RENDERING RESULT -> chalk (https://github.com/chalk/chalk) + - Use chalk.white() method to render pagination + - Use chalk for rendering persons data + - If person appears in movies: + - Use chalk for rendering movies + + 1.6 Ending the terminal spinner using ora.succeed() -In the `assembler-solution` branch you can see an implementation of these tools -if you'd like to use them. + *Example* : + ``` + node src/moviedb.js get-persons -p --page 100 + ``` -## Deployment +
-In this pill we won't deploy the app. +### 2. Single Person Details +------------------ + 2.1 URL: https://api.themoviedb.org/3/person/:id + - Required fields: + - description: "Make a network request to fetch the data of a single person" + - options: + - --id (-i) REQUIRED ("The id of the person") + + 2.2 Start terminal spinner using ora (https://github.com/sindresorhus/ora) -## Technologies used + 2.3 Create https request file (https://nodejs.org/api/https.html#https_https_request_options_callback) -- `Node.js` -- `eslint` -- `prettier` -- `lint-staged` -- `husky` + 2.4 ERROR HANDLER -> ora.fail() -## The Project + 2.5 Rendering using chalk https://github.com/chalk/chalk -In this project you will build a cli app similar to the following screenshot. + 2.6 Ending the terminal spinner using ora.succeed() - -## Project requirements +*Example* : +``` +node src/moviedb.js get-person --id 1245 +``` +
+ +### 3. Movies +------------------- + 3.1 URL: https://api.themoviedb.org/3/movie/popular?page=1 + - Required fields: + - description: "Make a network request to fetch movies" + - options: + - --page (none) (input type: number) REQUIRED ("The page of movies data results to fetch") + - --popular (-p) ("Fetch the popular movies") + - --now-playing (-n) ("Fetch the moviews that are playing now") + + + 3.2 Start terminal spinner using ora (https://github.com/sindresorhus/ora) + + 3.3 Create https request file (https://nodejs.org/api/https.html#https_https_request_options_callback) + + 3.4 ERROR HANDLER -> ora.fail() + + 3.5 Rendering using chalk https://github.com/chalk/chalk + + 3.6 Ending the terminal spinner using ora.succeed() + - if the request was made to the popular movies endpoint: + - "Popular movies data loaded" + - if the request was made to the popular movies endpoint: + - "Movies playing now data loaded" + +*Example* : + - popular movies + ``` + node src/moviedb.js get-movies --page 6 + ``` + - now playing movies + ``` + node src/moviedb.js get-movies -n --page 1 + ``` +
+ +### 4. Single Movie Details +----------------------- +4.1 URL: https://api.themoviedb.org/3/movie/:movieId +- Required fields: + - description: "Make a network request to fetch the data of a single movie" + - options: + - --id (-i) REQUIRED ("The id of the movie") + - reviews (-r) ("Fetch the reviews of the movie") + +4.2 Start terminal spinner using ora (https://github.com/sindresorhus/ora) + +4.3 Create https request file (https://nodejs.org/api/https.html#https_https_request_options_callback) + +4.4 ERROR HANDLER -> ora.fail() + +4.5 Rendering using chalk https://github.com/chalk/chalk + +4.6 Ending the terminal spinner using ora.succeed() + +*Example* : + + ``` +node src/moviedb.js get-movie --id 385128 +``` +or +``` +node src/moviedb.js get-movie -i 385128 --review + ``` +

-This is an overview of the main requirements of this project. The exact ones are -found in the doc that the academic team will provide you. +## Requirements -- You must follow all the instructions of the project step-by-step -- You should always try to solve them by yourself before asking for help -- You should always help your team members and fellow students of the master so - that you can all learn together and become better software developers and team - members -- You must finish all the steps that are marked as `Required` -- Once you are done, you can move on to the optional ones that are marked as - `Extra 💯` + - GIT + - Directory structure + - English comments + - camelCase + - Subtasks + - Delete files not used +

+## Deliverables -## Project delivery + - Repository + - Postman collection + - README +

-To deliver this project you must follow the steps indicated in the document: +## Technologies used -- [Submitting a solution](https://www.notion.so/Submitting-a-solution-524dab1a71dd4b96903f26385e24cdb6) +- `Node.js` +- `eslint` +- `prettier` +- `lint-staged` +- `husky` +

## Resources -- See the document we provide +- Oficial web page: https://nodejs.org/en/docs/
+- W3schools: https://www.w3schools.com/nodejs/
+- NodeJS Tutorial: https://www.tutorialsteacher.com/nodejs/nodejs-tutorials
+- chalk: https://www.npmjs.com/package/chalk
+- commander: https://www.npmjs.com/package/commander
+- dotenv: https://www.npmjs.com/package/dotenv
+- node-notifier: https://www.npmjs.com/package/node-notifier
+- ora: https://www.npmjs.com/package/ora/v/0.3.0
+
-## License +## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details -## Contributors ✨ - -Thanks goes to these wonderful people -([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - -

Dani Lucaci

💻 📖 💡 🔧
- - - +
- +## Authors -This project follows the -[all-contributors](https://github.com/all-contributors/all-contributors) -specification. Contributions of any kind welcome! +Hugo Gomez [@labietelabiete](https://github.com/labietelabiete)
+Jon García-Orad [@jonCroatanUto](https://github.com/jonCroatanUto)
+Eunyoung Kim [@solaz0824](https://github.com/solaz0824) diff --git a/package-lock.json b/package-lock.json index fcf3619..7f47730 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,350 @@ { "name": "node-moviedb-cli", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "commander": "^6.1.0", + "dotenv": "^8.2.0", + "node-notifier": "^8.0.0", + "ora": "^5.1.0" + }, + "bin": { + "moviedb": "src/moviedb.js" + } + }, + "node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz", + "integrity": "sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" + }, + "node_modules/is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/node-notifier": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", + "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + } + }, + "node_modules/ora": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz", + "integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==", + "dependencies": { + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.4.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/cli-spinners": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz", + "integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ora/node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/ora/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ora/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/ora/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" + }, + "node_modules/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + } + }, "dependencies": { "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -116,34 +453,11 @@ "wcwidth": "^1.0.1" }, "dependencies": { - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -162,19 +476,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -183,11 +484,6 @@ "clone": "^1.0.2" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -241,14 +537,6 @@ "ansi-regex": "^5.0.0" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/package.json b/package.json index f20c9c6..5847565 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,13 @@ }, "scripts": {}, "dependencies": { - "chalk": "^4.1.0", + "chalk": "^4.1.1", "commander": "^6.1.0", "dotenv": "^8.2.0", "node-notifier": "^8.0.0", "ora": "^5.1.0" + }, + "bin": { + "moviedb": "./src/moviedb.js" } } diff --git a/src/doc/Movie DB.postman_collection.json b/src/doc/Movie DB.postman_collection.json new file mode 100644 index 0000000..e77d22c --- /dev/null +++ b/src/doc/Movie DB.postman_collection.json @@ -0,0 +1,94 @@ +{ + "info": { + "_postman_id": "95671b9e-eb74-474e-98a5-a18e32c65457", + "name": "Movie DB", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Popular persons", + "request": { + "method": "GET", + "header": [], + "url": null + }, + "response": [] + }, + { + "name": "Person details", + "request": { + "method": "GET", + "header": [], + "url": null + }, + "response": [] + }, + { + "name": "Movies", + "request": { + "method": "GET", + "header": [], + "url": null + }, + "response": [] + }, + { + "name": "Movie", + "request": { + "method": "GET", + "header": [], + "url": null + }, + "response": [] + }, + { + "name": "Movie Reviews", + "request": { + "method": "GET", + "header": [], + "url": null + }, + "response": [] + } + ], + "auth": { + "type": "apikey", + "apikey": [ + { + "key": "key", + "value": "api_key", + "type": "string" + }, + { + "key": "value", + "value": "fd994b7d6abb03ae970228dfbc606f88", + "type": "string" + }, + { + "key": "in", + "value": "query", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/src/moviedb.js b/src/moviedb.js index dd5591a..a747d1a 100755 --- a/src/moviedb.js +++ b/src/moviedb.js @@ -1,36 +1,151 @@ #!/usr/bin/env node const { Command } = require("commander"); +const ora = require("ora"); +const dotenv = require("dotenv"); +dotenv.config(); + +const { + getPersons, + getPerson, + getMovies, + getMovie, +} = require("./utils/httpsRequest"); +const { + renderPersons, + renderPerson, + renderMovies, + renderMovie, +} = require("./utils/renderRequest"); + +const requestOptions = { + href: "https://api.themoviedb.org", + protocol: "https:", + hostname: "api.themoviedb.org", + path: ``, + port: 443, + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${process.env.API_KEY}`, + }, +}; const program = new Command(); program.version("0.0.1"); +/* +************ test it with ************** + +node src/moviedb.js get-persons -p --page 100 + +*/ + program .command("get-persons") .description("Make a network request to fetch most popular persons") - .action(function handleAction() { + .requiredOption("-p, --popular", "Fetch the popular persons") + .requiredOption( + "--page, ", + "The page of persons data results to fetch" + ) + .action(async function handleAction(programOptions) { + const spinner = ora("Fetching the popular person's data...").start(); console.log("hello-world"); + + requestOptions.path = `/3/person/popular?page=${programOptions.page}`; + data = await getPersons(requestOptions); + + renderPersons(data); + + spinner.succeed("Popular persons data loaded"); }); +/* +************ test it with ************** + +node src/moviedb.js get-person -i 990393 + +or + +node src/moviedb.js get-person -i 1245 +*/ program .command("get-person") .description("Make a network request to fetch the data of a single person") - .action(function handleAction() { - console.log("hello-world"); + .requiredOption("-i, --id", "The page of persons data results to fetch") + .action(async function handleAction(programOptions) { + const spinner = ora("Fetching the person's data...").start(); + const id = programOptions.args.toString(); + requestOptions.path = `/3/person/${id}`; + + data = await getPerson(requestOptions); + + renderPerson(data); + + spinner.succeed("Person data loaded"); }); +/* +************ test it with ************** +1. popular movies : +node src/moviedb.js get-movies --page 6 +2. now playing movies : +node src/moviedb.js get-movies -n --page 1 +*/ + program .command("get-movies") .description("Make a network request to fetch movies") - .action(function handleAction() { - console.log("hello-world"); + .requiredOption( + "--page, ", + "The page of movies data results to fetch" + ) + .option("-p, --popular", "Fetch the popular movies") + .option("-n, --now-playing", "Fetch the movies that are playing now") + .action(async function handleAction(programOptions) { + const spinner = ora("Fetching the movies data...").start(); + const page = programOptions.args.toString(); + let data = ""; + + if ( + programOptions.popular || + (!programOptions.popular && !programOptions.nowPlaying) + ) { + requestOptions.path = `/3/movie/popular?page=${page}`; + data = await getMovies(requestOptions); + renderMovies(data, "Popular movies data loaded", spinner); + } else if (programOptions.nowPlaying) { + requestOptions.path = `/3/movie/now_playing?page=${page}`; + data = await getMovies(requestOptions); + renderMovies(data, "Movies playing now data loaded", spinner); + } }); +/* +************ test it with ************** +node src/moviedb.js get-movie --id 385128 -r +or +node src/moviedb.js get-movie -i 385128 --review +*/ program .command("get-movie") .description("Make a network request to fetch the data of a single person") - .action(function handleAction() { - console.log("hello-world"); + .requiredOption("-i, --id", "The id of the movie") + .option("-r, --review", "Fetching the reviws of the movie") + .action(async function handleAction(programOptions) { + const spinner = ora("Fetching movie data...").start(); + const id = programOptions.args.toString(); + + if (programOptions.r || programOptions.review) { + requestOptions.path = `/3/movie/${id}/reviews`; + } else { + requestOptions.path = `/3/movie/${id}`; + } + + data = await getMovie(requestOptions); + renderMovie(programOptions.review, programOptions.r, id); + spinner.succeed("Movie reviews data loaded"); }); // error on unknown commands diff --git a/src/utils/httpsRequest.js b/src/utils/httpsRequest.js new file mode 100644 index 0000000..7694d4b --- /dev/null +++ b/src/utils/httpsRequest.js @@ -0,0 +1,100 @@ +const https = require("https"); + +async function getPersons(options) { + let promise = new Promise((resolve, reject) => { + const req = https.request(options, (res) => { + let response = ""; + + res.on("data", function onData(chunk) { + response += chunk; + }); + + res.on("end", function onEnd() { + const data = JSON.parse(response); + resolve(data); + }); + + res.on("error", function (error) { + reject(error); + }); + }); + + req.end(); + }); + return await promise; +} + +async function getPerson(options) { + let promise = new Promise((resolve, reject) => { + const req = https.request(options, (res) => { + let response = ""; + + res.on("data", function onData(chunk) { + response += chunk; + }); + + res.on("end", function onEnd() { + const data = JSON.parse(response); + resolve(data); + }); + }); + + req.on("error", (error) => { + reject(error); + }); + req.end(); + }); + return await promise; +} + +async function getMovies(options) { + let promise = new Promise((resolve, reject) => { + const req = https.request(options, (res) => { + let response = ""; + + res.on("data", function onData(chunk) { + response += chunk; + }); + + res.on("end", function onEnd() { + const data = JSON.parse(response); + resolve(data); + }); + + res.on("error", function (error) { + reject(error); + }); + }); + + req.end(); + }); + return await promise; +} +async function getMovie(options) { + let promise = new Promise((resolve, reject) => { + const req = https.request(options, (res) => { + let response = ""; + + res.on("data", function onData(chunk) { + response += chunk; + }); + + res.on("end", function onEnd() { + const data = JSON.parse(response); + resolve(data); + }); + }); + + req.on("error", (error) => { + reject(error); + }); + req.end(); + }); + return await promise; +} +module.exports = { + getPersons: getPersons, + getPerson: getPerson, + getMovies: getMovies, + getMovie: getMovie, +}; diff --git a/src/utils/renderRequest.js b/src/utils/renderRequest.js new file mode 100644 index 0000000..65ec8e0 --- /dev/null +++ b/src/utils/renderRequest.js @@ -0,0 +1,181 @@ +const chalk = require("chalk"); + +function renderPersons(data) { + data.results.forEach((person) => { + console.log( + `PERSON: + + ID: ${person.id} + Name: ${chalk.bold.blue(person.name)} + Departament: ${chalk.magenta(person.known_for_department)}\n\n` + ); + + person.known_for.forEach((movies) => { + if (movies.original_title == undefined) { + console.log(`${chalk.yellow.dim("There's no movive ")}`); + } else { + console.log( + `\tMovie: + \tID: ${chalk.green(movies.id)} + \tRelease Date: ${chalk.green(movies.release_date)} + \tTitle: ${chalk.green(movies.original_title)}` + ); + } + }); + + console.log( + `--------------------------------------------------------\n\n` + ); + }); +} + +function renderPerson(data) { + console.log( + chalk.white( + `\n-----------------------------------------------------------------` + ) + ); + console.log(chalk.white("Person:\n")); + console.log(chalk.white("ID: ", data.id)); + console.log("Name: ", chalk.blue(data.name)); + console.log( + chalk.white("Birthday: ", data.birthday), + chalk.gray("|"), + chalk.white(data.place_of_birth) + ); + if (data.known_for_department === "Acting") { + console.log("Department: ", chalk.magenta(data.known_for_department)); + } else { + console.log(""); + } + console.log("Biography: ", chalk.bold.blue(data.biography)); + if (data.also_known_as) { + console.log(`\n`); + console.log(chalk.white("Also known as: \n")); + data.also_known_as.map((name) => console.log(chalk.white(name))); + console.log(`\n`); + } else { + console.log(`\n`); + console.log( + chalk.yellow(data.name), + "doesn't have any alternate names\n" + ); + } + +} + +function renderMovies(data, msg, spinner) { + console.log( + chalk.white( + `\n-----------------------------------------------------------------` + ) + ); + console.log("Page: ", chalk.white(data.page, " of ", data.total_pages)); + data.results.map((movie) => { + console.log( + chalk.white( + `\n-----------------------------------------------------------------\n` + ) + ); + console.log(chalk.white("Movie:\n")); + console.log("ID: ", chalk.white(movie.id)); + console.log("Title: ", chalk.bold.blue(movie.title)); + console.log("Release Date: ", chalk.white(movie.release_date, "\n")); + }); + spinner.succeed(msg); +} +function renderMovie( + reviewLong, + reviewShort, + movieID + ){ + + if(reviewLong || reviewShort){ + if(data.results.length==0){ + console.log(chalk.yellow(`\nThe movie: ${movieID} doesn’t have any reviews`)); + }else{ + + const reviews = data.results + + reviews.forEach((review)=>{ + reviewText=""; + if(review.content.length>400){ + reviewText=review.content.slice(0,400); + console.log(` + \nAuthor: + \n\t${chalk.bold.blue(review.author)} + \nContent: + \n\t${chalk.whiteBright(reviewText)}...\n\n` + ) + + }else{ + reviewText=review.content; + console.log(` + \nAuthor: + \n\t${chalk.bold.blue(review.author)} + \nContent: + \n\t${chalk.white(reviewText)}\n\n` + ) + } + }) + } + + if(data.total_pages>data.page){ + console.log(chalk.white(`\n---------------------------------\n + ${data.page}/${data.total_pages}\n`)) + + } + }else{ + //console.log(data); + console.log(chalk.white( + `\n-------------------------------------\n + MOVIE: + + \n\tID: + \n\t\t${chalk.white(data.id)} + \n\tTitle: + \n\t\t${chalk.bold.blue(data.original_title)} + \n\tRelease Date: + \n\t\t${chalk.white(data.release_date)} + \n\tRun time: + \n\t\t${chalk.white(data.runtime)} + \n\tVote count: + \n\t\t${chalk.white(data.vote_count)} + \n\tOverview: + \n\t\t${chalk.green(data.overview)}\n\n` + )); + let genres=data.genres + if(genres.length>0){ + genres.forEach((genre)=>console.log(chalk.white( + `\n------------------------------------- + \n\tGenres: + \n\t\t${chalk.white(genre.name)} + `)) + ) + }else{ + console.log(chalk.yellow(`The movie doesn’t have a declared genre\n\n`)); + + } + let lenguages=data.spoken_languages; + if(lenguages.length>0){ + lenguages.forEach((lenguage)=>console.log(chalk.white( + `\n-------------------------------------\n + \n\tLenguatges: + \n\t\t${chalk.white(lenguage.name)}\n + `)) + ) + }else{ + console.log(chalk.yellow( `The movie: ${data.id} doesn’t have any declared languages\n\n`)); + + } + } + +} + +module.exports = { + renderPersons: renderPersons, + renderPerson: renderPerson, + renderMovies: renderMovies, + renderMovie: renderMovie, + +};