From 1872222346541e76fa8dbf1e1c14e80d0004966a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 4 Oct 2025 19:52:39 +0000 Subject: [PATCH] fix: correct player routes and IDs, add API documentation - Vidsrc: uses IMDb ID for both movies and TV shows - Vidlink: uses IMDb ID for movies, TMDB ID for TV shows - Updated routes: /players/vidsrc/{media_type}/{imdb_id} - Updated routes: /players/vidlink/movie/{imdb_id} - New route: /players/vidlink/tv/{tmdb_id} - Added comprehensive OpenAPI documentation for new players --- api/index.go | 5 +- main.go | 5 +- pkg/handlers/docs.go | 110 ++++++++++++++++++++++++++++++++++++++++ pkg/handlers/players.go | 79 ++++++++++++++++++----------- 4 files changed, 164 insertions(+), 35 deletions(-) diff --git a/api/index.go b/api/index.go index 14a3d0f..fa71980 100644 --- a/api/index.go +++ b/api/index.go @@ -97,8 +97,9 @@ func Handler(w http.ResponseWriter, r *http.Request) { api.HandleFunc("/players/alloha/{imdb_id}", playersHandler.GetAllohaPlayer).Methods("GET") api.HandleFunc("/players/lumex/{imdb_id}", playersHandler.GetLumexPlayer).Methods("GET") api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") - api.HandleFunc("/players/vidsrc/{media_type}/{id}", playersHandler.GetVidsrcPlayer).Methods("GET") - api.HandleFunc("/players/vidlink/{media_type}/{id}", playersHandler.GetVidlinkPlayer).Methods("GET") + api.HandleFunc("/players/vidsrc/{media_type}/{imdb_id}", playersHandler.GetVidsrcPlayer).Methods("GET") + api.HandleFunc("/players/vidlink/movie/{imdb_id}", playersHandler.GetVidlinkMoviePlayer).Methods("GET") + api.HandleFunc("/players/vidlink/tv/{tmdb_id}", playersHandler.GetVidlinkTVPlayer).Methods("GET") api.HandleFunc("/players/rgshows/{tmdb_id}", playersHandler.GetRgShowsPlayer).Methods("GET") api.HandleFunc("/players/rgshows/{tmdb_id}/{season}/{episode}", playersHandler.GetRgShowsTVPlayer).Methods("GET") api.HandleFunc("/players/iframevideo/{kinopoisk_id}/{imdb_id}", playersHandler.GetIframeVideoPlayer).Methods("GET") diff --git a/main.go b/main.go index ee3705b..dec7ab7 100644 --- a/main.go +++ b/main.go @@ -78,8 +78,9 @@ func main() { api.HandleFunc("/players/alloha/{imdb_id}", playersHandler.GetAllohaPlayer).Methods("GET") api.HandleFunc("/players/lumex/{imdb_id}", playersHandler.GetLumexPlayer).Methods("GET") api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") - api.HandleFunc("/players/vidsrc/{media_type}/{id}", playersHandler.GetVidsrcPlayer).Methods("GET") - api.HandleFunc("/players/vidlink/{media_type}/{id}", playersHandler.GetVidlinkPlayer).Methods("GET") + api.HandleFunc("/players/vidsrc/{media_type}/{imdb_id}", playersHandler.GetVidsrcPlayer).Methods("GET") + api.HandleFunc("/players/vidlink/movie/{imdb_id}", playersHandler.GetVidlinkMoviePlayer).Methods("GET") + api.HandleFunc("/players/vidlink/tv/{tmdb_id}", playersHandler.GetVidlinkTVPlayer).Methods("GET") api.HandleFunc("/torrents/search/{imdbId}", torrentsHandler.SearchTorrents).Methods("GET") api.HandleFunc("/torrents/movies", torrentsHandler.SearchMovies).Methods("GET") diff --git a/pkg/handlers/docs.go b/pkg/handlers/docs.go index 7440125..0d84450 100644 --- a/pkg/handlers/docs.go +++ b/pkg/handlers/docs.go @@ -374,6 +374,116 @@ func getOpenAPISpecWithURL(baseURL string) *OpenAPISpec { }, }, }, + "/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/torrents/search/{imdbId}": map[string]interface{}{ diff --git a/pkg/handlers/players.go b/pkg/handlers/players.go index fa635ea..8a3902b 100644 --- a/pkg/handlers/players.go +++ b/pkg/handlers/players.go @@ -436,22 +436,22 @@ func (h *PlayersHandler) GetStreamAPI(w http.ResponseWriter, r *http.Request) { log.Printf("Successfully served stream API for provider: %s, tmdb_id: %s", provider, tmdbID) } -// GetVidsrcPlayer handles Vidsrc.to player +// GetVidsrcPlayer handles Vidsrc.to player (uses IMDb ID for both movies and TV shows) func (h *PlayersHandler) GetVidsrcPlayer(w http.ResponseWriter, r *http.Request) { log.Printf("GetVidsrcPlayer called: %s %s", r.Method, r.URL.Path) vars := mux.Vars(r) - id := vars["id"] + imdbId := vars["imdb_id"] mediaType := vars["media_type"] // "movie" or "tv" - if id == "" || mediaType == "" { - http.Error(w, "id and media_type are required", http.StatusBadRequest) + if imdbId == "" || mediaType == "" { + http.Error(w, "imdb_id and media_type are required", http.StatusBadRequest) return } var playerURL string if mediaType == "movie" { - playerURL = fmt.Sprintf("https://vidsrc.to/embed/movie/%s", id) + playerURL = fmt.Sprintf("https://vidsrc.to/embed/movie/%s", imdbId) } else if mediaType == "tv" { season := r.URL.Query().Get("season") episode := r.URL.Query().Get("episode") @@ -459,7 +459,7 @@ func (h *PlayersHandler) GetVidsrcPlayer(w http.ResponseWriter, r *http.Request) http.Error(w, "season and episode are required for TV shows", http.StatusBadRequest) return } - playerURL = fmt.Sprintf("https://vidsrc.to/embed/tv/%s/%s/%s", id, season, episode) + playerURL = fmt.Sprintf("https://vidsrc.to/embed/tv/%s/%s/%s", imdbId, season, episode) } else { http.Error(w, "Invalid media_type. Use 'movie' or 'tv'", http.StatusBadRequest) return @@ -473,39 +473,24 @@ func (h *PlayersHandler) GetVidsrcPlayer(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "text/html") w.Write([]byte(htmlDoc)) - log.Printf("Successfully served Vidsrc player for %s: %s", mediaType, id) + log.Printf("Successfully served Vidsrc player for %s: %s", mediaType, imdbId) } -// GetVidlinkPlayer handles vidlink.pro player -func (h *PlayersHandler) GetVidlinkPlayer(w http.ResponseWriter, r *http.Request) { - log.Printf("GetVidlinkPlayer called: %s %s", r.Method, r.URL.Path) +// GetVidlinkMoviePlayer handles vidlink.pro player for movies (uses IMDb ID) +func (h *PlayersHandler) GetVidlinkMoviePlayer(w http.ResponseWriter, r *http.Request) { + log.Printf("GetVidlinkMoviePlayer called: %s %s", r.Method, r.URL.Path) vars := mux.Vars(r) - id := vars["id"] - mediaType := vars["media_type"] // "movie" or "tv" + imdbId := vars["imdb_id"] - if id == "" || mediaType == "" { - http.Error(w, "id and media_type are required", http.StatusBadRequest) + if imdbId == "" { + http.Error(w, "imdb_id is required", http.StatusBadRequest) return } - var playerURL string - if mediaType == "movie" { - playerURL = fmt.Sprintf("https://vidlink.pro/movie/%s", id) - } else if mediaType == "tv" { - season := r.URL.Query().Get("season") - episode := r.URL.Query().Get("episode") - if season == "" || episode == "" { - http.Error(w, "season and episode are required for TV shows", http.StatusBadRequest) - return - } - playerURL = fmt.Sprintf("https://vidlink.pro/tv/%s/%s/%s", id, season, episode) - } else { - http.Error(w, "Invalid media_type. Use 'movie' or 'tv'", http.StatusBadRequest) - return - } + playerURL := fmt.Sprintf("https://vidlink.pro/movie/%s", imdbId) - log.Printf("Generated Vidlink URL: %s", playerURL) + log.Printf("Generated Vidlink Movie URL: %s", playerURL) iframe := fmt.Sprintf(``, playerURL) htmlDoc := fmt.Sprintf(`Vidlink Player%s`, iframe) @@ -513,5 +498,37 @@ func (h *PlayersHandler) GetVidlinkPlayer(w http.ResponseWriter, r *http.Request w.Header().Set("Content-Type", "text/html") w.Write([]byte(htmlDoc)) - log.Printf("Successfully served Vidlink player for %s: %s", mediaType, id) + log.Printf("Successfully served Vidlink movie player: %s", imdbId) +} + +// GetVidlinkTVPlayer handles vidlink.pro player for TV shows (uses TMDB ID) +func (h *PlayersHandler) GetVidlinkTVPlayer(w http.ResponseWriter, r *http.Request) { + log.Printf("GetVidlinkTVPlayer called: %s %s", r.Method, r.URL.Path) + + vars := mux.Vars(r) + tmdbId := vars["tmdb_id"] + + if tmdbId == "" { + http.Error(w, "tmdb_id is required", http.StatusBadRequest) + return + } + + season := r.URL.Query().Get("season") + episode := r.URL.Query().Get("episode") + if season == "" || episode == "" { + http.Error(w, "season and episode are required for TV shows", http.StatusBadRequest) + return + } + + playerURL := fmt.Sprintf("https://vidlink.pro/tv/%s/%s/%s", tmdbId, season, episode) + + log.Printf("Generated Vidlink TV URL: %s", playerURL) + + iframe := fmt.Sprintf(``, playerURL) + htmlDoc := fmt.Sprintf(`Vidlink Player%s`, iframe) + + w.Header().Set("Content-Type", "text/html") + w.Write([]byte(htmlDoc)) + + log.Printf("Successfully served Vidlink TV player: %s S%sE%s", tmdbId, season, episode) }