123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- package main
- import (
- "fmt"
- "io"
- "log"
- "net/http"
- "os"
- "strings"
- "github.com/beanzilla/glom"
- "github.com/beego/x2j"
- )
- // https://zetcode.com/golang/getpostrequest/ post_req_form.go
- func Post(where string) *http.Response {
- resp, err := http.PostForm(where, nil)
- if err != nil {
- log.Printf("POST got non 200 code, %v", err)
- // Catch what error it is, if it's a no access to device try a etherwake
- return nil
- }
- return resp
- }
- /*func ListenToRequests(ln *net.UDPConn, data *string) {
- done := false
- do_send := true
- for !done {
- buffer := make([]byte, 1024) // 1k
- ln.SetReadDeadline(time.Now().Add(3 * time.Second))
- for !done {
- b, _, err := ln.ReadFromUDP(buffer)
- if b > 0 {
- str := string(buffer[0:])
- *data += str
- }
- if err != nil {
- if _, ok := err.(net.Error); !ok {
- log.Print(err)
- done = true
- }
- }
- if do_send {
- err = PostFind()
- if err != nil {
- log.Printf("POST Find returned %v", err)
- }
- do_send = false
- }
- }
- }
- }*/
- /*
- func PostFind() {
- file, err := os.ReadFile("finder.txt")
- if err != nil {
- log.Print(err)
- }
- addr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
- if err != nil {
- log.Print(err)
- }
- conn, err := net.DialUDP("udp", nil, addr)
- if err != nil {
- log.Print(err)
- }
- defer conn.Close()
- conn.Write(file)
- log.Println("Posted Request for devices")
- }
- func GetFind(data *[]string) {
- addr, err := net.ResolveUDPAddr("udp", ":1900")
- if err != nil {
- log.Printf("GET Find failed getting port 1900, %v", err)
- return
- }
- fmt.Printf("Listening on %s\r\n", addr.String())
- ln, err := net.ListenUDP("udp", addr)
- if err != nil {
- log.Printf("GET Find started listener for 1900, %v", err)
- return
- }
- var list []string
- buffer := make([]byte, 1024) // 1k
- defer ln.Close()
- ln.SetReadDeadline(time.Now().Add(3 * time.Second))
- for {
- n, adr, err := ln.ReadFromUDP(buffer)
- str := string(buffer[0:n])
- fmt.Printf("Got '%s' from %s\r\n", str, adr.String())
- if err != nil {
- log.Println(err)
- break
- }
- list = append(list, adr.String())
- }
- *data = list
- }
- */
- func Get(where string) *http.Response {
- resp, err := http.Get(where)
- if err != nil {
- log.Printf("GET got non 200 code, %v", err)
- return nil
- } else {
- return resp
- }
- }
- // https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#keypress-key-values codes
- func KeyPress(ip, command string) string {
- return fmt.Sprintf("http://%s:8060/keypress/%s", ip, command)
- }
- // https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#general-ecp-commands
- func Query(ip, what string) string {
- return fmt.Sprintf("http://%s:8060/query/%s", ip, what)
- }
- func PerformKey(ip, command string) bool {
- r := Post(KeyPress(ip, command))
- if r == nil {
- return false
- }
- defer r.Body.Close()
- return true
- }
- func GetQuery(ip, command string) map[string]interface{} {
- var resp *http.Response = Get(Query(ip, command))
- if resp == nil {
- return nil
- }
- var body []byte
- var err error
- body, err = io.ReadAll(resp.Body)
- if err != nil {
- log.Printf("Reading from body got error, %v", err)
- }
- // Change this so it's xml parsing it into a real struct (bye glom, your too ugly)
- var r map[string]interface{} = make(map[string]interface{})
- err = x2j.Unmarshal(body, &r)
- if err != nil {
- log.Printf("Got a error parsing XML, %v", err)
- }
- defer resp.Body.Close()
- // Save to file, for real pros
- if !FileExists("xmls") {
- os.Mkdir("xmls", 0660)
- }
- var filename string = fmt.Sprintf("xmls/%s.xml", command)
- err = os.WriteFile(filename, body, 0660)
- if err != nil {
- log.Printf("Got a error printing out xml to file '%s', %v", filename, err)
- }
- return r
- }
- func GetCurrentPlay(ip string) map[string]interface{} {
- resp := GetQuery(ip, "media-player")
- if resp == nil {
- return nil
- }
- return resp
- }
- func ObtainDeviceInfo(ip string) interface{} {
- resp := GetQuery(ip, "device-info")
- if resp == nil {
- return nil
- }
- return resp
- }
- func ParseDeviceInfo(dev_info interface{}) map[string]interface{} {
- dev, err := glom.Glom(dev_info, "device-info.*")
- if err != nil {
- log.Print(err)
- return nil
- }
- data := make(map[string]interface{})
- keys := glom.GetPossible(dev)
- for _, key := range keys {
- val, err := glom.Glom(dev, key)
- if err != nil {
- log.Printf("%s -> %v", key, err)
- } else {
- data[key] = val
- }
- }
- return data
- }
- // Returns a map of device-infos
- func GetDeviceInfo(ip string) map[string]interface{} {
- dev := ParseDeviceInfo(ObtainDeviceInfo(ip))
- /*keys := glom.GetPossible(dev)
- for _, key := range keys {
- log.Printf("%s = %v", key, dev[key])
- }*/
- return dev
- }
- func GetDevices(wake_on_lan map[string]string) (*[]string, map[string]string) {
- var str []string
- resp := strings.Split(PostFind(), "\n")
- //fmt.Printf("Processing %d lines\n", len(resp))
- ip := ""
- for _, line := range resp {
- if strings.Contains(line, "LOCATION") {
- st := strings.ReplaceAll(line, "LOCATION: http://", "")
- st = strings.ReplaceAll(st, ":8060/", "")
- st = strings.ReplaceAll(st, "\r", "")
- //fmt.Printf("IP='%s'", st)
- str = append(str, st)
- ip = st
- } else if strings.Contains(line, "WAKEUP") {
- st := strings.ReplaceAll(line, "WAKEUP: MAC=", "")
- st = strings.ReplaceAll(st, ";Timeout=10", "")
- st = strings.ReplaceAll(st, "\r", "")
- //fmt.Printf("IP='%s' MAC='%s'", ip, st)
- wake_on_lan[ip] = st
- }
- }
- return &str, wake_on_lan
- }
- func DebugInfo(ip string) string {
- // Query the current playing thing, and get the tv channels
- r := GetQuery(ip, "media-player")
- if r == nil {
- return ""
- }
- name, _ := glom.Glom(r, "player.plugin.-name")
- id, _ := glom.Glom(r, "player.plugin.-id")
- /*r1 := GetQuery(ip, "tv-channels")
- chan_name, _ := glom.Glom(r1, "tv-channels.channel.name")
- chan_phy_id, _ := glom.Glom(r1, "tv-channels.channel.physical-channel")
- chan_number, _ := glom.Glom(r1, "tv-channels.channel.number")*/
- if name == nil && id == nil {
- name = "TV"
- id = "No Connection"
- }
- // Debug print
- fmt.Printf("Name: %v (%v)\r\n", name, id)
- //fmt.Printf("Channel: %v (%v / %v)\r\n", chan_name, chan_phy_id, chan_number)
- return fmt.Sprintf("%v (%v)", name, id)
- }
- func examplePost() {
- keys := GetKeys()
- _ = keys // Keep alive
- PerformKey("192.168.254.75", keys["mute"])
- //Post("http://192.168.254.75:8060/launch/74519")
- //PerformKey("192.168.254.75", keys["home"])
- /*
- //resp := Post("http://192.168.254.75:8060/keypress/volumeMute")
- //resp := Post(KeyPress("192.168.254.75", "volumeMute"))
- //resp := Get(Query("192.168.254.75", "device-info"))
- //resp := GetQuery("192.168.254.75", "tv-active-channel")
- resp := GetQuery("192.168.254.75", "tv-channels")
- //result, err := glom.Glom(resp, "tv-channels.channel")
- _, err := glom.Glom(resp, "*")
- if err != nil {
- log.Println(err)
- } else {
- //fmt.Println(result)
- fmt.Println(glom.GetPossible(result))
- }
- */
- // Query the current playing thing, and get the tv channels
- r := GetQuery("192.168.254.75", "media-player")
- name, _ := glom.Glom(r, "player.plugin.-name")
- id, _ := glom.Glom(r, "player.plugin.-id")
- r1 := GetQuery("192.168.254.75", "tv-channels")
- chan_name, _ := glom.Glom(r1, "tv-channels.channel.name")
- chan_phy_id, _ := glom.Glom(r1, "tv-channels.channel.physical-channel")
- chan_number, _ := glom.Glom(r1, "tv-channels.channel.number")
- // Debug print
- fmt.Printf("Name: %v (%v)\r\n", name, id)
- fmt.Printf("Channel: %v (%v / %v)\r\n", chan_name, chan_phy_id, chan_number)
- }
|