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
This commit is contained in:
Cursor Agent
2025-10-04 19:52:39 +00:00
parent 39eea67323
commit d29dce0afc
4 changed files with 164 additions and 35 deletions

View File

@@ -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")

View File

@@ -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")

View File

@@ -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{}{

View File

@@ -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(`<iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe>`, playerURL)
htmlDoc := fmt.Sprintf(`<!DOCTYPE html><html><head><meta charset='utf-8'/><title>Vidlink Player</title><style>html,body{margin:0;height:100%%;}</style></head><body>%s</body></html>`, 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(`<iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe>`, playerURL)
htmlDoc := fmt.Sprintf(`<!DOCTYPE html><html><head><meta charset='utf-8'/><title>Vidlink Player</title><style>html,body{margin:0;height:100%%;}</style></head><body>%s</body></html>`, 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)
}