Initial commit: Null DRM Official
Capture, decrypt, and restream toolkit with compiled-in app modules (RTE, TG4, BBC), on-device MITM proxy, streamd control plane, and www. BBC module.yaml is published (clear streams); other module values stay local.
This commit is contained in:
commit
2fa8f2435f
121 changed files with 17802 additions and 0 deletions
152
apps/modules/tg4/steps.go
Normal file
152
apps/modules/tg4/steps.go
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
package tg4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"drmdecryption/adb"
|
||||
"drmdecryption/uiflow"
|
||||
)
|
||||
|
||||
// openLivePage navigates to the Live page: if a menu entry is visible tap it,
|
||||
// otherwise open the side drawer first. Ported from the Starlark hook this module
|
||||
// used to carry, with every selector and coordinate now coming from config.
|
||||
func (a *App) openLivePage(c *adb.Client) error {
|
||||
c.DismissShadeIfFocused()
|
||||
nodes, err := c.DumpUI(a.CacheDir())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a.onLivePage(nodes) {
|
||||
fmt.Println("[*] already on Live")
|
||||
return nil
|
||||
}
|
||||
if live := a.findMenuLive(nodes); live != nil {
|
||||
fmt.Printf("[*] tap Live @ %d,%d\n", live.CX(), live.CY())
|
||||
_ = c.Tap(live.CX(), live.CY())
|
||||
time.Sleep(time.Duration(a.cfg.Timeouts.AfterLiveTap))
|
||||
return nil
|
||||
}
|
||||
|
||||
if !a.openDrawer(c) {
|
||||
fmt.Printf("[*] drawer fallback tap %d,%d\n", a.cfg.UI.DrawerFallbackX, a.cfg.UI.DrawerFallbackY)
|
||||
_ = c.Tap(a.cfg.UI.DrawerFallbackX, a.cfg.UI.DrawerFallbackY)
|
||||
time.Sleep(time.Duration(a.cfg.Timeouts.AfterDrawer))
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(time.Duration(a.cfg.Timeouts.LiveNav))
|
||||
for time.Now().Before(deadline) {
|
||||
nodes, err := c.DumpUI(a.CacheDir())
|
||||
if err == nil {
|
||||
if live := a.findMenuLive(nodes); live != nil {
|
||||
fmt.Printf("[*] tap Live @ %d,%d\n", live.CX(), live.CY())
|
||||
_ = c.Tap(live.CX(), live.CY())
|
||||
time.Sleep(time.Duration(a.cfg.Timeouts.AfterLiveTap))
|
||||
break
|
||||
}
|
||||
a.openDrawer(c)
|
||||
}
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
}
|
||||
|
||||
deadline = time.Now().Add(time.Duration(a.cfg.Timeouts.LiveNav))
|
||||
for time.Now().Before(deadline) {
|
||||
if nodes, err := c.DumpUI(a.CacheDir()); err == nil && a.onLivePage(nodes) {
|
||||
fmt.Printf("[*] Live page ready\n")
|
||||
return nil
|
||||
}
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
}
|
||||
return fmt.Errorf("Live page did not open")
|
||||
}
|
||||
|
||||
// onLivePage is true when the Live title is showing and at least one content card
|
||||
// is on screen.
|
||||
func (a *App) onLivePage(nodes []adb.Node) bool {
|
||||
hasTitle := false
|
||||
for _, n := range nodes {
|
||||
if !strings.EqualFold(strings.TrimSpace(n.Text), a.cfg.UI.LiveLabel) {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(n.ResourceID, a.cfg.UI.LiveTitleResource) ||
|
||||
(n.Y1 < a.cfg.UI.TitleMaxY && !n.Clickable) {
|
||||
hasTitle = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasTitle {
|
||||
return false
|
||||
}
|
||||
return len(uiflow.Cards(nodes, a.cfg.Cards)) > 0
|
||||
}
|
||||
|
||||
// openDrawer opens the side menu. Returns false when the drawer button could not
|
||||
// be identified, so the caller can fall back to a fixed tap.
|
||||
func (a *App) openDrawer(c *adb.Client) bool {
|
||||
nodes, err := c.DumpUI(a.CacheDir())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Already open?
|
||||
for _, n := range nodes {
|
||||
desc := strings.TrimSpace(n.Desc)
|
||||
for _, d := range a.cfg.UI.DrawerDesc {
|
||||
if desc == d && d == "Closed" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(n.Text), a.cfg.UI.LiveLabel) &&
|
||||
n.Clickable && n.X2 < a.cfg.UI.MenuMaxX {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ham := a.findDrawerButton(nodes)
|
||||
if ham == nil {
|
||||
return false
|
||||
}
|
||||
fmt.Printf("[*] tap menu %q @ %d,%d\n", ham.Desc, ham.CX(), ham.CY())
|
||||
_ = c.Tap(ham.CX(), ham.CY())
|
||||
time.Sleep(time.Duration(a.cfg.Timeouts.AfterDrawer))
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *App) findDrawerButton(nodes []adb.Node) *adb.Node {
|
||||
for i := range nodes {
|
||||
n := &nodes[i]
|
||||
if !n.Clickable {
|
||||
continue
|
||||
}
|
||||
desc := strings.TrimSpace(n.Desc)
|
||||
for _, d := range a.cfg.UI.DrawerDesc {
|
||||
if desc == d {
|
||||
return n
|
||||
}
|
||||
}
|
||||
}
|
||||
// Geometric fallback: a small clickable node in the top-left corner.
|
||||
for i := range nodes {
|
||||
n := &nodes[i]
|
||||
if n.Clickable && n.X1 < 50 && n.Y1 < 200 && n.X2 < 200 && n.Y2 < 300 {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// findMenuLive locates the drawer's Live entry.
|
||||
func (a *App) findMenuLive(nodes []adb.Node) *adb.Node {
|
||||
for i := range nodes {
|
||||
n := &nodes[i]
|
||||
if !n.Clickable {
|
||||
continue
|
||||
}
|
||||
if !strings.EqualFold(strings.TrimSpace(n.Text), a.cfg.UI.LiveLabel) {
|
||||
continue
|
||||
}
|
||||
if n.X2 <= a.cfg.UI.MenuMaxX && n.Y1 > a.cfg.UI.MenuMinY && n.Y1 < a.cfg.UI.MenuMaxY {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue