2025-08-07 13:47:42 +00:00
package handlers
import (
"encoding/json"
"fmt"
2025-08-13 18:02:03 +00:00
"io"
"log"
2025-08-07 13:47:42 +00:00
"net/http"
2025-08-13 18:02:03 +00:00
"net/url"
2025-09-28 16:11:09 +00:00
"strconv"
2025-08-13 18:02:03 +00:00
"strings"
2025-08-11 18:36:02 +00:00
"time"
2025-08-07 13:47:42 +00:00
2025-08-13 18:02:03 +00:00
"github.com/gorilla/mux"
2025-09-28 11:46:20 +00:00
"neomovies-api/pkg/config"
2025-09-28 16:11:09 +00:00
"neomovies-api/pkg/players"
2025-08-07 13:47:42 +00:00
)
type PlayersHandler struct {
2025-08-13 18:02:03 +00:00
config * config . Config
2025-08-07 13:47:42 +00:00
}
func NewPlayersHandler ( cfg * config . Config ) * PlayersHandler {
2025-08-13 18:02:03 +00:00
return & PlayersHandler {
config : cfg ,
}
2025-08-07 13:47:42 +00:00
}
func ( h * PlayersHandler ) GetAllohaPlayer ( w http . ResponseWriter , r * http . Request ) {
2025-08-13 18:02:03 +00:00
log . Printf ( "GetAllohaPlayer called: %s %s" , r . Method , r . URL . Path )
2025-09-28 11:46:20 +00:00
2025-08-07 13:47:42 +00:00
vars := mux . Vars ( r )
2025-08-13 18:02:03 +00:00
log . Printf ( "Route vars: %+v" , vars )
2025-09-28 11:46:20 +00:00
2025-08-07 13:47:42 +00:00
imdbID := vars [ "imdb_id" ]
if imdbID == "" {
2025-08-13 18:02:03 +00:00
log . Printf ( "Error: imdb_id is empty" )
http . Error ( w , "imdb_id path param is required" , http . StatusBadRequest )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Processing imdb_id: %s" , imdbID )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if h . config . AllohaToken == "" {
log . Printf ( "Error: ALLOHA_TOKEN is missing" )
http . Error ( w , "Server misconfiguration: ALLOHA_TOKEN missing" , http . StatusInternalServerError )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
idParam := fmt . Sprintf ( "imdb=%s" , url . QueryEscape ( imdbID ) )
apiURL := fmt . Sprintf ( "https://api.alloha.tv/?token=%s&%s" , h . config . AllohaToken , idParam )
log . Printf ( "Calling Alloha API: %s" , apiURL )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
resp , err := http . Get ( apiURL )
if err != nil {
log . Printf ( "Error calling Alloha API: %v" , err )
http . Error ( w , "Failed to fetch from Alloha API" , http . StatusInternalServerError )
return
}
defer resp . Body . Close ( )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Alloha API response status: %d" , resp . StatusCode )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if resp . StatusCode != http . StatusOK {
http . Error ( w , fmt . Sprintf ( "Alloha API error: %d" , resp . StatusCode ) , http . StatusBadGateway )
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
body , err := io . ReadAll ( resp . Body )
if err != nil {
log . Printf ( "Error reading Alloha response: %v" , err )
http . Error ( w , "Failed to read Alloha response" , http . StatusInternalServerError )
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Alloha API response body: %s" , string ( body ) )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
var allohaResponse struct {
Status string ` json:"status" `
2025-09-28 11:46:20 +00:00
Data struct {
2025-10-04 21:12:29 +00:00
Iframe string ` json:"iframe" `
2025-08-13 18:02:03 +00:00
} ` json:"data" `
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if err := json . Unmarshal ( body , & allohaResponse ) ; err != nil {
log . Printf ( "Error unmarshaling JSON: %v" , err )
http . Error ( w , "Invalid JSON from Alloha" , http . StatusBadGateway )
return
}
2025-09-28 11:46:20 +00:00
2025-10-04 21:12:29 +00:00
if allohaResponse . Status != "success" || allohaResponse . Data . Iframe == "" {
log . Printf ( "Video not found or empty iframe" )
2025-08-13 18:02:03 +00:00
http . Error ( w , "Video not found" , http . StatusNotFound )
return
}
2025-09-28 11:46:20 +00:00
2025-10-04 20:56:19 +00:00
// Получаем параметры для сериалов
season := r . URL . Query ( ) . Get ( "season" )
episode := r . URL . Query ( ) . Get ( "episode" )
translation := r . URL . Query ( ) . Get ( "translation" )
if translation == "" {
translation = "66" // дефолтная озвучка
2025-08-13 18:02:03 +00:00
}
2025-09-28 11:46:20 +00:00
2025-10-04 21:12:29 +00:00
// Используем iframe URL из API
iframeCode := allohaResponse . Data . Iframe
// Если это не HTML код, а просто URL
2025-10-04 20:56:19 +00:00
var playerURL string
2025-10-04 21:12:29 +00:00
if ! strings . Contains ( iframeCode , "<" ) {
playerURL = iframeCode
// Добавляем параметры для сериалов
2025-10-04 20:56:19 +00:00
if season != "" && episode != "" {
2025-10-04 21:12:29 +00:00
separator := "?"
if strings . Contains ( playerURL , "?" ) {
separator = "&"
}
playerURL = fmt . Sprintf ( "%s%sseason=%s&episode=%s&translation=%s" , playerURL , separator , season , episode , translation )
2025-10-04 20:56:19 +00:00
}
2025-10-04 21:12:29 +00:00
iframeCode = fmt . Sprintf ( ` <iframe src="%s" allowfullscreen style="border:none;width:100%%;height:100%%"></iframe> ` , playerURL )
2025-10-04 20:56:19 +00:00
}
2025-10-04 21:12:29 +00:00
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>Alloha Player</title><style>html,body { margin:0;height:100%%;}</style></head><body>%s</body></html> ` , iframeCode )
2025-09-28 11:46:20 +00:00
2025-10-04 21:12:29 +00:00
// Авто-исправление экранированных кавычек
htmlDoc = strings . ReplaceAll ( htmlDoc , ` \" ` , ` " ` )
htmlDoc = strings . ReplaceAll ( htmlDoc , ` \' ` , ` ' ` )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
w . Header ( ) . Set ( "Content-Type" , "text/html" )
w . Write ( [ ] byte ( htmlDoc ) )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Successfully served Alloha player for imdb_id: %s" , imdbID )
2025-08-11 18:36:02 +00:00
}
func ( h * PlayersHandler ) GetLumexPlayer ( w http . ResponseWriter , r * http . Request ) {
2025-08-13 18:02:03 +00:00
log . Printf ( "GetLumexPlayer called: %s %s" , r . Method , r . URL . Path )
2025-09-28 11:46:20 +00:00
2025-08-11 18:36:02 +00:00
vars := mux . Vars ( r )
2025-08-13 18:02:03 +00:00
log . Printf ( "Route vars: %+v" , vars )
2025-09-28 11:46:20 +00:00
2025-08-11 18:36:02 +00:00
imdbID := vars [ "imdb_id" ]
if imdbID == "" {
2025-08-13 18:02:03 +00:00
log . Printf ( "Error: imdb_id is empty" )
http . Error ( w , "imdb_id path param is required" , http . StatusBadRequest )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Processing imdb_id: %s" , imdbID )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if h . config . LumexURL == "" {
log . Printf ( "Error: LUMEX_URL is missing" )
http . Error ( w , "Server misconfiguration: LUMEX_URL missing" , http . StatusInternalServerError )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-10-04 20:56:19 +00:00
// Получаем параметры для сериалов
season := r . URL . Query ( ) . Get ( "season" )
episode := r . URL . Query ( ) . Get ( "episode" )
2025-10-04 21:17:37 +00:00
log . Printf ( "🎬 Lumex Query Params - Season: '%s', Episode: '%s'" , season , episode )
2025-10-04 21:20:39 +00:00
// Lumex использует формат:
// Movie: {LUMEX_URL}/movie/{id}?autoplay=1
// TV: {LUMEX_URL}/tv-series/{id}?season=1&episode=3&autoplay=1
// ID может быть IMDb или числовым
var playerURL string
2025-10-04 20:56:19 +00:00
if season != "" && episode != "" {
2025-10-04 21:20:39 +00:00
// Сериал
playerURL = fmt . Sprintf ( "%s/tv-series/%s?season=%s&episode=%s&autoplay=1" , h . config . LumexURL , imdbID , season , episode )
log . Printf ( "✅ Lumex: TV series mode with season/episode" )
2025-10-04 21:17:37 +00:00
} else {
2025-10-04 21:20:39 +00:00
// Фильм
playerURL = fmt . Sprintf ( "%s/movie/%s?autoplay=1" , h . config . LumexURL , imdbID )
log . Printf ( "✅ Lumex: Movie mode" )
2025-10-04 20:56:19 +00:00
}
2025-10-04 21:17:37 +00:00
log . Printf ( "🔗 Final Lumex URL: %s" , playerURL )
2025-09-28 11:46:20 +00:00
2025-10-04 21:20:39 +00:00
iframe := fmt . Sprintf ( ` <iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe> ` , playerURL )
2025-08-13 18:02:03 +00:00
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>Lumex Player</title><style>html,body { margin:0;height:100%%;}</style></head><body>%s</body></html> ` , iframe )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
w . Header ( ) . Set ( "Content-Type" , "text/html" )
w . Write ( [ ] byte ( htmlDoc ) )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Successfully served Lumex player for imdb_id: %s" , imdbID )
2025-08-11 18:36:02 +00:00
}
func ( h * PlayersHandler ) GetVibixPlayer ( w http . ResponseWriter , r * http . Request ) {
2025-08-13 18:02:03 +00:00
log . Printf ( "GetVibixPlayer called: %s %s" , r . Method , r . URL . Path )
2025-09-28 11:46:20 +00:00
2025-08-11 18:36:02 +00:00
vars := mux . Vars ( r )
2025-08-13 18:02:03 +00:00
log . Printf ( "Route vars: %+v" , vars )
2025-09-28 11:46:20 +00:00
2025-08-11 18:36:02 +00:00
imdbID := vars [ "imdb_id" ]
if imdbID == "" {
2025-08-13 18:02:03 +00:00
log . Printf ( "Error: imdb_id is empty" )
http . Error ( w , "imdb_id path param is required" , http . StatusBadRequest )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Processing imdb_id: %s" , imdbID )
2025-08-11 18:36:02 +00:00
2025-08-13 18:02:03 +00:00
if h . config . VibixToken == "" {
log . Printf ( "Error: VIBIX_TOKEN is missing" )
http . Error ( w , "Server misconfiguration: VIBIX_TOKEN missing" , http . StatusInternalServerError )
2025-08-11 18:36:02 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
vibixHost := h . config . VibixHost
2025-08-11 18:36:02 +00:00
if vibixHost == "" {
vibixHost = "https://vibix.org"
2025-08-07 13:47:42 +00:00
}
2025-08-11 18:36:02 +00:00
2025-08-13 18:02:03 +00:00
apiURL := fmt . Sprintf ( "%s/api/v1/publisher/videos/imdb/%s" , vibixHost , imdbID )
log . Printf ( "Calling Vibix API: %s" , apiURL )
req , err := http . NewRequest ( "GET" , apiURL , nil )
2025-08-11 18:36:02 +00:00
if err != nil {
2025-08-13 18:02:03 +00:00
log . Printf ( "Error creating Vibix request: %v" , err )
http . Error ( w , "Failed to create request" , http . StatusInternalServerError )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-11 18:36:02 +00:00
req . Header . Set ( "Accept" , "application/json" )
2025-08-13 18:02:03 +00:00
req . Header . Set ( "Authorization" , "Bearer " + h . config . VibixToken )
2025-08-11 18:36:02 +00:00
req . Header . Set ( "X-CSRF-TOKEN" , "" )
client := & http . Client { Timeout : 8 * time . Second }
resp , err := client . Do ( req )
if err != nil {
2025-08-13 18:02:03 +00:00
log . Printf ( "Error calling Vibix API: %v" , err )
http . Error ( w , "Failed to fetch from Vibix API" , http . StatusInternalServerError )
2025-08-07 13:47:42 +00:00
return
}
2025-08-11 18:36:02 +00:00
defer resp . Body . Close ( )
2025-08-13 18:02:03 +00:00
log . Printf ( "Vibix API response status: %d" , resp . StatusCode )
2025-08-11 18:36:02 +00:00
if resp . StatusCode != http . StatusOK {
2025-08-13 18:02:03 +00:00
log . Printf ( "Vibix API error: %d" , resp . StatusCode )
http . Error ( w , fmt . Sprintf ( "Vibix API error: %d" , resp . StatusCode ) , http . StatusBadGateway )
2025-08-11 18:36:02 +00:00
return
2025-08-07 13:47:42 +00:00
}
2025-08-13 18:02:03 +00:00
body , err := io . ReadAll ( resp . Body )
if err != nil {
log . Printf ( "Error reading Vibix response: %v" , err )
http . Error ( w , "Failed to read Vibix response" , http . StatusInternalServerError )
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Vibix API response body: %s" , string ( body ) )
var vibixResponse struct {
2025-08-11 18:36:02 +00:00
ID interface { } ` json:"id" `
IframeURL string ` json:"iframe_url" `
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if err := json . Unmarshal ( body , & vibixResponse ) ; err != nil {
log . Printf ( "Error unmarshaling Vibix JSON: %v" , err )
http . Error ( w , "Invalid JSON from Vibix" , http . StatusBadGateway )
2025-08-07 13:47:42 +00:00
return
}
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
if vibixResponse . ID == nil || vibixResponse . IframeURL == "" {
log . Printf ( "Video not found or empty iframe_url" )
http . Error ( w , "Video not found" , http . StatusNotFound )
2025-08-07 13:47:42 +00:00
return
}
2025-08-11 18:36:02 +00:00
2025-10-04 20:56:19 +00:00
// Получаем параметры для сериалов
season := r . URL . Query ( ) . Get ( "season" )
episode := r . URL . Query ( ) . Get ( "episode" )
2025-10-04 21:17:37 +00:00
log . Printf ( "🎬 Vibix Query Params - Season: '%s', Episode: '%s'" , season , episode )
log . Printf ( "🔗 Vibix Base iframe_url: %s" , vibixResponse . IframeURL )
2025-10-04 20:56:19 +00:00
// Строим итоговый URL плеера
playerURL := vibixResponse . IframeURL
if season != "" && episode != "" {
// Добавляем параметры сезона и серии
separator := "?"
if strings . Contains ( playerURL , "?" ) {
separator = "&"
2025-10-04 21:17:37 +00:00
log . Printf ( "✅ Vibix: iframe_url already has query params, using '&'" )
} else {
log . Printf ( "✅ Vibix: iframe_url has no query params, using '?'" )
2025-10-04 20:56:19 +00:00
}
playerURL = fmt . Sprintf ( "%s%sseason=%s&episode=%s" , playerURL , separator , season , episode )
2025-10-04 21:17:37 +00:00
log . Printf ( "✅ Vibix: Added season/episode params" )
} else {
log . Printf ( "⚠️ Vibix: No season/episode params (movie mode)" )
2025-10-04 20:56:19 +00:00
}
2025-10-04 21:17:37 +00:00
log . Printf ( "🔗 Final Vibix URL: %s" , playerURL )
2025-10-04 20:56:19 +00:00
log . Printf ( "Generated Vibix iframe URL: %s" , playerURL )
2025-09-28 11:46:20 +00:00
2025-10-04 20:56:19 +00:00
iframe := fmt . Sprintf ( ` <iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe> ` , playerURL )
2025-08-13 18:02:03 +00:00
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>Vibix Player</title><style>html,body { margin:0;height:100%%;}</style></head><body>%s</body></html> ` , iframe )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
w . Header ( ) . Set ( "Content-Type" , "text/html" )
w . Write ( [ ] byte ( htmlDoc ) )
2025-09-28 11:46:20 +00:00
2025-08-13 18:02:03 +00:00
log . Printf ( "Successfully served Vibix player for imdb_id: %s" , imdbID )
2025-09-28 11:46:20 +00:00
}
2025-09-28 16:11:09 +00:00
// GetRgShowsPlayer handles RgShows streaming requests
func ( h * PlayersHandler ) GetRgShowsPlayer ( w http . ResponseWriter , r * http . Request ) {
log . Printf ( "GetRgShowsPlayer called: %s %s" , r . Method , r . URL . Path )
vars := mux . Vars ( r )
tmdbID := vars [ "tmdb_id" ]
if tmdbID == "" {
log . Printf ( "Error: tmdb_id is empty" )
http . Error ( w , "tmdb_id path param is required" , http . StatusBadRequest )
return
}
log . Printf ( "Processing tmdb_id: %s" , tmdbID )
pm := players . NewPlayersManager ( )
result , err := pm . GetMovieStreamByProvider ( "rgshows" , tmdbID )
if err != nil {
log . Printf ( "Error getting RgShows stream: %v" , err )
http . Error ( w , "Failed to get stream" , http . StatusInternalServerError )
return
}
if ! result . Success {
log . Printf ( "RgShows stream not found: %s" , result . Error )
http . Error ( w , "Stream not found" , http . StatusNotFound )
return
}
// Create iframe with the stream URL
iframe := fmt . Sprintf ( ` <iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe> ` , result . StreamURL )
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>RgShows 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 RgShows player for tmdb_id: %s" , tmdbID )
}
// GetRgShowsTVPlayer handles RgShows TV show streaming requests
func ( h * PlayersHandler ) GetRgShowsTVPlayer ( w http . ResponseWriter , r * http . Request ) {
log . Printf ( "GetRgShowsTVPlayer called: %s %s" , r . Method , r . URL . Path )
vars := mux . Vars ( r )
tmdbID := vars [ "tmdb_id" ]
seasonStr := vars [ "season" ]
episodeStr := vars [ "episode" ]
if tmdbID == "" || seasonStr == "" || episodeStr == "" {
log . Printf ( "Error: missing required parameters" )
http . Error ( w , "tmdb_id, season, and episode path params are required" , http . StatusBadRequest )
return
}
season , err := strconv . Atoi ( seasonStr )
if err != nil {
log . Printf ( "Error parsing season: %v" , err )
http . Error ( w , "Invalid season number" , http . StatusBadRequest )
return
}
episode , err := strconv . Atoi ( episodeStr )
if err != nil {
log . Printf ( "Error parsing episode: %v" , err )
http . Error ( w , "Invalid episode number" , http . StatusBadRequest )
return
}
log . Printf ( "Processing tmdb_id: %s, season: %d, episode: %d" , tmdbID , season , episode )
pm := players . NewPlayersManager ( )
result , err := pm . GetTVStreamByProvider ( "rgshows" , tmdbID , season , episode )
if err != nil {
log . Printf ( "Error getting RgShows TV stream: %v" , err )
http . Error ( w , "Failed to get stream" , http . StatusInternalServerError )
return
}
if ! result . Success {
log . Printf ( "RgShows TV stream not found: %s" , result . Error )
http . Error ( w , "Stream not found" , http . StatusNotFound )
return
}
// Create iframe with the stream URL
iframe := fmt . Sprintf ( ` <iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe> ` , result . StreamURL )
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>RgShows TV 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 RgShows TV player for tmdb_id: %s, S%dE%d" , tmdbID , season , episode )
}
// GetIframeVideoPlayer handles IframeVideo streaming requests
func ( h * PlayersHandler ) GetIframeVideoPlayer ( w http . ResponseWriter , r * http . Request ) {
log . Printf ( "GetIframeVideoPlayer called: %s %s" , r . Method , r . URL . Path )
vars := mux . Vars ( r )
kinopoiskID := vars [ "kinopoisk_id" ]
imdbID := vars [ "imdb_id" ]
if kinopoiskID == "" && imdbID == "" {
log . Printf ( "Error: both kinopoisk_id and imdb_id are empty" )
http . Error ( w , "Either kinopoisk_id or imdb_id path param is required" , http . StatusBadRequest )
return
}
log . Printf ( "Processing kinopoisk_id: %s, imdb_id: %s" , kinopoiskID , imdbID )
pm := players . NewPlayersManager ( )
result , err := pm . GetStreamWithKinopoisk ( kinopoiskID , imdbID )
if err != nil {
log . Printf ( "Error getting IframeVideo stream: %v" , err )
http . Error ( w , "Failed to get stream" , http . StatusInternalServerError )
return
}
if ! result . Success {
log . Printf ( "IframeVideo stream not found: %s" , result . Error )
http . Error ( w , "Stream not found" , http . StatusNotFound )
return
}
// Create iframe with the stream URL
iframe := fmt . Sprintf ( ` <iframe src="%s" allowfullscreen loading="lazy" style="border:none;width:100%%;height:100%%;"></iframe> ` , result . StreamURL )
htmlDoc := fmt . Sprintf ( ` <!DOCTYPE html><html><head><meta charset='utf-8'/><title>IframeVideo 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 IframeVideo player for kinopoisk_id: %s, imdb_id: %s" , kinopoiskID , imdbID )
}
// GetStreamAPI returns stream information as JSON API
func ( h * PlayersHandler ) GetStreamAPI ( w http . ResponseWriter , r * http . Request ) {
log . Printf ( "GetStreamAPI called: %s %s" , r . Method , r . URL . Path )
vars := mux . Vars ( r )
provider := vars [ "provider" ]
tmdbID := vars [ "tmdb_id" ]
if provider == "" || tmdbID == "" {
log . Printf ( "Error: missing required parameters" )
http . Error ( w , "provider and tmdb_id path params are required" , http . StatusBadRequest )
return
}
// Check for TV show parameters
seasonStr := r . URL . Query ( ) . Get ( "season" )
episodeStr := r . URL . Query ( ) . Get ( "episode" )
kinopoiskID := r . URL . Query ( ) . Get ( "kinopoisk_id" )
imdbID := r . URL . Query ( ) . Get ( "imdb_id" )
log . Printf ( "Processing provider: %s, tmdb_id: %s" , provider , tmdbID )
pm := players . NewPlayersManager ( )
var result * players . StreamResult
var err error
switch provider {
case "iframevideo" :
if kinopoiskID == "" && imdbID == "" {
http . Error ( w , "kinopoisk_id or imdb_id query param is required for IframeVideo" , http . StatusBadRequest )
return
}
result , err = pm . GetStreamWithKinopoisk ( kinopoiskID , imdbID )
case "rgshows" :
if seasonStr != "" && episodeStr != "" {
season , err1 := strconv . Atoi ( seasonStr )
episode , err2 := strconv . Atoi ( episodeStr )
if err1 != nil || err2 != nil {
http . Error ( w , "Invalid season or episode number" , http . StatusBadRequest )
return
}
result , err = pm . GetTVStreamByProvider ( "rgshows" , tmdbID , season , episode )
} else {
result , err = pm . GetMovieStreamByProvider ( "rgshows" , tmdbID )
}
default :
http . Error ( w , "Unsupported provider" , http . StatusBadRequest )
return
}
if err != nil {
log . Printf ( "Error getting stream from %s: %v" , provider , err )
result = & players . StreamResult {
Success : false ,
Provider : provider ,
Error : err . Error ( ) ,
}
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( result )
log . Printf ( "Successfully served stream API for provider: %s, tmdb_id: %s" , provider , tmdbID )
}
2025-10-04 19:18:44 +00:00
2025-10-04 19:52:39 +00:00
// GetVidsrcPlayer handles Vidsrc.to player (uses IMDb ID for both movies and TV shows)
2025-10-04 19:18:44 +00:00
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 )
2025-10-04 19:52:39 +00:00
imdbId := vars [ "imdb_id" ]
2025-10-04 19:18:44 +00:00
mediaType := vars [ "media_type" ] // "movie" or "tv"
2025-10-04 19:52:39 +00:00
if imdbId == "" || mediaType == "" {
http . Error ( w , "imdb_id and media_type are required" , http . StatusBadRequest )
2025-10-04 19:18:44 +00:00
return
}
var playerURL string
if mediaType == "movie" {
2025-10-04 19:52:39 +00:00
playerURL = fmt . Sprintf ( "https://vidsrc.to/embed/movie/%s" , imdbId )
2025-10-04 19:18:44 +00:00
} 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
}
2025-10-04 19:52:39 +00:00
playerURL = fmt . Sprintf ( "https://vidsrc.to/embed/tv/%s/%s/%s" , imdbId , season , episode )
2025-10-04 19:18:44 +00:00
} else {
http . Error ( w , "Invalid media_type. Use 'movie' or 'tv'" , http . StatusBadRequest )
return
}
log . Printf ( "Generated Vidsrc 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>Vidsrc 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 ) )
2025-10-04 19:52:39 +00:00
log . Printf ( "Successfully served Vidsrc player for %s: %s" , mediaType , imdbId )
2025-10-04 19:18:44 +00:00
}
2025-10-04 19:52:39 +00:00
// 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 )
2025-10-04 19:18:44 +00:00
vars := mux . Vars ( r )
2025-10-04 19:52:39 +00:00
imdbId := vars [ "imdb_id" ]
2025-10-04 19:18:44 +00:00
2025-10-04 19:52:39 +00:00
if imdbId == "" {
http . Error ( w , "imdb_id is required" , http . StatusBadRequest )
2025-10-04 19:18:44 +00:00
return
}
2025-10-04 19:52:39 +00:00
playerURL := fmt . Sprintf ( "https://vidlink.pro/movie/%s" , imdbId )
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 )
w . Header ( ) . Set ( "Content-Type" , "text/html" )
w . Write ( [ ] byte ( htmlDoc ) )
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 )
2025-10-04 19:18:44 +00:00
return
}
2025-10-04 19:52:39 +00:00
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 )
2025-10-04 19:18:44 +00:00
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 ) )
2025-10-04 19:52:39 +00:00
log . Printf ( "Successfully served Vidlink TV player: %s S%sE%s" , tmdbId , season , episode )
2025-10-04 19:18:44 +00:00
}