From 5f859eebb862220f0932873b21b653e3b622f08f Mon Sep 17 00:00:00 2001 From: Foxix Date: Fri, 3 Jan 2025 19:36:22 +0000 Subject: [PATCH] Update 25 files - /docs/docs.go - /docs/swagger.json - /docs/swagger.yaml - /internal/api/handlers.go - /internal/api/init.go - /internal/api/models.go - /internal/api/utils.go - /internal/tmdb/client.go - /internal/tmdb/models.go - /src/config/tmdb.js - /src/routes/movies.js - /src/utils/date.js - /src/utils/health.js - /src/index.js - /build.sh - /clean.sh - /go.mod - /go.sum - /main.go - /package-lock.json - /package.json - /README.md - /render.yaml - /run.sh - /vercel.json --- README.md | 85 -- build.sh | 26 - clean.sh | 13 - docs/docs.go | 806 ------------------- docs/swagger.json | 782 ------------------ docs/swagger.yaml | 512 ------------ go.mod | 55 -- go.sum | 156 ---- internal/api/handlers.go | 505 ------------ internal/api/init.go | 14 - internal/api/models.go | 64 -- internal/api/utils.go | 24 - internal/tmdb/client.go | 399 ---------- internal/tmdb/models.go | 76 -- main.go | 125 --- package-lock.json | 1632 -------------------------------------- package.json | 27 - render.yaml | 13 - run.sh | 7 - src/config/tmdb.js | 105 --- src/index.js | 275 ------- src/routes/movies.js | 325 -------- src/utils/date.js | 13 - src/utils/health.js | 103 --- vercel.json | 22 - 25 files changed, 6164 deletions(-) delete mode 100644 README.md delete mode 100644 build.sh delete mode 100644 clean.sh delete mode 100644 docs/docs.go delete mode 100644 docs/swagger.json delete mode 100644 docs/swagger.yaml delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 internal/api/handlers.go delete mode 100644 internal/api/init.go delete mode 100644 internal/api/models.go delete mode 100644 internal/api/utils.go delete mode 100644 internal/tmdb/client.go delete mode 100644 internal/tmdb/models.go delete mode 100644 main.go delete mode 100644 package-lock.json delete mode 100644 package.json delete mode 100644 render.yaml delete mode 100644 run.sh delete mode 100644 src/config/tmdb.js delete mode 100644 src/index.js delete mode 100644 src/routes/movies.js delete mode 100644 src/utils/date.js delete mode 100644 src/utils/health.js delete mode 100644 vercel.json diff --git a/README.md b/README.md deleted file mode 100644 index e0191f4..0000000 --- a/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Neo Movies API - -REST API для поиска и получения информации о фильмах, использующий TMDB API. - -## Особенности - -- Поиск фильмов -- Информация о фильмах -- Популярные фильмы -- Топ рейтинговые фильмы -- Предстоящие фильмы -- Swagger документация -- Поддержка русского языка - -## Установка - -1. Клонируйте репозиторий: -```bash -git clone https://github.com/yourusername/neomovies-api.git -cd neomovies-api -``` - -2. Установите зависимости: -```bash -npm install -``` - -3. Создайте файл `.env` на основе `.env.example`: -```bash -cp .env.example .env -``` - -4. Добавьте ваш TMDB Access Token в `.env` файл: -``` -TMDB_ACCESS_TOKEN=your_token_here -``` - -## Запуск - -Для разработки: -```bash -npm run dev -``` - -Для продакшена: -```bash -npm start -``` - -## Развертывание на Vercel - -1. Установите Vercel CLI: -```bash -npm i -g vercel -``` - -2. Войдите в ваш аккаунт Vercel: -```bash -vercel login -``` - -3. Разверните приложение: -```bash -vercel -``` - -4. Добавьте переменные окружения в Vercel: -- Перейдите в настройки проекта на Vercel -- Добавьте `TMDB_ACCESS_TOKEN` в раздел Environment Variables - -## API Endpoints - -- `GET /health` - Проверка работоспособности API -- `GET /movies/search?query=&page=` - Поиск фильмов -- `GET /movies/:id` - Получить информацию о фильме -- `GET /movies/popular` - Получить список популярных фильмов -- `GET /movies/top-rated` - Получить список топ рейтинговых фильмов -- `GET /movies/upcoming` - Получить список предстоящих фильмов -- `GET /movies/:id/external-ids` - Получить внешние ID фильма - -## Документация API - -После запуска API, документация Swagger доступна по адресу: -``` -http://localhost:3000/api-docs diff --git a/build.sh b/build.sh deleted file mode 100644 index 8c03311..0000000 --- a/build.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# Создаем директорию для сборки -BUILD_DIR="$HOME/build_tmp" -mkdir -p "$BUILD_DIR" - -# Скачиваем и устанавливаем Go во временную директорию -curl -L https://go.dev/dl/go1.21.5.linux-amd64.tar.gz | tar -C "$BUILD_DIR" -xz - -# Настраиваем переменные окружения для Go -export PATH="$BUILD_DIR/go/bin:$PATH" -export GOPATH="$BUILD_DIR/go_path" -export GOCACHE="$BUILD_DIR/go-build" -export GOMODCACHE="$BUILD_DIR/go-mod" - -# Создаем необходимые директории -mkdir -p "$GOPATH" -mkdir -p "$GOCACHE" -mkdir -p "$GOMODCACHE" - -# Собираем приложение с отключенным CGO и уменьшенным бинарником -cd "$HOME/neomovies-api" -CGO_ENABLED=0 go build -ldflags="-s -w" -o app - -# Очищаем после сборки -rm -rf "$BUILD_DIR" diff --git a/clean.sh b/clean.sh deleted file mode 100644 index d1210ab..0000000 --- a/clean.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Очищаем кэш Go -rm -rf $HOME/go/pkg/* -rm -rf $HOME/.cache/go-build/* - -# Удаляем временные файлы -rm -f go1.21.5.linux-amd64.tar.gz -rm -rf $HOME/go/src/* - -# Очищаем ненужные файлы в проекте -rm -rf vendor/ -rm -f app diff --git a/docs/docs.go b/docs/docs.go deleted file mode 100644 index 0f5a7fd..0000000 --- a/docs/docs.go +++ /dev/null @@ -1,806 +0,0 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT -package docs - -import "github.com/swaggo/swag" - -const docTemplate = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/bridge/tmdb/discover/movie": { - "get": { - "description": "Get a list of movies based on filters", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Discover movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/discover/tv": { - "get": { - "description": "Get a list of TV shows based on filters", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Discover TV shows", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/popular": { - "get": { - "description": "Get a list of popular movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB popular movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/top_rated": { - "get": { - "description": "Get a list of top rated movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB top rated movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/upcoming": { - "get": { - "description": "Get a list of upcoming movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB upcoming movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/{id}": { - "get": { - "description": "Get detailed information about a specific movie directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB movie details", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.Movie" - } - } - } - } - }, - "/bridge/tmdb/movie/{id}/external_ids": { - "get": { - "description": "Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific movie", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB movie external IDs", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.ExternalIDs" - } - } - } - } - }, - "/bridge/tmdb/search/movie": { - "get": { - "description": "Search for movies directly in TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Search TMDB movies", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.MoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/search/tv": { - "get": { - "description": "Search for TV shows directly in TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Search TMDB TV shows", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.TVSearchResults" - } - } - } - } - }, - "/bridge/tmdb/tv/{id}/external_ids": { - "get": { - "description": "Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific TV show", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB TV show external IDs", - "parameters": [ - { - "type": "integer", - "description": "TV Show ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.ExternalIDs" - } - } - } - } - }, - "/movies/popular": { - "get": { - "description": "Get a list of popular movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get popular movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/search": { - "get": { - "description": "Search for movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Search movies", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/top-rated": { - "get": { - "description": "Get a list of top rated movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get top rated movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/upcoming": { - "get": { - "description": "Get a list of upcoming movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get upcoming movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/{id}": { - "get": { - "description": "Get detailed information about a specific movie", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get movie details", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MovieDetails" - } - } - } - } - } - }, - "definitions": { - "api.Genre": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "api.Movie": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "api.MovieDetails": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "budget": { - "type": "integer" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "revenue": { - "type": "integer" - }, - "runtime": { - "type": "integer" - }, - "status": { - "type": "string" - }, - "tagline": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "api.MoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "api.TMDBMoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "tmdb.ExternalIDs": { - "type": "object", - "properties": { - "facebook_id": { - "type": "string" - }, - "id": { - "type": "integer" - }, - "imdb_id": { - "type": "string" - }, - "instagram_id": { - "type": "string" - }, - "twitter_id": { - "type": "string" - } - } - }, - "tmdb.Genre": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "tmdb.Movie": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "tmdb.MoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "tmdb.TV": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "first_air_date": { - "type": "string" - }, - "genre_ids": { - "type": "array", - "items": { - "type": "integer" - } - }, - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "original_language": { - "type": "string" - }, - "original_name": { - "type": "string" - }, - "overview": { - "type": "string" - }, - "popularity": { - "type": "number" - }, - "poster_path": { - "type": "string" - }, - "vote_average": { - "type": "number" - }, - "vote_count": { - "type": "integer" - } - } - }, - "tmdb.TVSearchResults": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.TV" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - } - } -}` - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = &swag.Spec{ - Version: "1.0", - Host: "localhost:8080", - BasePath: "/", - Schemes: []string{}, - Title: "Neo Movies API", - Description: "API для работы с фильмами", - InfoInstanceName: "swagger", - SwaggerTemplate: docTemplate, - LeftDelim: "{{", - RightDelim: "}}", -} - -func init() { - swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) -} diff --git a/docs/swagger.json b/docs/swagger.json deleted file mode 100644 index 5879bc7..0000000 --- a/docs/swagger.json +++ /dev/null @@ -1,782 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "API для работы с фильмами", - "title": "Neo Movies API", - "contact": {}, - "version": "1.0" - }, - "host": "localhost:8080", - "basePath": "/", - "paths": { - "/bridge/tmdb/discover/movie": { - "get": { - "description": "Get a list of movies based on filters", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Discover movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/discover/tv": { - "get": { - "description": "Get a list of TV shows based on filters", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Discover TV shows", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/popular": { - "get": { - "description": "Get a list of popular movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB popular movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/top_rated": { - "get": { - "description": "Get a list of top rated movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB top rated movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/upcoming": { - "get": { - "description": "Get a list of upcoming movies directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB upcoming movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.TMDBMoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/movie/{id}": { - "get": { - "description": "Get detailed information about a specific movie directly from TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB movie details", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.Movie" - } - } - } - } - }, - "/bridge/tmdb/movie/{id}/external_ids": { - "get": { - "description": "Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific movie", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB movie external IDs", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.ExternalIDs" - } - } - } - } - }, - "/bridge/tmdb/search/movie": { - "get": { - "description": "Search for movies directly in TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Search TMDB movies", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.MoviesResponse" - } - } - } - } - }, - "/bridge/tmdb/search/tv": { - "get": { - "description": "Search for TV shows directly in TMDB", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Search TMDB TV shows", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.TVSearchResults" - } - } - } - } - }, - "/bridge/tmdb/tv/{id}/external_ids": { - "get": { - "description": "Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific TV show", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "tmdb" - ], - "summary": "Get TMDB TV show external IDs", - "parameters": [ - { - "type": "integer", - "description": "TV Show ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tmdb.ExternalIDs" - } - } - } - } - }, - "/movies/popular": { - "get": { - "description": "Get a list of popular movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get popular movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/search": { - "get": { - "description": "Search for movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Search movies", - "parameters": [ - { - "type": "string", - "description": "Search query", - "name": "query", - "in": "query", - "required": true - }, - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/top-rated": { - "get": { - "description": "Get a list of top rated movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get top rated movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/upcoming": { - "get": { - "description": "Get a list of upcoming movies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get upcoming movies", - "parameters": [ - { - "type": "integer", - "description": "Page number (default: 1)", - "name": "page", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MoviesResponse" - } - } - } - } - }, - "/movies/{id}": { - "get": { - "description": "Get detailed information about a specific movie", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "movies" - ], - "summary": "Get movie details", - "parameters": [ - { - "type": "integer", - "description": "Movie ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.MovieDetails" - } - } - } - } - } - }, - "definitions": { - "api.Genre": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "api.Movie": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "api.MovieDetails": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "budget": { - "type": "integer" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "revenue": { - "type": "integer" - }, - "runtime": { - "type": "integer" - }, - "status": { - "type": "string" - }, - "tagline": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "api.MoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "api.TMDBMoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "tmdb.ExternalIDs": { - "type": "object", - "properties": { - "facebook_id": { - "type": "string" - }, - "id": { - "type": "integer" - }, - "imdb_id": { - "type": "string" - }, - "instagram_id": { - "type": "string" - }, - "twitter_id": { - "type": "string" - } - } - }, - "tmdb.Genre": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "tmdb.Movie": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "genres": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.Genre" - } - }, - "id": { - "type": "integer" - }, - "overview": { - "type": "string" - }, - "poster_path": { - "type": "string" - }, - "release_date": { - "type": "string" - }, - "title": { - "type": "string" - }, - "vote_average": { - "type": "number" - } - } - }, - "tmdb.MoviesResponse": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.Movie" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - }, - "tmdb.TV": { - "type": "object", - "properties": { - "backdrop_path": { - "type": "string" - }, - "first_air_date": { - "type": "string" - }, - "genre_ids": { - "type": "array", - "items": { - "type": "integer" - } - }, - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "original_language": { - "type": "string" - }, - "original_name": { - "type": "string" - }, - "overview": { - "type": "string" - }, - "popularity": { - "type": "number" - }, - "poster_path": { - "type": "string" - }, - "vote_average": { - "type": "number" - }, - "vote_count": { - "type": "integer" - } - } - }, - "tmdb.TVSearchResults": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/tmdb.TV" - } - }, - "total_pages": { - "type": "integer" - }, - "total_results": { - "type": "integer" - } - } - } - } -} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml deleted file mode 100644 index 7900459..0000000 --- a/docs/swagger.yaml +++ /dev/null @@ -1,512 +0,0 @@ -basePath: / -definitions: - api.Genre: - properties: - id: - type: integer - name: - type: string - type: object - api.Movie: - properties: - backdrop_path: - type: string - genres: - items: - $ref: '#/definitions/api.Genre' - type: array - id: - type: integer - overview: - type: string - poster_path: - type: string - release_date: - type: string - title: - type: string - vote_average: - type: number - type: object - api.MovieDetails: - properties: - backdrop_path: - type: string - budget: - type: integer - genres: - items: - $ref: '#/definitions/api.Genre' - type: array - id: - type: integer - overview: - type: string - poster_path: - type: string - release_date: - type: string - revenue: - type: integer - runtime: - type: integer - status: - type: string - tagline: - type: string - title: - type: string - vote_average: - type: number - type: object - api.MoviesResponse: - properties: - page: - type: integer - results: - items: - $ref: '#/definitions/api.Movie' - type: array - total_pages: - type: integer - total_results: - type: integer - type: object - api.TMDBMoviesResponse: - properties: - page: - type: integer - results: - items: - $ref: '#/definitions/api.Movie' - type: array - total_pages: - type: integer - total_results: - type: integer - type: object - tmdb.ExternalIDs: - properties: - facebook_id: - type: string - id: - type: integer - imdb_id: - type: string - instagram_id: - type: string - twitter_id: - type: string - type: object - tmdb.Genre: - properties: - id: - type: integer - name: - type: string - type: object - tmdb.Movie: - properties: - backdrop_path: - type: string - genres: - items: - $ref: '#/definitions/tmdb.Genre' - type: array - id: - type: integer - overview: - type: string - poster_path: - type: string - release_date: - type: string - title: - type: string - vote_average: - type: number - type: object - tmdb.MoviesResponse: - properties: - page: - type: integer - results: - items: - $ref: '#/definitions/tmdb.Movie' - type: array - total_pages: - type: integer - total_results: - type: integer - type: object - tmdb.TV: - properties: - backdrop_path: - type: string - first_air_date: - type: string - genre_ids: - items: - type: integer - type: array - id: - type: integer - name: - type: string - original_language: - type: string - original_name: - type: string - overview: - type: string - popularity: - type: number - poster_path: - type: string - vote_average: - type: number - vote_count: - type: integer - type: object - tmdb.TVSearchResults: - properties: - page: - type: integer - results: - items: - $ref: '#/definitions/tmdb.TV' - type: array - total_pages: - type: integer - total_results: - type: integer - type: object -host: localhost:8080 -info: - contact: {} - description: API для работы с фильмами - title: Neo Movies API - version: "1.0" -paths: - /bridge/tmdb/discover/movie: - get: - consumes: - - application/json - description: Get a list of movies based on filters - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.TMDBMoviesResponse' - summary: Discover movies - tags: - - tmdb - /bridge/tmdb/discover/tv: - get: - consumes: - - application/json - description: Get a list of TV shows based on filters - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.TMDBMoviesResponse' - summary: Discover TV shows - tags: - - tmdb - /bridge/tmdb/movie/{id}: - get: - consumes: - - application/json - description: Get detailed information about a specific movie directly from TMDB - parameters: - - description: Movie ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/tmdb.Movie' - summary: Get TMDB movie details - tags: - - tmdb - /bridge/tmdb/movie/{id}/external_ids: - get: - consumes: - - application/json - description: Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific - movie - parameters: - - description: Movie ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/tmdb.ExternalIDs' - summary: Get TMDB movie external IDs - tags: - - tmdb - /bridge/tmdb/movie/popular: - get: - consumes: - - application/json - description: Get a list of popular movies directly from TMDB - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.TMDBMoviesResponse' - summary: Get TMDB popular movies - tags: - - tmdb - /bridge/tmdb/movie/top_rated: - get: - consumes: - - application/json - description: Get a list of top rated movies directly from TMDB - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.TMDBMoviesResponse' - summary: Get TMDB top rated movies - tags: - - tmdb - /bridge/tmdb/movie/upcoming: - get: - consumes: - - application/json - description: Get a list of upcoming movies directly from TMDB - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.TMDBMoviesResponse' - summary: Get TMDB upcoming movies - tags: - - tmdb - /bridge/tmdb/search/movie: - get: - consumes: - - application/json - description: Search for movies directly in TMDB - parameters: - - description: Search query - in: query - name: query - required: true - type: string - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/tmdb.MoviesResponse' - summary: Search TMDB movies - tags: - - tmdb - /bridge/tmdb/search/tv: - get: - consumes: - - application/json - description: Search for TV shows directly in TMDB - parameters: - - description: Search query - in: query - name: query - required: true - type: string - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/tmdb.TVSearchResults' - summary: Search TMDB TV shows - tags: - - tmdb - /bridge/tmdb/tv/{id}/external_ids: - get: - consumes: - - application/json - description: Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific - TV show - parameters: - - description: TV Show ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/tmdb.ExternalIDs' - summary: Get TMDB TV show external IDs - tags: - - tmdb - /movies/{id}: - get: - consumes: - - application/json - description: Get detailed information about a specific movie - parameters: - - description: Movie ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.MovieDetails' - summary: Get movie details - tags: - - movies - /movies/popular: - get: - consumes: - - application/json - description: Get a list of popular movies - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.MoviesResponse' - summary: Get popular movies - tags: - - movies - /movies/search: - get: - consumes: - - application/json - description: Search for movies - parameters: - - description: Search query - in: query - name: query - required: true - type: string - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.MoviesResponse' - summary: Search movies - tags: - - movies - /movies/top-rated: - get: - consumes: - - application/json - description: Get a list of top rated movies - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.MoviesResponse' - summary: Get top rated movies - tags: - - movies - /movies/upcoming: - get: - consumes: - - application/json - description: Get a list of upcoming movies - parameters: - - description: 'Page number (default: 1)' - in: query - name: page - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.MoviesResponse' - summary: Get upcoming movies - tags: - - movies -swagger: "2.0" diff --git a/go.mod b/go.mod deleted file mode 100644 index 547a6bd..0000000 --- a/go.mod +++ /dev/null @@ -1,55 +0,0 @@ -module neomovies-api - -go 1.21.0 - -toolchain go1.23.4 - -require ( - github.com/gin-gonic/gin v1.10.0 - github.com/joho/godotenv v1.5.1 - github.com/swaggo/files v1.0.1 - github.com/swaggo/gin-swagger v1.6.0 - github.com/swaggo/swag v1.16.2 -) - -require ( - github.com/KyleBanks/depth v1.2.1 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/bytedance/sonic v1.12.6 // indirect - github.com/bytedance/sonic/loader v0.2.1 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.7 // indirect - github.com/gin-contrib/cors v1.7.3 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/spec v0.20.4 // indirect - github.com/go-openapi/swag v0.19.15 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.23.0 // indirect - github.com/goccy/go-json v0.10.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.7.6 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.12.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - h12.io/socks v1.0.3 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 4db1636..0000000 --- a/go.sum +++ /dev/null @@ -1,156 +0,0 @@ -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= -github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= -github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= -github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= -github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= -github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= -github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= -github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= -github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= -github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= -github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= -github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= -github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= -github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= -golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo= -h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/internal/api/handlers.go b/internal/api/handlers.go deleted file mode 100644 index ed09ac1..0000000 --- a/internal/api/handlers.go +++ /dev/null @@ -1,505 +0,0 @@ -package api - -import ( - "net/http" - - "github.com/gin-gonic/gin" - "neomovies-api/internal/tmdb" -) - -// GetPopularMovies возвращает список популярных фильмов -// @Summary Get popular movies -// @Description Get a list of popular movies -// @Tags movies -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} MoviesResponse -// @Router /movies/popular [get] -func GetPopularMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetPopular(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// GetMovie возвращает информацию о фильме -// @Summary Get movie details -// @Description Get detailed information about a specific movie -// @Tags movies -// @Accept json -// @Produce json -// @Param id path int true "Movie ID" -// @Success 200 {object} MovieDetails -// @Router /movies/{id} [get] -func GetMovie(c *gin.Context) { - id := c.Param("id") - - movie, err := tmdbClient.GetMovie(id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - if movie.PosterPath != "" { - movie.PosterPath = tmdbClient.GetImageURL(movie.PosterPath, "original") - } - if movie.BackdropPath != "" { - movie.BackdropPath = tmdbClient.GetImageURL(movie.BackdropPath, "original") - } - - // Обрабатываем изображения для коллекции - if movie.BelongsToCollection != nil { - if movie.BelongsToCollection.PosterPath != "" { - movie.BelongsToCollection.PosterPath = tmdbClient.GetImageURL(movie.BelongsToCollection.PosterPath, "w500") - } - if movie.BelongsToCollection.BackdropPath != "" { - movie.BelongsToCollection.BackdropPath = tmdbClient.GetImageURL(movie.BelongsToCollection.BackdropPath, "w1280") - } - } - - // Обрабатываем логотипы компаний - for i := range movie.ProductionCompanies { - if movie.ProductionCompanies[i].LogoPath != "" { - movie.ProductionCompanies[i].LogoPath = tmdbClient.GetImageURL(movie.ProductionCompanies[i].LogoPath, "w185") - } - } - - c.JSON(http.StatusOK, movie) -} - -// SearchMovies ищет фильмы -// @Summary Поиск фильмов -// @Description Поиск фильмов по запросу -// @Tags movies -// @Accept json -// @Produce json -// @Param query query string true "Поисковый запрос" -// @Param page query string false "Номер страницы (по умолчанию 1)" -// @Success 200 {object} SearchResponse -// @Router /movies/search [get] -func SearchMovies(c *gin.Context) { - query := c.Query("query") - if query == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter is required"}) - return - } - - page := c.DefaultQuery("page", "1") - - // Получаем результаты поиска - results, err := tmdbClient.SearchMovies(query, page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Преобразуем результаты в формат ответа - response := SearchResponse{ - Page: results.Page, - TotalPages: results.TotalPages, - TotalResults: results.TotalResults, - Results: make([]MovieResponse, 0), - } - - // Преобразуем каждый фильм - for _, movie := range results.Results { - // Форматируем дату - releaseDate := formatDate(movie.ReleaseDate) - - // Добавляем фильм в результаты - response.Results = append(response.Results, MovieResponse{ - ID: movie.ID, - Title: movie.Title, - Overview: movie.Overview, - ReleaseDate: releaseDate, - VoteAverage: movie.VoteAverage, - PosterPath: tmdbClient.GetImageURL(movie.PosterPath, "w500"), - BackdropPath: tmdbClient.GetImageURL(movie.BackdropPath, "w1280"), - }) - } - - c.JSON(http.StatusOK, response) -} - -// GetTopRatedMovies возвращает список лучших фильмов -// @Summary Get top rated movies -// @Description Get a list of top rated movies -// @Tags movies -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} MoviesResponse -// @Router /movies/top-rated [get] -func GetTopRatedMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetTopRated(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// GetUpcomingMovies возвращает список предстоящих фильмов -// @Summary Get upcoming movies -// @Description Get a list of upcoming movies -// @Tags movies -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} MoviesResponse -// @Router /movies/upcoming [get] -func GetUpcomingMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetUpcoming(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// GetTMDBPopularMovies возвращает список популярных фильмов из TMDB -// @Summary Get TMDB popular movies -// @Description Get a list of popular movies directly from TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} TMDBMoviesResponse -// @Router /bridge/tmdb/movie/popular [get] -func GetTMDBPopularMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetPopular(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// GetTMDBMovie возвращает информацию о фильме из TMDB -// @Summary Get TMDB movie details -// @Description Get detailed information about a specific movie directly from TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param id path int true "Movie ID" -// @Success 200 {object} tmdb.Movie -// @Router /bridge/tmdb/movie/{id} [get] -func GetTMDBMovie(c *gin.Context) { - id := c.Param("id") - - movie, err := tmdbClient.GetMovie(id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, movie) -} - -// GetTMDBTopRatedMovies возвращает список лучших фильмов из TMDB -// @Summary Get TMDB top rated movies -// @Description Get a list of top rated movies directly from TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} TMDBMoviesResponse -// @Router /bridge/tmdb/movie/top_rated [get] -func GetTMDBTopRatedMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetTopRated(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// GetTMDBUpcomingMovies возвращает список предстоящих фильмов из TMDB -// @Summary Get TMDB upcoming movies -// @Description Get a list of upcoming movies directly from TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} TMDBMoviesResponse -// @Router /bridge/tmdb/movie/upcoming [get] -func GetTMDBUpcomingMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - - movies, err := tmdbClient.GetUpcoming(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Добавляем полные URL для изображений - for i := range movies.Results { - if movies.Results[i].PosterPath != "" { - movies.Results[i].PosterPath = tmdbClient.GetImageURL(movies.Results[i].PosterPath, "w500") - } - if movies.Results[i].BackdropPath != "" { - movies.Results[i].BackdropPath = tmdbClient.GetImageURL(movies.Results[i].BackdropPath, "w1280") - } - } - - c.JSON(http.StatusOK, movies) -} - -// SearchTMDBMovies ищет фильмы в TMDB -// @Summary Search TMDB movies -// @Description Search for movies directly in TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param query query string true "Search query" -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} tmdb.MoviesResponse -// @Router /bridge/tmdb/search/movie [get] -func SearchTMDBMovies(c *gin.Context) { - query := c.Query("query") - if query == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter is required"}) - return - } - - page := c.DefaultQuery("page", "1") - movies, err := tmdbClient.SearchMovies(query, page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, movies) -} - -// SearchTMDBTV ищет сериалы в TMDB -// @Summary Search TMDB TV shows -// @Description Search for TV shows directly in TMDB -// @Tags tmdb -// @Accept json -// @Produce json -// @Param query query string true "Search query" -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} tmdb.TVSearchResults -// @Router /bridge/tmdb/search/tv [get] -func SearchTMDBTV(c *gin.Context) { - query := c.Query("query") - if query == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter is required"}) - return - } - - page := c.DefaultQuery("page", "1") - tv, err := tmdbClient.SearchTV(query, page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, tv) -} - -// DiscoverMovies возвращает список фильмов по фильтрам -// @Summary Discover movies -// @Description Get a list of movies based on filters -// @Tags tmdb -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} TMDBMoviesResponse -// @Router /bridge/tmdb/discover/movie [get] -func DiscoverMovies(c *gin.Context) { - page := c.DefaultQuery("page", "1") - movies, err := tmdbClient.DiscoverMovies(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - c.JSON(http.StatusOK, movies) -} - -// DiscoverTV возвращает список сериалов по фильтрам -// @Summary Discover TV shows -// @Description Get a list of TV shows based on filters -// @Tags tmdb -// @Accept json -// @Produce json -// @Param page query int false "Page number (default: 1)" -// @Success 200 {object} TMDBMoviesResponse -// @Router /bridge/tmdb/discover/tv [get] -func DiscoverTV(c *gin.Context) { - page := c.DefaultQuery("page", "1") - shows, err := tmdbClient.DiscoverTV(page) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - c.JSON(http.StatusOK, shows) -} - -// GetTMDBMovieExternalIDs возвращает внешние идентификаторы фильма -// @Summary Get TMDB movie external IDs -// @Description Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific movie -// @Tags tmdb -// @Accept json -// @Produce json -// @Param id path int true "Movie ID" -// @Success 200 {object} tmdb.ExternalIDs -// @Router /bridge/tmdb/movie/{id}/external_ids [get] -func GetTMDBMovieExternalIDs(c *gin.Context) { - id := c.Param("id") - - externalIDs, err := tmdbClient.GetMovieExternalIDs(id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, externalIDs) -} - -// GetTMDBTVExternalIDs возвращает внешние идентификаторы сериала -// @Summary Get TMDB TV show external IDs -// @Description Get external IDs (IMDb, Facebook, Instagram, Twitter) for a specific TV show -// @Tags tmdb -// @Accept json -// @Produce json -// @Param id path int true "TV Show ID" -// @Success 200 {object} tmdb.ExternalIDs -// @Router /bridge/tmdb/tv/{id}/external_ids [get] -func GetTMDBTVExternalIDs(c *gin.Context) { - id := c.Param("id") - - externalIDs, err := tmdbClient.GetTVExternalIDs(id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, externalIDs) -} - -// HealthCheck godoc -// @Summary Проверка работоспособности API -// @Description Проверяет, что API работает -// @Tags health -// @Produce json -// @Success 200 {object} map[string]string -// @Router /health [get] -func HealthCheck(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "status": "ok", - }) -} - -// InitTMDBClientWithProxy инициализирует TMDB клиент с прокси -func InitTMDBClientWithProxy(apiKey string, proxyAddr string) error { - tmdbClient = tmdb.NewClient(apiKey) - return tmdbClient.SetSOCKS5Proxy(proxyAddr) -} - -// Admin handlers - -// GetAdminMovies возвращает список фильмов для админа -func GetAdminMovies(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Admin movies list"}) -} - -// ToggleMovieVisibility переключает видимость фильма -func ToggleMovieVisibility(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Movie visibility toggled"}) -} - -// GetUsers возвращает список пользователей -func GetUsers(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Users list"}) -} - -// CreateUser создает нового пользователя -func CreateUser(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "User created"}) -} - -// ToggleAdmin переключает права администратора -func ToggleAdmin(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Admin status toggled"}) -} - -// SendVerification отправляет код верификации -func SendVerification(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Verification code sent"}) -} - -// VerifyCode проверяет код верификации -func VerifyCode(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "Code verified"}) -} diff --git a/internal/api/init.go b/internal/api/init.go deleted file mode 100644 index 874cf66..0000000 --- a/internal/api/init.go +++ /dev/null @@ -1,14 +0,0 @@ -package api - -import ( - "neomovies-api/internal/tmdb" -) - -var ( - tmdbClient *tmdb.Client -) - -// InitTMDBClient инициализирует TMDB клиент -func InitTMDBClient(apiKey string) { - tmdbClient = tmdb.NewClient(apiKey) -} diff --git a/internal/api/models.go b/internal/api/models.go deleted file mode 100644 index 42d6eb0..0000000 --- a/internal/api/models.go +++ /dev/null @@ -1,64 +0,0 @@ -package api - -// Genre представляет жанр фильма -type Genre struct { - ID int `json:"id"` - Name string `json:"name"` -} - -// Movie представляет базовую информацию о фильме -type Movie struct { - ID int `json:"id"` - Title string `json:"title"` - Overview string `json:"overview"` - PosterPath *string `json:"poster_path"` - BackdropPath *string `json:"backdrop_path"` - ReleaseDate string `json:"release_date"` - VoteAverage float64 `json:"vote_average"` - Genres []Genre `json:"genres"` -} - -// MovieDetails представляет детальную информацию о фильме -type MovieDetails struct { - Movie - Runtime int `json:"runtime"` - Tagline string `json:"tagline"` - Budget int `json:"budget"` - Revenue int `json:"revenue"` - Status string `json:"status"` -} - -// MoviesResponse представляет ответ со списком фильмов -type MoviesResponse struct { - Page int `json:"page"` - TotalPages int `json:"total_pages"` - TotalResults int `json:"total_results"` - Results []Movie `json:"results"` -} - -// TMDBMoviesResponse представляет ответ со списком фильмов от TMDB API -type TMDBMoviesResponse struct { - Page int `json:"page"` - TotalPages int `json:"total_pages"` - TotalResults int `json:"total_results"` - Results []Movie `json:"results"` -} - -// SearchResponse представляет ответ на поисковый запрос -type SearchResponse struct { - Page int `json:"page"` - TotalPages int `json:"total_pages"` - TotalResults int `json:"total_results"` - Results []MovieResponse `json:"results"` -} - -// MovieResponse представляет информацию о фильме в ответе API -type MovieResponse struct { - ID int `json:"id"` - Title string `json:"title"` - Overview string `json:"overview"` - ReleaseDate string `json:"release_date"` - VoteAverage float64 `json:"vote_average"` - PosterPath string `json:"poster_path"` - BackdropPath string `json:"backdrop_path"` -} diff --git a/internal/api/utils.go b/internal/api/utils.go deleted file mode 100644 index 3b62c43..0000000 --- a/internal/api/utils.go +++ /dev/null @@ -1,24 +0,0 @@ -package api - -import "time" - -// formatDate форматирует дату в более читаемый формат -func formatDate(date string) string { - if date == "" { - return "" - } - - // Парсим дату из формата YYYY-MM-DD - t, err := time.Parse("2006-01-02", date) - if err != nil { - return date - } - - // Форматируем дату в русском стиле - months := []string{ - "января", "февраля", "марта", "апреля", "мая", "июня", - "июля", "августа", "сентября", "октября", "ноября", "декабря", - } - - return t.Format("2") + " " + months[t.Month()-1] + " " + t.Format("2006") -} diff --git a/internal/tmdb/client.go b/internal/tmdb/client.go deleted file mode 100644 index 582849e..0000000 --- a/internal/tmdb/client.go +++ /dev/null @@ -1,399 +0,0 @@ -package tmdb - -import ( - "context" - "encoding/json" - "fmt" - "io" - "log" - "net" - "net/http" - "net/url" - "path" - "time" -) - -const ( - baseURL = "https://api.themoviedb.org/3" - imageBaseURL = "https://image.tmdb.org/t/p" - googleDNS = "8.8.8.8:53" // Google Public DNS - cloudflareDNS = "1.1.1.1:53" // Cloudflare DNS -) - -// Client представляет клиент для работы с TMDB API -type Client struct { - apiKey string - httpClient *http.Client -} - -// NewClient создает новый клиент TMDB API с кастомным DNS -func NewClient(apiKey string) *Client { - // Создаем кастомный DNS резолвер с двумя DNS серверами - dialer := &net.Dialer{ - Timeout: 5 * time.Second, - Resolver: &net.Resolver{ - PreferGo: true, - Dial: func(ctx context.Context, network, address string) (net.Conn, error) { - // Пробуем сначала Google DNS - d := net.Dialer{Timeout: 5 * time.Second} - conn, err := d.DialContext(ctx, "udp", googleDNS) - if err != nil { - log.Printf("Failed to connect to Google DNS, trying Cloudflare: %v", err) - // Если Google DNS не отвечает, пробуем Cloudflare - return d.DialContext(ctx, "udp", cloudflareDNS) - } - return conn, nil - }, - }, - } - - // Создаем транспорт с кастомным диалером - transport := &http.Transport{ - DialContext: dialer.DialContext, - TLSHandshakeTimeout: 5 * time.Second, - ResponseHeaderTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - } - - client := &Client{ - apiKey: apiKey, - httpClient: &http.Client{ - Transport: transport, - Timeout: 10 * time.Second, - }, - } - - // Проверяем работу DNS и API - log.Println("Testing DNS resolution and TMDB API access...") - - // Тест 1: Проверяем резолвинг через DNS - ips, err := net.LookupIP("api.themoviedb.org") - if err != nil { - log.Printf("Warning: DNS lookup failed: %v", err) - } else { - log.Printf("Successfully resolved api.themoviedb.org to: %v", ips) - } - - // Тест 2: Проверяем наш IP - resp, err := client.httpClient.Get("https://ipinfo.io/json") - if err != nil { - log.Printf("Warning: Failed to check our IP: %v", err) - } else { - defer resp.Body.Close() - var ipInfo struct { - IP string `json:"ip"` - City string `json:"city"` - Country string `json:"country"` - Org string `json:"org"` - } - if err := json.NewDecoder(resp.Body).Decode(&ipInfo); err != nil { - log.Printf("Warning: Failed to decode IP info: %v", err) - } else { - log.Printf("Our IP info: IP=%s, City=%s, Country=%s, Org=%s", - ipInfo.IP, ipInfo.City, ipInfo.Country, ipInfo.Org) - } - } - - // Тест 3: Проверяем доступ к TMDB API - testURL := fmt.Sprintf("%s/movie/popular?api_key=%s", baseURL, apiKey) - resp, err = client.httpClient.Get(testURL) - if err != nil { - log.Printf("Warning: TMDB API test failed: %v", err) - } else { - defer resp.Body.Close() - if resp.StatusCode == http.StatusOK { - log.Println("Successfully connected to TMDB API!") - } else { - log.Printf("Warning: TMDB API returned status code: %d", resp.StatusCode) - } - } - - return client -} - -// SetSOCKS5Proxy устанавливает SOCKS5 прокси для клиента -func (c *Client) SetSOCKS5Proxy(proxyAddr string) error { - return fmt.Errorf("proxy support has been removed in favor of custom DNS resolvers") -} - -// makeRequest выполняет HTTP запрос к TMDB API -func (c *Client) makeRequest(method, endpoint string, params url.Values) ([]byte, error) { - // Создаем URL - u, err := url.Parse(baseURL) - if err != nil { - return nil, fmt.Errorf("failed to parse base URL: %v", err) - } - u.Path = path.Join(u.Path, endpoint) - if params == nil { - params = url.Values{} - } - u.RawQuery = params.Encode() - - // Создаем запрос - req, err := http.NewRequest(method, u.String(), nil) - if err != nil { - return nil, fmt.Errorf("failed to create request: %v", err) - } - - // Добавляем заголовок авторизации - req.Header.Set("Authorization", "Bearer "+c.apiKey) - req.Header.Set("Content-Type", "application/json;charset=utf-8") - - log.Printf("Making request to TMDB: %s %s", method, u.String()) - - // Выполняем запрос - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to make request: %v", err) - } - defer resp.Body.Close() - - // Проверяем статус ответа - if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) - return nil, fmt.Errorf("TMDB API error: status=%d body=%s", resp.StatusCode, string(body)) - } - - // Читаем тело ответа - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body: %v", err) - } - - return body, nil -} - -// GetImageURL возвращает полный URL изображения -func (c *Client) GetImageURL(path string, size string) string { - if path == "" { - return "" - } - return fmt.Sprintf("%s/%s%s", imageBaseURL, size, path) -} - -// GetPopular получает список популярных фильмов -func (c *Client) GetPopular(page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "movie/popular", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &response, nil -} - -// GetMovie получает информацию о конкретном фильме -func (c *Client) GetMovie(id string) (*MovieDetails, error) { - body, err := c.makeRequest(http.MethodGet, fmt.Sprintf("movie/%s", id), nil) - if err != nil { - return nil, err - } - - var movie MovieDetails - if err := json.Unmarshal(body, &movie); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &movie, nil -} - -// SearchMovies ищет фильмы по запросу с поддержкой русского языка -func (c *Client) SearchMovies(query string, page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("query", query) - params.Set("page", page) - params.Set("language", "ru-RU") // Добавляем русский язык - params.Set("region", "RU") // Добавляем русский регион - params.Set("include_adult", "false") // Исключаем взрослый контент - - body, err := c.makeRequest(http.MethodGet, "search/movie", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - // Фильтруем результаты - filteredResults := make([]Movie, 0) - for _, movie := range response.Results { - // Проверяем, что у фильма есть постер и описание - if movie.PosterPath != "" && movie.Overview != "" { - // Проверяем, что рейтинг больше 0 - if movie.VoteAverage > 0 { - filteredResults = append(filteredResults, movie) - } - } - } - - // Обновляем результаты - response.Results = filteredResults - response.TotalResults = len(filteredResults) - - return &response, nil -} - -// GetTopRated получает список лучших фильмов -func (c *Client) GetTopRated(page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "movie/top_rated", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &response, nil -} - -// GetUpcoming получает список предстоящих фильмов -func (c *Client) GetUpcoming(page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "movie/upcoming", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &response, nil -} - -// DiscoverMovies получает список фильмов по фильтрам -func (c *Client) DiscoverMovies(page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "discover/movie", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &response, nil -} - -// DiscoverTV получает список сериалов по фильтрам -func (c *Client) DiscoverTV(page string) (*MoviesResponse, error) { - params := url.Values{} - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "discover/tv", params) - if err != nil { - return nil, err - } - - var response MoviesResponse - if err := json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &response, nil -} - -// ExternalIDs содержит внешние идентификаторы фильма/сериала -type ExternalIDs struct { - ID int `json:"id"` - IMDbID string `json:"imdb_id"` - FacebookID string `json:"facebook_id"` - InstagramID string `json:"instagram_id"` - TwitterID string `json:"twitter_id"` -} - -// GetMovieExternalIDs возвращает внешние идентификаторы фильма -func (c *Client) GetMovieExternalIDs(id string) (*ExternalIDs, error) { - body, err := c.makeRequest(http.MethodGet, fmt.Sprintf("movie/%s/external_ids", id), nil) - if err != nil { - return nil, err - } - - var externalIDs ExternalIDs - if err := json.Unmarshal(body, &externalIDs); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &externalIDs, nil -} - -// GetTVExternalIDs возвращает внешние идентификаторы сериала -func (c *Client) GetTVExternalIDs(id string) (*ExternalIDs, error) { - body, err := c.makeRequest(http.MethodGet, fmt.Sprintf("tv/%s/external_ids", id), nil) - if err != nil { - return nil, err - } - - var externalIDs ExternalIDs - if err := json.Unmarshal(body, &externalIDs); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &externalIDs, nil -} - -// TVSearchResults содержит результаты поиска сериалов -type TVSearchResults struct { - Page int `json:"page"` - TotalResults int `json:"total_results"` - TotalPages int `json:"total_pages"` - Results []TV `json:"results"` -} - -// TV содержит информацию о сериале -type TV struct { - ID int `json:"id"` - Name string `json:"name"` - OriginalName string `json:"original_name"` - Overview string `json:"overview"` - FirstAirDate string `json:"first_air_date"` - PosterPath string `json:"poster_path"` - BackdropPath string `json:"backdrop_path"` - VoteAverage float64 `json:"vote_average"` - VoteCount int `json:"vote_count"` - Popularity float64 `json:"popularity"` - OriginalLanguage string `json:"original_language"` - GenreIDs []int `json:"genre_ids"` -} - -// SearchTV ищет сериалы в TMDB -func (c *Client) SearchTV(query string, page string) (*TVSearchResults, error) { - params := url.Values{} - params.Set("query", query) - params.Set("page", page) - - body, err := c.makeRequest(http.MethodGet, "search/tv", params) - if err != nil { - return nil, err - } - - var results TVSearchResults - if err := json.Unmarshal(body, &results); err != nil { - return nil, fmt.Errorf("error decoding response: %v", err) - } - - return &results, nil -} diff --git a/internal/tmdb/models.go b/internal/tmdb/models.go deleted file mode 100644 index 28bc434..0000000 --- a/internal/tmdb/models.go +++ /dev/null @@ -1,76 +0,0 @@ -package tmdb - -// MoviesResponse представляет ответ от TMDB API со списком фильмов -type MoviesResponse struct { - Page int `json:"page"` - Results []Movie `json:"results"` - TotalPages int `json:"total_pages"` - TotalResults int `json:"total_results"` -} - -// Movie представляет информацию о фильме -type Movie struct { - Adult bool `json:"adult"` - BackdropPath string `json:"backdrop_path"` - GenreIDs []int `json:"genre_ids"` - ID int `json:"id"` - OriginalLanguage string `json:"original_language"` - OriginalTitle string `json:"original_title"` - Overview string `json:"overview"` - Popularity float64 `json:"popularity"` - PosterPath string `json:"poster_path"` - ReleaseDate string `json:"release_date"` - Title string `json:"title"` - Video bool `json:"video"` - VoteAverage float64 `json:"vote_average"` - VoteCount int `json:"vote_count"` -} - -// Genre представляет жанр фильма -type Genre struct { - ID int `json:"id"` - Name string `json:"name"` -} - -// Collection представляет коллекцию фильмов -type Collection struct { - ID int `json:"id"` - Name string `json:"name"` - PosterPath string `json:"poster_path"` - BackdropPath string `json:"backdrop_path"` -} - -// ProductionCompany представляет компанию-производителя -type ProductionCompany struct { - ID int `json:"id"` - LogoPath string `json:"logo_path"` - Name string `json:"name"` - Country string `json:"origin_country"` -} - -// MovieDetails представляет детальную информацию о фильме -type MovieDetails struct { - Adult bool `json:"adult"` - BackdropPath string `json:"backdrop_path"` - BelongsToCollection *Collection `json:"belongs_to_collection"` - Budget int `json:"budget"` - Genres []Genre `json:"genres"` - Homepage string `json:"homepage"` - ID int `json:"id"` - IMDbID string `json:"imdb_id"` - OriginalLanguage string `json:"original_language"` - OriginalTitle string `json:"original_title"` - Overview string `json:"overview"` - Popularity float64 `json:"popularity"` - PosterPath string `json:"poster_path"` - ProductionCompanies []ProductionCompany `json:"production_companies"` - ReleaseDate string `json:"release_date"` - Revenue int `json:"revenue"` - Runtime int `json:"runtime"` - Status string `json:"status"` - Tagline string `json:"tagline"` - Title string `json:"title"` - Video bool `json:"video"` - VoteAverage float64 `json:"vote_average"` - VoteCount int `json:"vote_count"` -} diff --git a/main.go b/main.go deleted file mode 100644 index ef26ad0..0000000 --- a/main.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "log" - "os" - - "neomovies-api/internal/api" - - "github.com/gin-contrib/cors" - "github.com/gin-gonic/gin" - swaggerFiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" - - _ "neomovies-api/docs" -) - -// @title Neo Movies API -// @version 1.0 -// @description API для работы с фильмами -// @host localhost:8080 -// @BasePath / -func main() { - // Устанавливаем переменные окружения - os.Setenv("GIN_MODE", "debug") - os.Setenv("PORT", "8080") - os.Setenv("TMDB_ACCESS_TOKEN", "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI4ZmU3ODhlYmI5ZDAwNjZiNjQ2MWZhNzk5M2MyMzcxYiIsIm5iZiI6MTcyMzQwMTM3My4yMDgsInN1YiI6IjY2YjkwNDlkNzU4ZDQxOTQwYzA3NjlhNSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.x50tvcWDdBTEhtwRb3dE7aEe9qu4sXV_qOjLMn_Vmew") - - // Инициализируем TMDB клиент с CommsOne DNS - log.Println("Initializing TMDB client with CommsOne DNS") - api.InitTMDBClient(os.Getenv("TMDB_ACCESS_TOKEN")) - - // Устанавливаем режим Gin - gin.SetMode(os.Getenv("GIN_MODE")) - - // Создаем роутер - r := gin.Default() - - // Настраиваем CORS - r.Use(cors.New(cors.Config{ - AllowOrigins: []string{"*"}, - AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, - AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"}, - })) - - // Swagger документация - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - // Health check - r.GET("/health", api.HealthCheck) - - // Movies API - movies := r.Group("/movies") - { - movies.GET("/popular", api.GetPopularMovies) - movies.GET("/search", api.SearchMovies) - movies.GET("/top-rated", api.GetTopRatedMovies) - movies.GET("/upcoming", api.GetUpcomingMovies) - movies.GET("/:id", api.GetMovie) - } - - // Bridge API - bridge := r.Group("/bridge") - { - // TMDB endpoints - tmdb := bridge.Group("/tmdb") - { - // Movie endpoints - movie := tmdb.Group("/movie") - { - movie.GET("/popular", api.GetTMDBPopularMovies) - movie.GET("/top_rated", api.GetTMDBTopRatedMovies) - movie.GET("/upcoming", api.GetTMDBUpcomingMovies) - movie.GET("/:id", api.GetTMDBMovie) - movie.GET("/:id/external_ids", api.GetTMDBMovieExternalIDs) - } - - // Search endpoints - search := tmdb.Group("/search") - { - search.GET("/movie", api.SearchTMDBMovies) - search.GET("/tv", api.SearchTMDBTV) - } - - // TV endpoints - tv := tmdb.Group("/tv") - { - tv.GET("/:id/external_ids", api.GetTMDBTVExternalIDs) - } - - // Discover endpoints - discover := tmdb.Group("/discover") - { - discover.GET("/movie", api.DiscoverMovies) - discover.GET("/tv", api.DiscoverTV) - } - } - } - - // Admin API - admin := r.Group("/admin") - { - // Movies endpoints - adminMovies := admin.Group("/movies") - { - adminMovies.GET("", api.GetAdminMovies) - adminMovies.POST("/toggle-visibility", api.ToggleMovieVisibility) - } - - // Users endpoints - adminUsers := admin.Group("/users") - { - adminUsers.GET("", api.GetUsers) - adminUsers.POST("/create", api.CreateUser) - adminUsers.POST("/toggle-admin", api.ToggleAdmin) - adminUsers.POST("/send-verification", api.SendVerification) - adminUsers.POST("/verify-code", api.VerifyCode) - } - } - - // Запускаем сервер - port := os.Getenv("PORT") - if err := r.Run(":" + port); err != nil { - log.Fatal(err) - } -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index c17d700..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1632 +0,0 @@ -{ - "name": "neomovies-api", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "neomovies-api", - "version": "1.0.0", - "dependencies": { - "axios": "^1.6.2", - "cors": "^2.8.5", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0" - }, - "devDependencies": { - "nodemon": "^3.0.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", - "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - } - }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "license": "MIT" - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@apidevtools/openapi-schemas": "^2.0.4", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "z-schema": "^5.0.1" - }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "license": "MIT" - }, - "node_modules/@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true, - "license": "Apache-2.0" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "license": "MIT" - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "function-bind": "^1.1.2", - "get-proto": "^1.0.0", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "license": "MIT" - }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "license": "MIT" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nodemon": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", - "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "license": "MIT", - "peer": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true, - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/swagger-jsdoc": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", - "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", - "license": "MIT", - "dependencies": { - "commander": "6.2.0", - "doctrine": "3.0.0", - "glob": "7.1.6", - "lodash.mergewith": "^4.6.2", - "swagger-parser": "^10.0.3", - "yaml": "2.0.0-1" - }, - "bin": { - "swagger-jsdoc": "bin/swagger-jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/swagger-parser": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", - "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", - "license": "MIT", - "dependencies": { - "@apidevtools/swagger-parser": "10.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/swagger-ui-dist": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", - "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", - "license": "Apache-2.0", - "dependencies": { - "@scarf/scarf": "=1.4.0" - } - }, - "node_modules/swagger-ui-express": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", - "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", - "license": "MIT", - "dependencies": { - "swagger-ui-dist": ">=5.0.0" - }, - "engines": { - "node": ">= v0.10.32" - }, - "peerDependencies": { - "express": ">=4.0.0 || >=5.0.0-beta" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/validator": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.0.0-1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", - "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/z-schema": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", - "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", - "license": "MIT", - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^9.4.1" - } - }, - "node_modules/z-schema/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": "^12.20.0 || >=14" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 04439ca..0000000 --- a/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "neomovies-api", - "version": "1.0.0", - "description": "Neo Movies API with TMDB integration", - "main": "src/index.js", - "scripts": { - "start": "node src/index.js", - "dev": "nodemon src/index.js", - "build": "npm install --production", - "vercel-build": "echo hello", - "clean": "rm -rf node_modules" - }, - "dependencies": { - "axios": "^1.6.2", - "cors": "^2.8.5", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0" - }, - "devDependencies": { - "nodemon": "^3.0.2" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/render.yaml b/render.yaml deleted file mode 100644 index e900a92..0000000 --- a/render.yaml +++ /dev/null @@ -1,13 +0,0 @@ -services: - - type: web - name: neomovies-api - env: go - buildCommand: go build -o app - startCommand: ./app - envVars: - - key: GIN_MODE - value: release - - key: TMDB_ACCESS_TOKEN - sync: false - healthCheckPath: /health - autoDeploy: true diff --git a/run.sh b/run.sh deleted file mode 100644 index a2046a0..0000000 --- a/run.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# Переходим в директорию с приложением -cd "$HOME/neomovies-api" - -# Запускаем приложение -PORT=$PORT GIN_MODE=release ./app diff --git a/src/config/tmdb.js b/src/config/tmdb.js deleted file mode 100644 index ada9f24..0000000 --- a/src/config/tmdb.js +++ /dev/null @@ -1,105 +0,0 @@ -const axios = require('axios'); - -class TMDBClient { - constructor(accessToken) { - this.client = axios.create({ - baseURL: 'https://api.themoviedb.org/3', - headers: { - 'Authorization': `Bearer ${accessToken}`, - 'Accept': 'application/json' - } - }); - } - - async makeRequest(method, endpoint, params = {}) { - try { - const response = await this.client.request({ - method, - url: endpoint, - params: { - ...params, - language: 'ru-RU', - region: 'RU' - } - }); - return response.data; - } catch (error) { - console.error(`TMDB API Error: ${error.message}`); - throw error; - } - } - - getImageURL(path, size = 'original') { - if (!path) return null; - return `https://image.tmdb.org/t/p/${size}${path}`; - } - - async searchMovies(query, page = 1) { - const data = await this.makeRequest('GET', '/search/movie', { - query, - page, - include_adult: false - }); - - // Фильтруем результаты - data.results = data.results.filter(movie => - movie.poster_path && - movie.overview && - movie.vote_average > 0 - ); - - // Добавляем полные URL для изображений - data.results = data.results.map(movie => ({ - ...movie, - poster_path: this.getImageURL(movie.poster_path, 'w500'), - backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280') - })); - - return data; - } - - async getMovie(id) { - const movie = await this.makeRequest('GET', `/movie/${id}`); - return { - ...movie, - poster_path: this.getImageURL(movie.poster_path, 'w500'), - backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280') - }; - } - - async getPopularMovies(page = 1) { - const data = await this.makeRequest('GET', '/movie/popular', { page }); - data.results = data.results.map(movie => ({ - ...movie, - poster_path: this.getImageURL(movie.poster_path, 'w500'), - backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280') - })); - return data; - } - - async getTopRatedMovies(page = 1) { - const data = await this.makeRequest('GET', '/movie/top_rated', { page }); - data.results = data.results.map(movie => ({ - ...movie, - poster_path: this.getImageURL(movie.poster_path, 'w500'), - backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280') - })); - return data; - } - - async getUpcomingMovies(page = 1) { - const data = await this.makeRequest('GET', '/movie/upcoming', { page }); - data.results = data.results.map(movie => ({ - ...movie, - poster_path: this.getImageURL(movie.poster_path, 'w500'), - backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280') - })); - return data; - } - - async getMovieExternalIDs(id) { - return await this.makeRequest('GET', `/movie/${id}/external_ids`); - } -} - -module.exports = TMDBClient; diff --git a/src/index.js b/src/index.js deleted file mode 100644 index a40d551..0000000 --- a/src/index.js +++ /dev/null @@ -1,275 +0,0 @@ -require('dotenv').config(); -const express = require('express'); -const cors = require('cors'); -const swaggerJsdoc = require('swagger-jsdoc'); -const swaggerUi = require('swagger-ui-express'); -const path = require('path'); -const TMDBClient = require('./config/tmdb'); -const healthCheck = require('./utils/health'); - -const app = express(); -const port = process.env.PORT || 3000; - -// Определяем базовый URL для документации -const BASE_URL = process.env.VERCEL_URL - ? `https://${process.env.VERCEL_URL}` - : `http://localhost:${port}`; - -// Swagger configuration -const swaggerOptions = { - definition: { - openapi: '3.0.0', - info: { - title: 'Neo Movies API', - version: '1.0.0', - description: 'API для поиска и получения информации о фильмах с поддержкой русского языка', - contact: { - name: 'API Support', - url: 'https://gitlab.com/foxixus/neomovies-api' - } - }, - servers: [ - { - url: BASE_URL, - description: process.env.VERCEL_URL ? 'Production server' : 'Development server', - }, - ], - tags: [ - { - name: 'movies', - description: 'Операции с фильмами' - }, - { - name: 'health', - description: 'Проверка работоспособности API' - } - ], - components: { - schemas: { - Movie: { - type: 'object', - properties: { - id: { - type: 'integer', - description: 'ID фильма' - }, - title: { - type: 'string', - description: 'Название фильма' - }, - overview: { - type: 'string', - description: 'Описание фильма' - }, - release_date: { - type: 'string', - format: 'date', - description: 'Дата выхода' - }, - vote_average: { - type: 'number', - description: 'Средняя оценка' - }, - poster_path: { - type: 'string', - description: 'URL постера' - }, - backdrop_path: { - type: 'string', - description: 'URL фонового изображения' - } - } - }, - Error: { - type: 'object', - properties: { - error: { - type: 'string', - description: 'Сообщение об ошибке' - } - } - }, - Health: { - type: 'object', - properties: { - status: { - type: 'string', - enum: ['healthy', 'unhealthy'], - description: 'Общий статус API' - }, - version: { - type: 'string', - description: 'Версия API' - }, - uptime: { - type: 'object', - properties: { - seconds: { - type: 'integer', - description: 'Время работы в секундах' - }, - formatted: { - type: 'string', - description: 'Отформатированное время работы' - } - } - }, - tmdb: { - type: 'object', - properties: { - status: { - type: 'string', - enum: ['ok', 'error'], - description: 'Статус подключения к TMDB' - }, - responseTime: { - type: 'integer', - description: 'Время ответа TMDB в мс' - }, - error: { - type: 'string', - description: 'Сообщение об ошибке, если есть' - } - } - }, - memory: { - type: 'object', - properties: { - heapTotal: { - type: 'integer', - description: 'Общий размер кучи (MB)' - }, - heapUsed: { - type: 'integer', - description: 'Использованный размер кучи (MB)' - }, - rss: { - type: 'integer', - description: 'Resident Set Size (MB)' - }, - memoryUsage: { - type: 'integer', - description: 'Процент использования памяти' - }, - system: { - type: 'object', - properties: { - total: { - type: 'integer', - description: 'Общая память системы (MB)' - }, - free: { - type: 'integer', - description: 'Свободная память системы (MB)' - }, - usage: { - type: 'integer', - description: 'Процент использования системной памяти' - } - } - } - } - }, - system: { - type: 'object', - properties: { - platform: { - type: 'string', - description: 'Операционная система' - }, - arch: { - type: 'string', - description: 'Архитектура процессора' - }, - nodeVersion: { - type: 'string', - description: 'Версия Node.js' - }, - cpuUsage: { - type: 'number', - description: 'Загрузка CPU' - } - } - }, - timestamp: { - type: 'string', - format: 'date-time', - description: 'Время проверки' - } - } - } - } - } - }, - apis: ['./src/routes/*.js', './src/index.js'], -}; - -const swaggerDocs = swaggerJsdoc(swaggerOptions); - -// Custom CSS для Swagger UI -const swaggerCustomOptions = { - customCss: '.swagger-ui .topbar { display: none }', - customSiteTitle: "Neo Movies API Documentation", - customfavIcon: "https://www.themoviedb.org/favicon.ico", - swaggerOptions: { - url: `${BASE_URL}/api-docs/swagger.json`, - persistAuthorization: true - } -}; - -// Middleware -app.use(cors()); -app.use(express.json()); -app.use(express.static(path.join(__dirname, 'public'))); - -// TMDB client middleware -app.use((req, res, next) => { - if (!process.env.TMDB_ACCESS_TOKEN) { - return res.status(500).json({ error: 'TMDB_ACCESS_TOKEN is not set' }); - } - req.tmdb = new TMDBClient(process.env.TMDB_ACCESS_TOKEN); - next(); -}); - -// Serve Swagger JSON -app.get('/api-docs/swagger.json', (req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.send(swaggerDocs); -}); - -// Routes -app.use('/api-docs', swaggerUi.serve); -app.get('/api-docs', swaggerUi.setup(null, swaggerCustomOptions)); -app.use('/movies', require('./routes/movies')); - -/** - * @swagger - * /health: - * get: - * tags: [health] - * summary: Проверка работоспособности API - * description: Возвращает подробную информацию о состоянии API, включая статус TMDB, использование памяти и системную информацию - * responses: - * 200: - * description: API работает нормально - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Health' - */ -app.get('/health', async (req, res) => { - const health = await healthCheck.getFullHealth(req.tmdb); - res.json(health); -}); - -// Error handling -app.use((err, req, res, next) => { - console.error(err.stack); - res.status(500).json({ error: 'Something went wrong!' }); -}); - -// Start server -app.listen(port, () => { - console.log(`Server is running on port ${port}`); - console.log(`Documentation available at http://localhost:${port}/api-docs`); -}); diff --git a/src/routes/movies.js b/src/routes/movies.js deleted file mode 100644 index 84dc57f..0000000 --- a/src/routes/movies.js +++ /dev/null @@ -1,325 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const { formatDate } = require('../utils/date'); - -/** - * @swagger - * /movies/search: - * get: - * summary: Поиск фильмов - * description: Поиск фильмов по запросу с поддержкой русского языка - * tags: [movies] - * parameters: - * - in: query - * name: query - * required: true - * description: Поисковый запрос - * schema: - * type: string - * example: Матрица - * - in: query - * name: page - * description: Номер страницы (по умолчанию 1) - * schema: - * type: integer - * minimum: 1 - * default: 1 - * example: 1 - * responses: - * 200: - * description: Успешный поиск - * content: - * application/json: - * schema: - * type: object - * properties: - * page: - * type: integer - * description: Текущая страница - * total_pages: - * type: integer - * description: Всего страниц - * total_results: - * type: integer - * description: Всего результатов - * results: - * type: array - * items: - * $ref: '#/components/schemas/Movie' - * 400: - * description: Неверный запрос - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/search', async (req, res) => { - try { - const { query, page = 1 } = req.query; - if (!query) { - return res.status(400).json({ error: "query parameter is required" }); - } - - const results = await req.tmdb.searchMovies(query, page); - - const response = { - page: results.page, - total_pages: results.total_pages, - total_results: results.total_results, - results: results.results.map(movie => ({ - id: movie.id, - title: movie.title, - overview: movie.overview, - release_date: formatDate(movie.release_date), - vote_average: movie.vote_average, - poster_path: movie.poster_path, - backdrop_path: movie.backdrop_path - })) - }; - - res.json(response); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -/** - * @swagger - * /movies/{id}: - * get: - * summary: Получить информацию о фильме - * description: Получает детальную информацию о фильме по ID - * tags: [movies] - * parameters: - * - in: path - * name: id - * required: true - * description: ID фильма - * schema: - * type: integer - * example: 603 - * responses: - * 200: - * description: Информация о фильме - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Movie' - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/:id', async (req, res) => { - try { - const movie = await req.tmdb.getMovie(req.params.id); - res.json({ - ...movie, - release_date: formatDate(movie.release_date) - }); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -/** - * @swagger - * /movies/popular: - * get: - * summary: Популярные фильмы - * description: Получает список популярных фильмов с русскими названиями и описаниями - * tags: [movies] - * parameters: - * - in: query - * name: page - * description: Номер страницы - * schema: - * type: integer - * minimum: 1 - * default: 1 - * example: 1 - * responses: - * 200: - * description: Список популярных фильмов - * content: - * application/json: - * schema: - * type: object - * properties: - * page: - * type: integer - * results: - * type: array - * items: - * $ref: '#/components/schemas/Movie' - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/popular', async (req, res) => { - try { - const { page = 1 } = req.query; - const movies = await req.tmdb.getPopularMovies(page); - res.json(movies); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -/** - * @swagger - * /movies/top-rated: - * get: - * summary: Лучшие фильмы - * description: Получает список лучших фильмов с русскими названиями и описаниями - * tags: [movies] - * parameters: - * - in: query - * name: page - * description: Номер страницы - * schema: - * type: integer - * minimum: 1 - * default: 1 - * example: 1 - * responses: - * 200: - * description: Список лучших фильмов - * content: - * application/json: - * schema: - * type: object - * properties: - * page: - * type: integer - * results: - * type: array - * items: - * $ref: '#/components/schemas/Movie' - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/top-rated', async (req, res) => { - try { - const { page = 1 } = req.query; - const movies = await req.tmdb.getTopRatedMovies(page); - res.json(movies); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -/** - * @swagger - * /movies/upcoming: - * get: - * summary: Предстоящие фильмы - * description: Получает список предстоящих фильмов с русскими названиями и описаниями - * tags: [movies] - * parameters: - * - in: query - * name: page - * description: Номер страницы - * schema: - * type: integer - * minimum: 1 - * default: 1 - * example: 1 - * responses: - * 200: - * description: Список предстоящих фильмов - * content: - * application/json: - * schema: - * type: object - * properties: - * page: - * type: integer - * results: - * type: array - * items: - * $ref: '#/components/schemas/Movie' - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/upcoming', async (req, res) => { - try { - const { page = 1 } = req.query; - const movies = await req.tmdb.getUpcomingMovies(page); - res.json(movies); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -/** - * @swagger - * /movies/{id}/external-ids: - * get: - * summary: Внешние ID фильма - * description: Получает внешние идентификаторы фильма (IMDb и др.) - * tags: [movies] - * parameters: - * - in: path - * name: id - * required: true - * description: ID фильма - * schema: - * type: integer - * example: 603 - * responses: - * 200: - * description: Внешние ID фильма - * content: - * application/json: - * schema: - * type: object - * properties: - * imdb_id: - * type: string - * description: ID на IMDb - * facebook_id: - * type: string - * description: ID на Facebook - * instagram_id: - * type: string - * description: ID на Instagram - * twitter_id: - * type: string - * description: ID на Twitter - * 500: - * description: Ошибка сервера - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Error' - */ -router.get('/:id/external-ids', async (req, res) => { - try { - const externalIds = await req.tmdb.getMovieExternalIDs(req.params.id); - res.json(externalIds); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -module.exports = router; diff --git a/src/utils/date.js b/src/utils/date.js deleted file mode 100644 index 34c04e6..0000000 --- a/src/utils/date.js +++ /dev/null @@ -1,13 +0,0 @@ -function formatDate(dateString) { - if (!dateString) return null; - const date = new Date(dateString); - return date.toLocaleDateString('ru-RU', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); -} - -module.exports = { - formatDate -}; diff --git a/src/utils/health.js b/src/utils/health.js deleted file mode 100644 index 6c0efd2..0000000 --- a/src/utils/health.js +++ /dev/null @@ -1,103 +0,0 @@ -const os = require('os'); -const process = require('process'); - -class HealthCheck { - constructor() { - this.startTime = Date.now(); - } - - getUptime() { - return Math.floor((Date.now() - this.startTime) / 1000); - } - - getMemoryUsage() { - const used = process.memoryUsage(); - return { - heapTotal: Math.round(used.heapTotal / 1024 / 1024), // MB - heapUsed: Math.round(used.heapUsed / 1024 / 1024), // MB - rss: Math.round(used.rss / 1024 / 1024), // MB - memoryUsage: Math.round((used.heapUsed / used.heapTotal) * 100) // % - }; - } - - getSystemInfo() { - return { - platform: process.platform, - arch: process.arch, - nodeVersion: process.version, - cpuUsage: Math.round(os.loadavg()[0] * 100) / 100, - totalMemory: Math.round(os.totalmem() / 1024 / 1024), // MB - freeMemory: Math.round(os.freemem() / 1024 / 1024) // MB - }; - } - - async checkTMDBConnection(tmdbClient) { - try { - const startTime = Date.now(); - await tmdbClient.makeRequest('GET', '/configuration'); - const endTime = Date.now(); - return { - status: 'ok', - responseTime: endTime - startTime - }; - } catch (error) { - return { - status: 'error', - error: error.message - }; - } - } - - formatUptime(seconds) { - const days = Math.floor(seconds / (24 * 60 * 60)); - const hours = Math.floor((seconds % (24 * 60 * 60)) / (60 * 60)); - const minutes = Math.floor((seconds % (60 * 60)) / 60); - const remainingSeconds = seconds % 60; - - const parts = []; - if (days > 0) parts.push(`${days}d`); - if (hours > 0) parts.push(`${hours}h`); - if (minutes > 0) parts.push(`${minutes}m`); - if (remainingSeconds > 0 || parts.length === 0) parts.push(`${remainingSeconds}s`); - - return parts.join(' '); - } - - async getFullHealth(tmdbClient) { - const uptime = this.getUptime(); - const tmdbStatus = await this.checkTMDBConnection(tmdbClient); - const memory = this.getMemoryUsage(); - const system = this.getSystemInfo(); - - return { - status: tmdbStatus.status === 'ok' ? 'healthy' : 'unhealthy', - version: process.env.npm_package_version || '1.0.0', - uptime: { - seconds: uptime, - formatted: this.formatUptime(uptime) - }, - tmdb: { - status: tmdbStatus.status, - responseTime: tmdbStatus.responseTime, - error: tmdbStatus.error - }, - memory: { - ...memory, - system: { - total: system.totalMemory, - free: system.freeMemory, - usage: Math.round(((system.totalMemory - system.freeMemory) / system.totalMemory) * 100) - } - }, - system: { - platform: system.platform, - arch: system.arch, - nodeVersion: system.nodeVersion, - cpuUsage: system.cpuUsage - }, - timestamp: new Date().toISOString() - }; - } -} - -module.exports = new HealthCheck(); diff --git a/vercel.json b/vercel.json deleted file mode 100644 index e6e16d3..0000000 --- a/vercel.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": 2, - "builds": [ - { - "src": "src/index.js", - "use": "@vercel/node" - } - ], - "routes": [ - { - "src": "/api-docs/(.*)", - "dest": "src/index.js" - }, - { - "src": "/(.*)", - "dest": "src/index.js" - } - ], - "env": { - "NODE_ENV": "production" - } -}