Initial Exctractor work

This commit is contained in:
Salastil
2025-10-20 19:56:37 -04:00
parent 9ad5a2bc53
commit e5d769d59b
3 changed files with 201 additions and 174 deletions
+63 -17
View File
@@ -3,8 +3,6 @@ package internal
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
@@ -14,6 +12,10 @@ import (
"github.com/charmbracelet/lipgloss"
)
// ────────────────────────────────
// KEYMAP
// ────────────────────────────────
type keyMap struct {
Up, Down, Left, Right key.Binding
Enter, Quit, Refresh key.Binding
@@ -40,6 +42,7 @@ func defaultKeys() keyMap {
func (k keyMap) ShortHelp() []key.Binding {
return []key.Binding{k.Up, k.Down, k.Left, k.Right, k.Enter, k.OpenBrowser, k.OpenMPV, k.Quit}
}
func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Up, k.Down, k.Left, k.Right},
@@ -47,6 +50,10 @@ func (k keyMap) FullHelp() [][]key.Binding {
}
}
// ────────────────────────────────
// TYPES & CONSTANTS
// ────────────────────────────────
type (
sportsLoadedMsg []Sport
matchesLoadedMsg struct {
@@ -74,6 +81,10 @@ const (
viewDebug
)
// ────────────────────────────────
// MODEL
// ────────────────────────────────
type Model struct {
apiClient *Client
styles Styles
@@ -92,6 +103,10 @@ type Model struct {
TerminalWidth int
}
// ────────────────────────────────
// ENTRY POINT
// ────────────────────────────────
func Run() error {
p := tea.NewProgram(New(), tea.WithAltScreen())
_, err := p.Run()
@@ -134,6 +149,10 @@ func New() Model {
return m
}
// ────────────────────────────────
// VIEW MANAGEMENT
// ────────────────────────────────
func (m Model) Init() tea.Cmd {
return tea.Batch(m.fetchSports(), m.fetchPopularMatches())
}
@@ -212,6 +231,10 @@ func (m Model) renderDebugPanel() string {
return panel
}
// ────────────────────────────────
// UPDATE LOOP
// ────────────────────────────────
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
@@ -368,6 +391,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
// ────────────────────────────────
// FETCHERS
// ────────────────────────────────
func (m Model) fetchSports() tea.Cmd {
return func() tea.Msg {
sports, err := m.apiClient.GetSports(context.Background())
@@ -408,33 +435,52 @@ func (m Model) fetchStreamsForMatch(mt Match) tea.Cmd {
}
}
// ────────────────────────────────
// EXTRACTOR (chromedp integration)
// ────────────────────────────────
func (m Model) runExtractor(st Stream) tea.Cmd {
return func() tea.Msg {
if st.EmbedURL == "" {
return debugLogMsg("Extractor aborted: empty embed URL")
}
m3u8, err := extractM3U8Lite(st.EmbedURL, func(line string) {
// each extractor log line will flow back to the UI
return
logcb := func(line string) {
m.debugLines = append(m.debugLines, line)
if len(m.debugLines) > 200 {
m.debugLines = m.debugLines[len(m.debugLines)-200:]
}
}
logcb(fmt.Sprintf("[extractor] Starting Chrome-based extractor for %s", st.EmbedURL))
m3u8, hdrs, err := extractM3U8Lite(st.EmbedURL, func(line string) {
m.debugLines = append(m.debugLines, line)
})
if err != nil {
logcb(fmt.Sprintf("[extractor] ❌ %v", err))
return debugLogMsg(fmt.Sprintf("Extractor failed: %v", err))
}
cmd := exec.Command("mpv",
"--no-terminal",
"--really-quiet",
fmt.Sprintf("--http-header-fields=User-Agent: %s", "Mozilla/5.0 (X11; Linux x86_64) Gecko/20100101 Firefox/144.0"),
fmt.Sprintf("--http-header-fields=Origin: %s", "https://embedsports.top"),
fmt.Sprintf("--http-header-fields=Referer: %s", "https://embedsports.top/"),
m3u8,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
_ = cmd.Start()
return debugLogMsg(fmt.Sprintf("Extractor success, launched MPV: %s", m3u8))
logcb(fmt.Sprintf("[extractor] ✅ Found M3U8: %s", m3u8))
if len(hdrs) > 0 {
logcb(fmt.Sprintf("[extractor] Captured %d headers", len(hdrs)))
}
if err := LaunchMPVWithHeaders(m3u8, hdrs, logcb); err != nil {
logcb(fmt.Sprintf("[mpv] ❌ %v", err))
return debugLogMsg(fmt.Sprintf("MPV error: %v", err))
}
logcb(fmt.Sprintf("[mpv] ▶ Streaming started for %s", st.EmbedURL))
return debugLogMsg("Extractor completed successfully")
}
}
// ────────────────────────────────
// LOG TO UI
// ────────────────────────────────
func (m Model) logToUI(line string) tea.Cmd {
return func() tea.Msg {
return debugLogMsg(line)