Files
neomovies-api/pkg/handlers/docs.go

1876 lines
65 KiB
Go
Raw Normal View History

2025-08-07 13:47:42 +00:00
package handlers
import (
"encoding/json"
"fmt"
"net/http"
2025-08-14 12:47:52 +00:00
"strings"
2025-08-07 13:47:42 +00:00
"github.com/MarceloPetrucio/go-scalar-api-reference"
)
2025-08-08 16:47:02 +00:00
type DocsHandler struct{}
2025-08-07 13:47:42 +00:00
func NewDocsHandler() *DocsHandler {
return &DocsHandler{}
}
func (h *DocsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.ServeDocs(w, r)
}
func (h *DocsHandler) RedirectToDocs(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/docs/", http.StatusMovedPermanently)
}
func (h *DocsHandler) GetOpenAPISpec(w http.ResponseWriter, r *http.Request) {
2025-08-14 13:19:19 +00:00
_ = determineBaseURL(r)
2025-08-07 13:47:42 +00:00
2025-08-14 13:19:19 +00:00
// Use relative server URL to inherit correct scheme/host from the browser/proxy
spec := getOpenAPISpecWithURL("/")
2025-08-07 13:47:42 +00:00
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
2025-08-14 11:34:31 +00:00
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Origin, X-Requested-With")
2025-08-07 13:47:42 +00:00
json.NewEncoder(w).Encode(spec)
}
func (h *DocsHandler) ServeDocs(w http.ResponseWriter, r *http.Request) {
2025-08-14 13:36:22 +00:00
baseURL := determineBaseURL(r)
2025-08-07 13:47:42 +00:00
htmlContent, err := scalar.ApiReferenceHTML(&scalar.Options{
2025-08-14 13:36:22 +00:00
SpecURL: fmt.Sprintf("%s/openapi.json", baseURL),
2025-08-07 13:47:42 +00:00
CustomOptions: scalar.CustomOptions{
PageTitle: "Neo Movies API Documentation",
},
DarkMode: true,
})
if err != nil {
fmt.Printf("Error generating documentation: %v", err)
http.Error(w, fmt.Sprintf("Error generating documentation: %v", err), http.StatusInternalServerError)
return
}
2025-08-14 11:34:31 +00:00
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
2025-08-07 13:47:42 +00:00
fmt.Fprintln(w, htmlContent)
}
2025-08-14 12:47:52 +00:00
func determineBaseURL(r *http.Request) string {
2025-08-14 13:19:19 +00:00
// Prefer proxy headers and request info over environment to avoid wrong scheme on platforms like Vercel
2025-08-14 12:47:52 +00:00
proto := ""
host := r.Host
if fwd := r.Header.Get("Forwarded"); fwd != "" {
for _, part := range strings.Split(fwd, ";") {
kv := strings.SplitN(strings.TrimSpace(part), "=", 2)
if len(kv) != 2 {
continue
}
key := strings.ToLower(strings.TrimSpace(kv[0]))
val := strings.Trim(strings.TrimSpace(kv[1]), "\"")
switch key {
case "proto":
if proto == "" {
proto = strings.ToLower(val)
}
case "host":
if val != "" {
host = val
}
}
}
}
if proto == "" {
if p := r.Header.Get("X-Forwarded-Proto"); p != "" {
proto = strings.ToLower(strings.TrimSpace(strings.Split(p, ",")[0]))
}
}
if xfh := r.Header.Get("X-Forwarded-Host"); xfh != "" {
host = strings.TrimSpace(strings.Split(xfh, ",")[0])
}
if proto == "" {
if r.TLS != nil {
proto = "https"
} else {
proto = "http"
}
}
if xfp := r.Header.Get("X-Forwarded-Port"); xfp != "" && !strings.Contains(host, ":") {
isDefault := (proto == "http" && xfp == "80") || (proto == "https" && xfp == "443")
if !isDefault {
host = host + ":" + xfp
}
}
return fmt.Sprintf("%s://%s", proto, host)
}
2025-08-07 13:47:42 +00:00
type OpenAPISpec struct {
OpenAPI string `json:"openapi"`
Info Info `json:"info"`
Servers []Server `json:"servers"`
Paths map[string]interface{} `json:"paths"`
Components Components `json:"components"`
2025-08-07 13:47:42 +00:00
}
type Info struct {
Title string `json:"title"`
Description string `json:"description"`
Version string `json:"version"`
Contact Contact `json:"contact"`
}
type Contact struct {
Name string `json:"name"`
URL string `json:"url"`
}
type Server struct {
URL string `json:"url"`
Description string `json:"description"`
}
type Components struct {
SecuritySchemes map[string]SecurityScheme `json:"securitySchemes"`
Schemas map[string]interface{} `json:"schemas"`
}
type SecurityScheme struct {
Type string `json:"type"`
Scheme string `json:"scheme,omitempty"`
BearerFormat string `json:"bearerFormat,omitempty"`
}
func getOpenAPISpecWithURL(baseURL string) *OpenAPISpec {
return &OpenAPISpec{
OpenAPI: "3.0.0",
Info: Info{
Title: "Neo Movies API",
Description: "Современный API для поиска фильмов и сериалов с интеграцией TMDB и поддержкой авторизации",
Version: "2.0.0",
Contact: Contact{
Name: "API Support",
2025-08-13 18:02:03 +00:00
URL: "https://github.com/your-username/neomovies-api-go",
2025-08-07 13:47:42 +00:00
},
},
Servers: []Server{
{
URL: baseURL,
Description: "Production server",
},
},
Paths: map[string]interface{}{
"/api/v1/health": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Health Check",
2025-08-07 13:47:42 +00:00
"description": "Проверка работоспособности API",
"tags": []string{"Health"},
2025-08-07 13:47:42 +00:00
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "API работает корректно",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/APIResponse",
},
},
},
},
},
},
},
2025-08-14 11:34:31 +00:00
"/api/v1/search/multi": map[string]interface{}{
2025-08-07 13:47:42 +00:00
"get": map[string]interface{}{
"summary": "Мультипоиск",
2025-08-07 13:47:42 +00:00
"description": "Поиск фильмов, сериалов и актеров",
"tags": []string{"Search"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "query",
"in": "query",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Поисковый запрос",
},
{
"name": "page",
"in": "query",
"schema": map[string]string{"type": "integer", "default": "1"},
2025-08-07 13:47:42 +00:00
"description": "Номер страницы",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Результаты поиска",
},
},
},
},
"/api/v1/categories": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Получить категории",
2025-08-07 13:47:42 +00:00
"description": "Получение списка категорий фильмов",
"tags": []string{"Categories"},
2025-08-07 13:47:42 +00:00
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список категорий",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "array",
2025-08-07 13:47:42 +00:00
"items": map[string]interface{}{"$ref": "#/components/schemas/Category"},
},
},
},
},
},
},
},
"/api/v1/categories/{id}/movies": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Фильмы по категории",
2025-08-07 13:47:42 +00:00
"description": "Получение фильмов по категории",
"tags": []string{"Categories"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID категории",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Фильмы категории",
},
},
},
},
2025-08-14 11:34:31 +00:00
"/api/v1/categories/{id}/media": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Медиа по категории",
2025-08-14 11:34:31 +00:00
"description": "Получение фильмов или сериалов по категории",
"tags": []string{"Categories"},
2025-08-14 11:34:31 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-14 11:34:31 +00:00
"description": "ID категории",
},
{
"name": "type",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "string",
"enum": []string{"movie", "tv"},
2025-08-14 11:34:31 +00:00
"default": "movie",
},
"description": "Тип медиа: movie или tv",
},
{
"name": "page",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "integer",
2025-08-14 11:34:31 +00:00
"default": 1,
},
"description": "Номер страницы",
},
{
"name": "language",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "string",
2025-08-14 11:34:31 +00:00
"default": "ru-RU",
},
"description": "Язык ответа",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Медиа по категории",
},
},
},
},
2025-08-07 13:47:42 +00:00
"/api/v1/players/alloha/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Плеер Alloha",
2025-08-07 13:47:42 +00:00
"description": "Получение плеера Alloha по IMDb ID",
"tags": []string{"Players"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "IMDb ID фильма",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Данные плеера",
},
},
},
},
"/api/v1/players/lumex/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Плеер Lumex",
"description": "Получение плеера Lumex по IMDb ID. Не поддерживает выбор сезона/серии - плеер работает напрямую с IMDb ID",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID фильма или сериала (например, tt0133093)",
2025-08-07 13:47:42 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML со встроенным Lumex плеером",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
2025-08-07 13:47:42 +00:00
},
},
},
},
},
"/api/v1/players/vibix/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vibix плеер по IMDb ID",
"description": "Возвращает HTML-страницу с iframe Vibix для указанного IMDb ID. Не поддерживает выбор сезона/серии - плеер работает напрямую с IMDb ID",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID, например tt0133093",
2025-08-11 18:36:02 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML со встроенным Vibix плеером",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
2025-08-11 18:36:02 +00:00
},
},
"404": map[string]interface{}{"description": "Фильм не найден"},
"503": map[string]interface{}{"description": "VIBIX_TOKEN не настроен"},
2025-08-11 18:36:02 +00:00
},
},
},
"/api/v1/players/vidsrc/{media_type}/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidsrc плеер (английский)",
"description": "Возвращает HTML-страницу с iframe Vidsrc.to. Использует IMDb ID для фильмов и сериалов. Пример URL для фильма: https://vidsrc.to/embed/movie/tt1234567, для сериала: https://vidsrc.to/embed/tv/tt6385540/1/1",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "media_type",
"in": "path",
"required": true,
"schema": map[string]interface{}{"type": "string", "enum": []string{"movie", "tv"}},
"description": "Тип контента: movie (фильм) или tv (сериал)",
},
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID, например tt6385540 (с префиксом tt)",
},
{
"name": "season",
"in": "query",
"required": false,
"schema": map[string]string{"type": "integer"},
"description": "Номер сезона (обязательно для TV)",
},
{
"name": "episode",
"in": "query",
"required": false,
"schema": map[string]string{"type": "integer"},
"description": "Номер серии (обязательно для TV)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML со встроенным Vidsrc плеером",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "Отсутствуют обязательные параметры"},
},
},
},
"/api/v1/players/vidlink/movie/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidlink плеер для фильмов (английский)",
"description": "Возвращает HTML-страницу с iframe Vidlink.pro для фильмов. Использует IMDb ID. Пример URL: https://vidlink.pro/movie/tt1234567",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID фильма, например tt1234567 (с префиксом tt)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML со встроенным Vidlink плеером",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "IMDb ID не указан"},
},
},
},
"/api/v1/players/vidlink/tv/{tmdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidlink плеер для сериалов (английский)",
"description": "Возвращает HTML-страницу с iframe Vidlink.pro для сериалов. Использует TMDB ID (без префикса tt). Пример URL: https://vidlink.pro/tv/94997/1/1",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "tmdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "TMDB ID сериала, например 94997 (числовой идентификатор без префикса)",
},
{
"name": "season",
"in": "query",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "Номер сезона (обязательно)",
},
{
"name": "episode",
"in": "query",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "Номер серии (обязательно)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML со встроенным Vidlink плеером",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "Отсутствуют обязательные параметры (tmdb_id, season, episode)"},
},
},
},
"/api/v1/players/vidsrc-parse/{media_type}/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidsrc плеер с парсингом (кастомный плеер)",
"description": "Возвращает HTML-страницу с кастомным Video.js плеером. Автоматически извлекает m3u8 ссылку из Vidsrc.to через клиентский парсинг в iframe. Использует IMDb ID для фильмов и сериалов.",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "media_type",
"in": "path",
"required": true,
"schema": map[string]interface{}{"type": "string", "enum": []string{"movie", "tv"}},
"description": "Тип контента: movie (фильм) или tv (сериал)",
},
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID, например tt6385540 (с префиксом tt)",
},
{
"name": "season",
"in": "query",
"required": false,
"schema": map[string]string{"type": "integer"},
"description": "Номер сезона (обязательно для TV)",
},
{
"name": "episode",
"in": "query",
"required": false,
"schema": map[string]string{"type": "integer"},
"description": "Номер серии (обязательно для TV)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML с кастомным Video.js плеером и системой парсинга",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "Отсутствуют обязательные параметры"},
},
},
},
"/api/v1/players/vidlink-parse/movie/{imdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidlink плеер с парсингом для фильмов (кастомный)",
"description": "Возвращает HTML-страницу с кастомным Video.js плеером. Автоматически извлекает m3u8/mp4 ссылку из Vidlink.pro через клиентский парсинг. Использует IMDb ID для фильмов.",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "imdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDb ID фильма, например tt1234567 (с префиксом tt)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML с кастомным Video.js плеером и системой парсинга",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "IMDb ID не указан"},
},
},
},
"/api/v1/players/vidlink-parse/tv/{tmdb_id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Vidlink плеер с парсингом для сериалов (кастомный)",
"description": "Возвращает HTML-страницу с кастомным Video.js плеером. Автоматически извлекает m3u8/mp4 ссылку из Vidlink.pro через клиентский парсинг. Использует TMDB ID для сериалов.",
"tags": []string{"Players"},
"parameters": []map[string]interface{}{
{
"name": "tmdb_id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "TMDB ID сериала, например 94997 (числовой идентификатор без префикса)",
},
{
"name": "season",
"in": "query",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "Номер сезона (обязательно)",
},
{
"name": "episode",
"in": "query",
"required": true,
"schema": map[string]string{"type": "integer"},
"description": "Номер серии (обязательно)",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "HTML с кастомным Video.js плеером и системой парсинга",
"content": map[string]interface{}{
"text/html": map[string]interface{}{},
},
},
"400": map[string]interface{}{"description": "Отсутствуют обязательные параметры (tmdb_id, season, episode)"},
},
},
},
2025-08-07 13:47:42 +00:00
"/api/v1/torrents/search/{imdbId}": map[string]interface{}{
"get": map[string]interface{}{
2025-08-07 18:25:43 +00:00
"summary": "Поиск торрентов",
2025-08-07 13:47:42 +00:00
"description": "Поиск торрентов по IMDB ID",
2025-08-07 18:25:43 +00:00
"tags": []string{"Torrents"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
2025-08-07 18:25:43 +00:00
"name": "imdbId",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
"description": "IMDB ID фильма или сериала",
},
{
"name": "type",
"in": "query",
"required": true,
"schema": map[string]interface{}{"type": "string", "enum": []string{"movie", "tv", "serial"}},
"description": "Тип контента: movie (фильм) или tv/serial (сериал)",
},
{
"name": "season",
"in": "query",
"required": false,
"schema": map[string]interface{}{"type": "integer"},
"description": "Номер сезона (для сериалов)",
2025-08-07 13:47:42 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Результаты поиска торрентов",
},
},
},
},
"/api/v1/reactions/{mediaType}/{mediaId}/counts": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Количество реакций",
2025-08-07 13:47:42 +00:00
"description": "Получение количества реакций для медиа",
"tags": []string{"Reactions"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "mediaType",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Тип медиа (movie/tv)",
},
{
"name": "mediaId",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "ID медиа",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Количество реакций",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/ReactionCounts",
},
},
},
},
},
},
},
"/api/v1/images/{size}/{path}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Изображения",
2025-08-07 13:47:42 +00:00
"description": "Прокси для изображений TMDB",
"tags": []string{"Images"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "size",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Размер изображения",
},
{
"name": "path",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Путь к изображению",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Изображение",
"content": map[string]interface{}{
"image/*": map[string]interface{}{},
},
},
},
},
},
"/api/v1/auth/register": map[string]interface{}{
"post": map[string]interface{}{
"summary": "Регистрация пользователя",
2025-08-07 13:47:42 +00:00
"description": "Создание нового аккаунта пользователя",
"tags": []string{"Authentication"},
2025-08-07 13:47:42 +00:00
"requestBody": map[string]interface{}{
"required": true,
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/RegisterRequest",
},
},
},
},
"responses": map[string]interface{}{
"201": map[string]interface{}{
"description": "Пользователь успешно зарегистрирован",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/AuthResponse",
},
},
},
},
"409": map[string]interface{}{
"description": "Пользователь с таким email уже существует",
},
},
},
},
"/api/v1/auth/verify": map[string]interface{}{
"post": map[string]interface{}{
"tags": []string{"Authentication"},
"summary": "Подтверждение email",
"description": "Подтверждение email пользователя с помощью кода",
"requestBody": map[string]interface{}{
"required": true,
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
2025-08-07 13:47:42 +00:00
"required": []string{"email", "code"},
"properties": map[string]interface{}{
"email": map[string]interface{}{
"type": "string",
"format": "email",
"description": "Email пользователя",
"example": "user@example.com",
},
"code": map[string]interface{}{
"type": "string",
"description": "6-значный код верификации",
"example": "123456",
},
},
},
},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Email успешно подтвержден",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"success": map[string]interface{}{
"type": "boolean",
},
"message": map[string]interface{}{
"type": "string",
},
},
},
},
},
},
"400": map[string]interface{}{
"description": "Неверный или истекший код",
},
},
},
},
"/api/v1/auth/resend-code": map[string]interface{}{
"post": map[string]interface{}{
"tags": []string{"Authentication"},
"summary": "Повторная отправка кода",
"description": "Повторная отправка кода верификации на email",
"requestBody": map[string]interface{}{
"required": true,
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
2025-08-07 13:47:42 +00:00
"required": []string{"email"},
"properties": map[string]interface{}{
"email": map[string]interface{}{
"type": "string",
"format": "email",
"description": "Email пользователя",
"example": "user@example.com",
},
},
},
},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Код отправлен на email",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"success": map[string]interface{}{
"type": "boolean",
},
"message": map[string]interface{}{
"type": "string",
},
},
},
},
},
},
"400": map[string]interface{}{
"description": "Email уже подтвержден или пользователь не найден",
},
},
},
},
"/api/v1/auth/login": map[string]interface{}{
"post": map[string]interface{}{
"summary": "Авторизация пользователя",
2025-08-07 13:47:42 +00:00
"description": "Получение JWT токена для доступа к приватным эндпоинтам",
"tags": []string{"Authentication"},
2025-08-07 13:47:42 +00:00
"requestBody": map[string]interface{}{
"required": true,
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/LoginRequest",
},
},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Успешная авторизация",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/AuthResponse",
},
},
},
},
"401": map[string]interface{}{
"description": "Неверный email или пароль",
},
},
},
},
"/api/v1/auth/profile": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Получить профиль пользователя",
2025-08-07 13:47:42 +00:00
"description": "Получение информации о текущем пользователе",
"tags": []string{"Authentication"},
2025-08-07 13:47:42 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Информация о пользователе",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/User",
},
},
},
},
},
},
"put": map[string]interface{}{
"summary": "Обновить профиль пользователя",
2025-08-07 13:47:42 +00:00
"description": "Обновление информации о пользователе",
"tags": []string{"Authentication"},
2025-08-07 13:47:42 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Профиль успешно обновлен",
},
},
},
2025-08-11 18:36:02 +00:00
"delete": map[string]interface{}{
"summary": "Удалить аккаунт пользователя",
2025-08-07 18:25:43 +00:00
"description": "Полное и безвозвратное удаление аккаунта пользователя и всех связанных с ним данных (избранное, реакции)",
"tags": []string{"Authentication"},
2025-08-07 18:25:43 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Аккаунт успешно удален",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"success": map[string]interface{}{"type": "boolean"},
"message": map[string]interface{}{"type": "string"},
},
},
},
},
},
"401": map[string]interface{}{
"description": "Неавторизованный запрос",
},
"500": map[string]interface{}{
"description": "Внутренняя ошибка сервера",
},
},
},
2025-08-07 13:47:42 +00:00
},
"/api/v1/movies/search": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Поиск фильмов",
2025-08-07 13:47:42 +00:00
"description": "Поиск фильмов по названию с поддержкой фильтров",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "query",
"in": "query",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Поисковый запрос",
},
{
"name": "page",
"in": "query",
"schema": map[string]string{"type": "integer", "default": "1"},
2025-08-07 13:47:42 +00:00
"description": "Номер страницы",
},
{
"name": "language",
"in": "query",
"schema": map[string]string{"type": "string", "default": "ru-RU"},
2025-08-07 13:47:42 +00:00
"description": "Язык ответа",
},
{
"name": "year",
"in": "query",
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "Год выпуска",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Результаты поиска фильмов",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/MovieSearchResponse",
},
},
},
},
},
},
},
"/api/v1/movies/popular": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Популярные фильмы",
2025-08-07 13:47:42 +00:00
"description": "Получение списка популярных фильмов",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список популярных фильмов",
},
},
},
},
"/api/v1/movies/{id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Получить фильм по ID",
2025-08-07 13:47:42 +00:00
"description": "Подробная информация о фильме",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID фильма в TMDB",
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Информация о фильме",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/Movie",
},
},
},
},
},
},
},
"/api/v1/favorites": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Получить избранное",
2025-08-14 11:34:31 +00:00
"description": "Список избранных фильмов и сериалов пользователя",
"tags": []string{"Favorites"},
2025-08-07 13:47:42 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
2025-08-14 11:34:31 +00:00
"description": "Список избранного",
2025-08-07 13:47:42 +00:00
},
},
},
},
"/api/v1/favorites/{id}": map[string]interface{}{
"post": map[string]interface{}{
"summary": "Добавить в избранное",
2025-08-14 11:34:31 +00:00
"description": "Добавление фильма или сериала в избранное",
"tags": []string{"Favorites"},
2025-08-07 13:47:42 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
"description": "ID медиа",
},
{
"name": "type",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "string",
"enum": []string{"movie", "tv"},
2025-08-14 11:34:31 +00:00
"default": "movie",
},
"description": "Тип медиа: movie или tv",
2025-08-07 13:47:42 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
2025-08-14 11:34:31 +00:00
"description": "Добавлено в избранное",
2025-08-07 13:47:42 +00:00
},
},
},
"delete": map[string]interface{}{
"summary": "Удалить из избранного",
2025-08-14 11:34:31 +00:00
"description": "Удаление фильма или сериала из избранного",
"tags": []string{"Favorites"},
2025-08-14 11:34:31 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
"description": "ID медиа",
},
{
"name": "type",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "string",
"enum": []string{"movie", "tv"},
2025-08-14 11:34:31 +00:00
"default": "movie",
},
"description": "Тип медиа: movie или tv",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Удалено из избранного",
},
},
},
},
"/api/v1/favorites/{id}/check": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Проверить избранное",
2025-08-14 11:34:31 +00:00
"description": "Проверка, находится ли медиа в избранном",
"tags": []string{"Favorites"},
2025-08-07 13:47:42 +00:00
"security": []map[string][]string{
{"bearerAuth": []string{}},
},
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
"description": "ID медиа",
},
{
"name": "type",
"in": "query",
2025-08-14 11:34:31 +00:00
"required": false,
"schema": map[string]interface{}{
"type": "string",
"enum": []string{"movie", "tv"},
2025-08-14 11:34:31 +00:00
"default": "movie",
},
"description": "Тип медиа: movie или tv",
2025-08-07 13:47:42 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
2025-08-14 11:34:31 +00:00
"description": "Статус избранного",
2025-08-07 13:47:42 +00:00
},
},
},
},
"/api/v1/movies/top-rated": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Топ рейтинг фильмов",
2025-08-07 13:47:42 +00:00
"description": "Получение списка фильмов с высоким рейтингом",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список фильмов с высоким рейтингом",
},
},
},
},
"/api/v1/movies/upcoming": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Скоро в прокате",
2025-08-07 13:47:42 +00:00
"description": "Получение списка фильмов, которые скоро выйдут в прокат",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список фильмов, которые скоро выйдут",
},
},
},
},
"/api/v1/movies/now-playing": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Сейчас в прокате",
2025-08-07 13:47:42 +00:00
"description": "Получение списка фильмов, которые сейчас в прокате",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список фильмов в прокате",
},
},
},
},
"/api/v1/movies/{id}/recommendations": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Рекомендации фильмов",
2025-08-07 13:47:42 +00:00
"description": "Получение рекомендаций фильмов на основе выбранного",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID фильма в TMDB",
},
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Рекомендуемые фильмы",
},
},
},
},
"/api/v1/movies/{id}/similar": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Похожие фильмы",
2025-08-07 13:47:42 +00:00
"description": "Получение похожих фильмов",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID фильма в TMDB",
},
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Похожие фильмы",
},
},
},
},
"/api/v1/tv/search": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Поиск сериалов",
2025-08-07 13:47:42 +00:00
"description": "Поиск сериалов по названию",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "query",
"in": "query",
"required": true,
"schema": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": "Поисковый запрос",
},
{
"name": "page",
"in": "query",
"schema": map[string]string{"type": "integer", "default": "1"},
2025-08-07 18:25:43 +00:00
"description": "Номер страницы",
2025-08-07 13:47:42 +00:00
},
{
"name": "language",
"in": "query",
"schema": map[string]string{"type": "string", "default": "ru-RU"},
2025-08-07 18:25:43 +00:00
"description": "Язык ответа",
2025-08-07 13:47:42 +00:00
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Результаты поиска сериалов",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/TVSearchResponse",
},
},
},
},
},
},
},
"/api/v1/tv/popular": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Популярные сериалы",
2025-08-07 13:47:42 +00:00
"description": "Получение списка популярных сериалов",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список популярных сериалов",
},
},
},
},
"/api/v1/tv/top-rated": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Топ рейтинг сериалов",
2025-08-07 13:47:42 +00:00
"description": "Получение списка сериалов с высоким рейтингом",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список сериалов с высоким рейтингом",
},
},
},
},
"/api/v1/tv/on-the-air": map[string]interface{}{
"get": map[string]interface{}{
"summary": "В эфире",
2025-08-07 13:47:42 +00:00
"description": "Получение списка сериалов, которые сейчас в эфире",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список сериалов в эфире",
},
},
},
},
"/api/v1/tv/airing-today": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Сегодня в эфире",
2025-08-07 13:47:42 +00:00
"description": "Получение списка сериалов, которые выходят сегодня",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Список сериалов, выходящих сегодня",
},
},
},
},
"/api/v1/tv/{id}": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Получить сериал по ID",
2025-08-07 13:47:42 +00:00
"description": "Подробная информация о сериале",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID сериала в TMDB",
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Информация о сериале",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/TVSeries",
},
},
},
},
},
},
},
"/api/v1/tv/{id}/recommendations": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Рекомендации сериалов",
2025-08-07 13:47:42 +00:00
"description": "Получение рекомендаций сериалов на основе выбранного",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID сериала в TMDB",
},
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Рекомендуемые сериалы",
},
},
},
},
"/api/v1/tv/{id}/similar": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Похожие сериалы",
2025-08-07 13:47:42 +00:00
"description": "Получение похожих сериалов",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID сериала в TMDB",
},
{
"name": "page",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "integer", "default": "1"},
},
{
"name": "language",
"in": "query",
2025-08-07 13:47:42 +00:00
"schema": map[string]string{"type": "string", "default": "ru-RU"},
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Похожие сериалы",
},
},
},
},
"/api/v1/movies/{id}/external-ids": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Внешние идентификаторы фильма",
2025-08-07 13:47:42 +00:00
"description": "Получить внешние ID (IMDb, TVDB, Facebook и др.) для фильма по TMDB ID",
"tags": []string{"Movies"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID фильма в TMDB",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Внешние идентификаторы фильма",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/ExternalIDs",
},
},
},
},
},
},
},
"/api/v1/tv/{id}/external-ids": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Внешние идентификаторы сериала",
2025-08-07 13:47:42 +00:00
"description": "Получить внешние ID (IMDb, TVDB, Facebook и др.) для сериала по TMDB ID",
"tags": []string{"TV Series"},
2025-08-07 13:47:42 +00:00
"parameters": []map[string]interface{}{
{
"name": "id",
"in": "path",
"required": true,
"schema": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"description": "ID сериала в TMDB",
},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Внешние идентификаторы сериала",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{
"$ref": "#/components/schemas/ExternalIDs",
},
},
},
},
},
},
},
2025-08-08 16:47:02 +00:00
"/api/v1/auth/google/login": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Google OAuth: начало",
2025-08-08 16:47:02 +00:00
"description": "Редирект на страницу авторизации Google",
"tags": []string{"Authentication"},
2025-08-08 16:47:02 +00:00
"responses": map[string]interface{}{
"302": map[string]interface{}{"description": "Redirect to Google"},
"400": map[string]interface{}{"description": "OAuth не сконфигурирован"},
},
},
},
"/api/v1/auth/google/callback": map[string]interface{}{
"get": map[string]interface{}{
"summary": "Google OAuth: коллбек",
2025-08-08 16:47:02 +00:00
"description": "Обработка кода авторизации и выдача JWT",
"tags": []string{"Authentication"},
2025-08-08 16:47:02 +00:00
"parameters": []map[string]interface{}{
{"name": "state", "in": "query", "required": true, "schema": map[string]string{"type": "string"}},
{"name": "code", "in": "query", "required": true, "schema": map[string]string{"type": "string"}},
},
"responses": map[string]interface{}{
"200": map[string]interface{}{
"description": "Успешная авторизация через Google",
"content": map[string]interface{}{
"application/json": map[string]interface{}{
"schema": map[string]interface{}{"$ref": "#/components/schemas/AuthResponse"},
},
},
},
"400": map[string]interface{}{"description": "Неверный state или ошибка обмена кода"},
},
},
},
2025-08-07 13:47:42 +00:00
},
Components: Components{
SecuritySchemes: map[string]SecurityScheme{
"bearerAuth": {
Type: "http",
Scheme: "bearer",
BearerFormat: "JWT",
},
},
Schemas: map[string]interface{}{
"APIResponse": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"success": map[string]string{"type": "boolean"},
"data": map[string]string{"type": "object"},
2025-08-07 13:47:42 +00:00
"message": map[string]string{"type": "string"},
"error": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
},
},
"RegisterRequest": map[string]interface{}{
"type": "object",
2025-08-07 13:47:42 +00:00
"required": []string{"email", "password", "name"},
"properties": map[string]interface{}{
"email": map[string]interface{}{
"type": "string",
"format": "email",
2025-08-07 13:47:42 +00:00
"example": "user@example.com",
},
"password": map[string]interface{}{
"type": "string",
2025-08-07 13:47:42 +00:00
"minLength": 6,
"example": "password123",
2025-08-07 13:47:42 +00:00
},
"name": map[string]interface{}{
"type": "string",
2025-08-07 13:47:42 +00:00
"example": "Иван Иванов",
},
},
},
"LoginRequest": map[string]interface{}{
"type": "object",
2025-08-07 13:47:42 +00:00
"required": []string{"email", "password"},
"properties": map[string]interface{}{
"email": map[string]interface{}{
"type": "string",
"format": "email",
2025-08-07 13:47:42 +00:00
"example": "user@example.com",
},
"password": map[string]interface{}{
"type": "string",
2025-08-07 13:47:42 +00:00
"example": "password123",
},
},
},
"AuthResponse": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"token": map[string]string{"type": "string"},
"user": map[string]interface{}{"$ref": "#/components/schemas/User"},
2025-08-07 13:47:42 +00:00
},
},
"User": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "string"},
"email": map[string]string{"type": "string"},
"name": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"avatar": map[string]string{"type": "string"},
"favorites": map[string]interface{}{
"type": "array",
2025-08-07 13:47:42 +00:00
"items": map[string]string{"type": "string"},
},
"created_at": map[string]interface{}{
"type": "string",
2025-08-07 13:47:42 +00:00
"format": "date-time",
},
"updated_at": map[string]interface{}{
"type": "string",
2025-08-07 13:47:42 +00:00
"format": "date-time",
},
},
},
"Movie": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
"title": map[string]string{"type": "string"},
"original_title": map[string]string{"type": "string"},
"overview": map[string]string{"type": "string"},
"poster_path": map[string]string{"type": "string"},
"backdrop_path": map[string]string{"type": "string"},
"release_date": map[string]string{"type": "string"},
"vote_average": map[string]string{"type": "number"},
"vote_count": map[string]string{"type": "integer"},
"popularity": map[string]string{"type": "number"},
"adult": map[string]string{"type": "boolean"},
2025-08-07 13:47:42 +00:00
"original_language": map[string]string{"type": "string"},
},
},
"MovieSearchResponse": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"page": map[string]string{"type": "integer"},
"results": map[string]interface{}{
"type": "array",
2025-08-07 13:47:42 +00:00
"items": map[string]interface{}{"$ref": "#/components/schemas/Movie"},
},
"total_pages": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"total_results": map[string]string{"type": "integer"},
},
},
"TVSeries": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
"name": map[string]string{"type": "string"},
"original_name": map[string]string{"type": "string"},
"overview": map[string]string{"type": "string"},
"poster_path": map[string]string{"type": "string"},
"backdrop_path": map[string]string{"type": "string"},
"first_air_date": map[string]string{"type": "string"},
"vote_average": map[string]string{"type": "number"},
"vote_count": map[string]string{"type": "integer"},
"popularity": map[string]string{"type": "number"},
"original_language": map[string]string{"type": "string"},
"number_of_seasons": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"number_of_episodes": map[string]string{"type": "integer"},
"status": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
},
},
"TVSearchResponse": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"page": map[string]string{"type": "integer"},
"results": map[string]interface{}{
"type": "array",
2025-08-07 13:47:42 +00:00
"items": map[string]interface{}{"$ref": "#/components/schemas/TVSeries"},
},
"total_pages": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"total_results": map[string]string{"type": "integer"},
},
},
"Category": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
"name": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"description": map[string]string{"type": "string"},
},
},
"Player": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"url": map[string]string{"type": "string"},
"title": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"quality": map[string]string{"type": "string"},
"type": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
},
},
"Torrent": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"title": map[string]string{"type": "string"},
"size": map[string]string{"type": "string"},
"seeds": map[string]string{"type": "integer"},
"peers": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"magnet": map[string]string{"type": "string"},
"hash": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
},
},
"Reaction": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"type": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"count": map[string]string{"type": "integer"},
},
},
"ReactionCounts": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"like": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
"dislike": map[string]string{"type": "integer"},
"love": map[string]string{"type": "integer"},
2025-08-07 13:47:42 +00:00
},
},
"ExternalIDs": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
"imdb_id": map[string]string{"type": "string"},
"tvdb_id": map[string]string{"type": "integer"},
"wikidata_id": map[string]string{"type": "string"},
"facebook_id": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
"instagram_id": map[string]string{"type": "string"},
"twitter_id": map[string]string{"type": "string"},
2025-08-07 13:47:42 +00:00
},
},
2025-08-14 11:34:31 +00:00
"WebTorrentMetadata": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
2025-08-14 11:34:31 +00:00
"title": map[string]string{"type": "string"},
"type": map[string]interface{}{
"type": "string",
"enum": []string{"movie", "tv"},
},
"year": map[string]string{"type": "integer"},
"posterPath": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
"backdropPath": map[string]string{"type": "string"},
"overview": map[string]string{"type": "string"},
"runtime": map[string]string{"type": "integer"},
2025-08-14 11:34:31 +00:00
"genres": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"$ref": "#/components/schemas/Genre",
},
},
"seasons": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"$ref": "#/components/schemas/SeasonMetadata",
},
},
"episodes": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"$ref": "#/components/schemas/EpisodeMetadata",
},
},
},
},
"SeasonMetadata": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"seasonNumber": map[string]string{"type": "integer"},
"name": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
"episodes": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"$ref": "#/components/schemas/EpisodeMetadata",
},
},
},
},
"EpisodeMetadata": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"episodeNumber": map[string]string{"type": "integer"},
"seasonNumber": map[string]string{"type": "integer"},
"name": map[string]string{"type": "string"},
"overview": map[string]string{"type": "string"},
"runtime": map[string]string{"type": "integer"},
"stillPath": map[string]string{"type": "string"},
2025-08-14 11:34:31 +00:00
},
},
"Genre": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]string{"type": "integer"},
2025-08-14 11:34:31 +00:00
"name": map[string]string{"type": "string"},
},
},
2025-08-07 13:47:42 +00:00
},
},
}
2025-08-07 18:25:43 +00:00
}