Initial Commit
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ────────────────────────────────
|
||||
// API DATA TYPES
|
||||
// ────────────────────────────────
|
||||
|
||||
type Client struct {
|
||||
base string
|
||||
http *http.Client
|
||||
}
|
||||
|
||||
func NewClient(base string, timeout time.Duration) *Client {
|
||||
return &Client{
|
||||
base: base,
|
||||
http: &http.Client{Timeout: timeout},
|
||||
}
|
||||
}
|
||||
|
||||
func BaseURLFromEnv() string {
|
||||
val := strings.TrimSpace(os.Getenv("STREAMED_BASE"))
|
||||
if val == "" {
|
||||
val = "https://streamed.pk"
|
||||
}
|
||||
return strings.TrimRight(val, "/")
|
||||
}
|
||||
|
||||
type Sport struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type Team struct {
|
||||
Name string `json:"name"`
|
||||
Badge string `json:"badge"`
|
||||
}
|
||||
|
||||
type Teams struct {
|
||||
Home *Team `json:"home"`
|
||||
Away *Team `json:"away"`
|
||||
}
|
||||
|
||||
type Match struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Category string `json:"category"`
|
||||
Date int64 `json:"date"`
|
||||
Poster string `json:"poster"`
|
||||
Popular bool `json:"popular"`
|
||||
Teams *Teams `json:"teams"`
|
||||
Sources []struct {
|
||||
Source string `json:"source"`
|
||||
ID string `json:"id"`
|
||||
} `json:"sources"`
|
||||
}
|
||||
|
||||
type Stream struct {
|
||||
ID string `json:"id"`
|
||||
StreamNo int `json:"streamNo"`
|
||||
Language string `json:"language"`
|
||||
HD bool `json:"hd"`
|
||||
EmbedURL string `json:"embedUrl"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
// ────────────────────────────────
|
||||
// API CLIENT
|
||||
// ────────────────────────────────
|
||||
|
||||
func (c *Client) GetSports(ctx context.Context) ([]Sport, error) {
|
||||
url := c.base + "/api/sports"
|
||||
var out []Sport
|
||||
if err := c.get(ctx, url, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetPopularMatches(ctx context.Context) ([]Match, error) {
|
||||
url := c.base + "/api/matches/all/popular"
|
||||
return c.getMatches(ctx, url)
|
||||
}
|
||||
|
||||
func (c *Client) GetMatchesBySport(ctx context.Context, sportID string) ([]Match, error) {
|
||||
url := fmt.Sprintf("%s/api/matches/%s", c.base, sportID)
|
||||
return c.getMatches(ctx, url)
|
||||
}
|
||||
|
||||
func (c *Client) GetStreamsForMatch(ctx context.Context, mt Match) ([]Stream, error) {
|
||||
var all []Stream
|
||||
for _, src := range mt.Sources {
|
||||
url := fmt.Sprintf("%s/api/stream/%s/%s", c.base, src.Source, src.ID)
|
||||
var list []Stream
|
||||
if err := c.get(ctx, url, &list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
all = append(all, list...)
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
func (c *Client) getMatches(ctx context.Context, url string) ([]Match, error) {
|
||||
var out []Match
|
||||
if err := c.get(ctx, url, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].Date < out[j].Date })
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) get(ctx context.Context, url string, v any) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", "StreamedTUI/1.0 (+https://github.com/Salastil/streamed-tui)")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("GET %s: %s", url, resp.Status)
|
||||
}
|
||||
return json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
Reference in New Issue
Block a user