poster.go 7.3 KB

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