poster.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "net"
  7. "net/http"
  8. "os"
  9. "time"
  10. "github.com/beanzilla/glom"
  11. "github.com/beego/x2j"
  12. )
  13. // https://zetcode.com/golang/getpostrequest/ post_req_form.go
  14. func Post(where string) *http.Response {
  15. resp, err := http.PostForm(where, nil)
  16. if err != nil {
  17. log.Printf("POST got non 200 code, %v", err)
  18. }
  19. return resp
  20. }
  21. /*func ListenToRequests(ln *net.UDPConn, data *string) {
  22. done := false
  23. do_send := true
  24. for !done {
  25. buffer := make([]byte, 1024) // 1k
  26. ln.SetReadDeadline(time.Now().Add(3 * time.Second))
  27. for !done {
  28. b, _, err := ln.ReadFromUDP(buffer)
  29. if b > 0 {
  30. str := string(buffer[0:])
  31. *data += str
  32. }
  33. if err != nil {
  34. if _, ok := err.(net.Error); !ok {
  35. log.Print(err)
  36. done = true
  37. }
  38. }
  39. if do_send {
  40. err = PostFind()
  41. if err != nil {
  42. log.Printf("POST Find returned %v", err)
  43. }
  44. do_send = false
  45. }
  46. }
  47. }
  48. }*/
  49. func PostFind() {
  50. file, err := os.ReadFile("finder.txt")
  51. if err != nil {
  52. log.Print(err)
  53. }
  54. addr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
  55. if err != nil {
  56. log.Print(err)
  57. }
  58. conn, err := net.DialUDP("udp", nil, addr)
  59. if err != nil {
  60. log.Print(err)
  61. }
  62. defer conn.Close()
  63. conn.Write(file)
  64. log.Println("Posted Request for devices")
  65. }
  66. func GetFind(data *[]string) {
  67. addr, err := net.ResolveUDPAddr("udp", ":1900")
  68. if err != nil {
  69. log.Printf("GET Find failed getting port 1900, %v", err)
  70. return
  71. }
  72. fmt.Printf("Listening on %s\r\n", addr.String())
  73. ln, err := net.ListenUDP("udp", addr)
  74. if err != nil {
  75. log.Printf("GET Find started listener for 1900, %v", err)
  76. return
  77. }
  78. var list []string
  79. buffer := make([]byte, 1024) // 1k
  80. defer ln.Close()
  81. ln.SetReadDeadline(time.Now().Add(3 * time.Second))
  82. for {
  83. n, adr, err := ln.ReadFromUDP(buffer)
  84. str := string(buffer[0:n])
  85. fmt.Printf("Got '%s' from %s\r\n", str, adr.String())
  86. if err != nil {
  87. log.Println(err)
  88. break
  89. }
  90. list = append(list, adr.String())
  91. }
  92. *data = list
  93. }
  94. func Get(where string) *http.Response {
  95. resp, err := http.Get(where)
  96. if err != nil {
  97. log.Printf("GET got non 200 code, %v", err)
  98. return nil
  99. } else {
  100. return resp
  101. }
  102. }
  103. // https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#keypress-key-values codes
  104. func KeyPress(ip, command string) string {
  105. return fmt.Sprintf("http://%s:8060/keypress/%s", ip, command)
  106. }
  107. // https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#general-ecp-commands
  108. func Query(ip, what string) string {
  109. return fmt.Sprintf("http://%s:8060/query/%s", ip, what)
  110. }
  111. func PerformKey(ip, command string) {
  112. r := Post(KeyPress(ip, command))
  113. defer r.Body.Close()
  114. }
  115. func GetQuery(ip, command string) map[string]interface{} {
  116. resp := Get(Query(ip, command))
  117. if resp == nil {
  118. return nil
  119. }
  120. body, err := io.ReadAll(resp.Body)
  121. if err != nil {
  122. log.Printf("Reading from body got error, %v", err)
  123. }
  124. r := make(map[string]interface{})
  125. err = x2j.Unmarshal(body, &r)
  126. if err != nil {
  127. log.Printf("Got a error parsing XML, %v", err)
  128. }
  129. defer resp.Body.Close()
  130. return r
  131. }
  132. func GetCurrentPlay(ip string) map[string]interface{} {
  133. resp := GetQuery(ip, "media-player")
  134. if resp == nil {
  135. return nil
  136. }
  137. return resp
  138. }
  139. func ObtainDeviceInfo(ip string) interface{} {
  140. resp := GetQuery(ip, "device-info")
  141. if resp == nil {
  142. return nil
  143. }
  144. return resp
  145. }
  146. func ParseDeviceInfo(dev_info interface{}) map[string]interface{} {
  147. dev, err := glom.Glom(dev_info, "device-info.*")
  148. if err != nil {
  149. log.Print(err)
  150. return nil
  151. }
  152. data := make(map[string]interface{})
  153. keys := glom.GetPossible(dev)
  154. for _, key := range keys {
  155. val, err := glom.Glom(dev, key)
  156. if err != nil {
  157. log.Printf("%s -> %v", key, err)
  158. } else {
  159. data[key] = val
  160. }
  161. }
  162. return data
  163. }
  164. // Returns a map of device-infos
  165. func GetDeviceInfo(ip string) map[string]interface{} {
  166. dev := ParseDeviceInfo(ObtainDeviceInfo(ip))
  167. /*keys := glom.GetPossible(dev)
  168. for _, key := range keys {
  169. log.Printf("%s = %v", key, dev[key])
  170. }*/
  171. return dev
  172. }
  173. func GetDevices() *[]string {
  174. var str []string
  175. go GetFind(&str)
  176. go PostFind()
  177. //fmt.Print(str)
  178. return &str
  179. }
  180. func DebugInfo(ip string) string {
  181. // Query the current playing thing, and get the tv channels
  182. r := GetQuery(ip, "media-player")
  183. if r == nil {
  184. return ""
  185. }
  186. name, _ := glom.Glom(r, "player.plugin.-name")
  187. id, _ := glom.Glom(r, "player.plugin.-id")
  188. /*r1 := GetQuery(ip, "tv-channels")
  189. chan_name, _ := glom.Glom(r1, "tv-channels.channel.name")
  190. chan_phy_id, _ := glom.Glom(r1, "tv-channels.channel.physical-channel")
  191. chan_number, _ := glom.Glom(r1, "tv-channels.channel.number")*/
  192. if name == nil && id == nil {
  193. name = "TV"
  194. id = "No Connection"
  195. }
  196. // Debug print
  197. fmt.Printf("Name: %v (%v)\r\n", name, id)
  198. //fmt.Printf("Channel: %v (%v / %v)\r\n", chan_name, chan_phy_id, chan_number)
  199. return fmt.Sprintf("%v (%v)", name, id)
  200. }
  201. func examplePost() {
  202. keys := GetKeys()
  203. _ = keys // Keep alive
  204. PerformKey("192.168.254.75", keys["mute"])
  205. //Post("http://192.168.254.75:8060/launch/74519")
  206. //PerformKey("192.168.254.75", keys["home"])
  207. /*
  208. //resp := Post("http://192.168.254.75:8060/keypress/volumeMute")
  209. //resp := Post(KeyPress("192.168.254.75", "volumeMute"))
  210. //resp := Get(Query("192.168.254.75", "device-info"))
  211. //resp := GetQuery("192.168.254.75", "tv-active-channel")
  212. resp := GetQuery("192.168.254.75", "tv-channels")
  213. //result, err := glom.Glom(resp, "tv-channels.channel")
  214. _, err := glom.Glom(resp, "*")
  215. if err != nil {
  216. log.Println(err)
  217. } else {
  218. //fmt.Println(result)
  219. fmt.Println(glom.GetPossible(result))
  220. }
  221. */
  222. // Query the current playing thing, and get the tv channels
  223. r := GetQuery("192.168.254.75", "media-player")
  224. name, _ := glom.Glom(r, "player.plugin.-name")
  225. id, _ := glom.Glom(r, "player.plugin.-id")
  226. r1 := GetQuery("192.168.254.75", "tv-channels")
  227. chan_name, _ := glom.Glom(r1, "tv-channels.channel.name")
  228. chan_phy_id, _ := glom.Glom(r1, "tv-channels.channel.physical-channel")
  229. chan_number, _ := glom.Glom(r1, "tv-channels.channel.number")
  230. // Debug print
  231. fmt.Printf("Name: %v (%v)\r\n", name, id)
  232. fmt.Printf("Channel: %v (%v / %v)\r\n", chan_name, chan_phy_id, chan_number)
  233. }