Files
neomovies-api/pkg/players/rgshows.go

82 lines
2.2 KiB
Go
Raw Normal View History

feat: add RgShows and IframeVideo streaming players 🎬 New Streaming Players Added: - RgShows player for movies and TV shows via TMDB ID - IframeVideo player using Kinopoisk ID and IMDB ID - Unified players manager for multiple streaming providers - JSON API endpoints for programmatic access 📡 RgShows Player Features: - Direct movie streaming: /api/v1/players/rgshows/{tmdb_id} - TV show episodes: /api/v1/players/rgshows/{tmdb_id}/{season}/{episode} - HTTP API integration with rgshows.com - 40-second timeout for reliability - Proper error handling and logging 🎯 IframeVideo Player Features: - Two-step authentication process (search + token extraction) - Support for both Kinopoisk and IMDB IDs - HTML iframe parsing for token extraction - Multipart form data for video URL requests - Endpoint: /api/v1/players/iframevideo/{kinopoisk_id}/{imdb_id} 🔧 Technical Implementation: - Clean Go architecture with pkg/players package - StreamResult interface for consistent responses - Proper HTTP headers mimicking browser requests - Comprehensive error handling and logging - RESTful API design following existing patterns 🌐 New API Endpoints: - /api/v1/players/rgshows/{tmdb_id} - RgShows movie player - /api/v1/players/rgshows/{tmdb_id}/{season}/{episode} - RgShows TV player - /api/v1/players/iframevideo/{kinopoisk_id}/{imdb_id} - IframeVideo player - /api/v1/stream/{provider}/{tmdb_id} - JSON API for stream info ✅ Quality Assurance: - All code passes go vet without issues - Proper Go formatting applied - Modular design for easy extension - No breaking changes to existing functionality Ready for production deployment! 🚀
2025-09-28 15:19:54 +00:00
package players
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
// RgShowsResponse represents the response from RgShows API
type RgShowsResponse struct {
Stream *struct {
URL string `json:"url"`
} `json:"stream"`
}
// RgShowsPlayer implements the RgShows streaming service
type RgShowsPlayer struct {
BaseURL string
Client *http.Client
}
// NewRgShowsPlayer creates a new RgShows player instance
func NewRgShowsPlayer() *RgShowsPlayer {
return &RgShowsPlayer{
BaseURL: "https://rgshows.com",
Client: &http.Client{
Timeout: 40 * time.Second,
},
}
}
// GetMovieStream gets streaming URL for a movie by TMDB ID
func (r *RgShowsPlayer) GetMovieStream(tmdbID string) (*StreamResult, error) {
url := fmt.Sprintf("%s/main/movie/%s", r.BaseURL, tmdbID)
return r.fetchStream(url)
}
// GetTVStream gets streaming URL for a TV show episode by TMDB ID, season and episode
func (r *RgShowsPlayer) GetTVStream(tmdbID string, season, episode int) (*StreamResult, error) {
url := fmt.Sprintf("%s/main/tv/%s/%d/%d", r.BaseURL, tmdbID, season, episode)
return r.fetchStream(url)
}
// fetchStream makes HTTP request to RgShows API and extracts stream URL
func (r *RgShowsPlayer) fetchStream(url string) (*StreamResult, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
// Set headers similar to the C# implementation
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36")
resp, err := r.Client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to fetch stream: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status: %d", resp.StatusCode)
}
var rgResp RgShowsResponse
if err := json.NewDecoder(resp.Body).Decode(&rgResp); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
if rgResp.Stream == nil || rgResp.Stream.URL == "" {
return nil, fmt.Errorf("stream not found")
}
return &StreamResult{
Success: true,
StreamURL: rgResp.Stream.URL,
Provider: "RgShows",
Type: "direct",
}, nil
}