plex.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package plexapi
  2. import (
  3. "crypto/tls"
  4. "encoding/xml"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "net/http/cookiejar"
  9. "strings"
  10. "sync"
  11. "time"
  12. log "github.com/Sirupsen/logrus"
  13. "gopkg.in/yaml.v2"
  14. )
  15. // API struct
  16. type API struct {
  17. User string `yaml:"user"`
  18. Password string `yaml:"password"`
  19. HTTP HTTPConfig `yaml:"http"`
  20. client *http.Client
  21. userInfo UserInfo
  22. servers map[string]*Server
  23. }
  24. // HTTPConfig struct
  25. type HTTPConfig struct {
  26. Timeout time.Duration `yaml:"timeout"`
  27. WorkerSize int `yaml:"workerSize"`
  28. }
  29. // UserInfo struct
  30. type UserInfo struct {
  31. XMLName xml.Name `xml:"user"`
  32. UserName string `xml:"username"`
  33. Token string `xml:"authentication-token"`
  34. }
  35. // ResponseError struct
  36. type ResponseError struct {
  37. XMLName xml.Name `xml:"errors"`
  38. Errors []string `xml:"error"`
  39. }
  40. // MediaContainer struct
  41. type MediaContainer struct {
  42. Paths []string `xml:"-"`
  43. Keys []KeyInfo `xml:"-"`
  44. XMLName xml.Name `xml:"MediaContainer"`
  45. Servers []Server `xml:"Server"`
  46. Directories []Directory `xml:"Directory"`
  47. Videos []Video `xml:"Video"`
  48. Size int `xml:"size,attr"`
  49. AllowCameraUpload int `xml:"allowCameraUpload,attr"`
  50. AllowSync int `xml:"allowSync,attr"`
  51. AllowChannelAccess int `xml:"allowChannelAccess,attr"`
  52. RequestParametersInCookie int `xml:"requestParametersInCookie,attr"`
  53. Sync int `xml:"sync,attr"`
  54. TranscoderActiveVideoSessions int `xml:"transcoderActiveVideoSessions,attr"`
  55. TranscoderAudio int `xml:"transcoderAudio,attr"`
  56. TranscoderVideo int `xml:"transcoderVideo,attr"`
  57. TranscoderVideoBitrates string `xml:"transcoderVideoBitrates,attr"`
  58. TranscoderVideoQualities string `xml:"transcoderVideoQualities,attr"`
  59. TranscoderVideoResolutions string `xml:"transcoderVideoResolutions,attr"`
  60. FriendlyName string `xml:"friendlyName,attr"`
  61. MachineIdentifier string `xml:"machineIdentifier,attr"`
  62. }
  63. // KeyInfo struct
  64. type KeyInfo struct {
  65. Key string
  66. Type string
  67. Title string
  68. }
  69. // Progress struct
  70. type Progress struct {
  71. Server string
  72. Command string
  73. Delta int
  74. }
  75. // LoadConfig func
  76. func (api *API) LoadConfig(name string) error {
  77. cfg, err := ioutil.ReadFile(name)
  78. if err != nil {
  79. return err
  80. }
  81. yaml.Unmarshal(cfg, &api)
  82. return nil
  83. }
  84. // SaveConfig func
  85. func (api *API) SaveConfig(name string) error {
  86. data, err := yaml.Marshal(api)
  87. if err != nil {
  88. return err
  89. }
  90. err = ioutil.WriteFile(name, data, 0700)
  91. return err
  92. }
  93. func (api *API) setHeader(req *http.Request) {
  94. req.Header.Add("X-Plex-Product", "plex-sync")
  95. req.Header.Add("X-Plex-Version", "1.0.0")
  96. req.Header.Add("X-Plex-Client-Identifier", "donkey")
  97. if api.userInfo.Token != "" {
  98. req.Header.Add("X-Plex-Token", api.userInfo.Token)
  99. }
  100. }
  101. // Login func
  102. func (api *API) login() error {
  103. if api.client == nil {
  104. cookieJar, _ := cookiejar.New(nil)
  105. tr := &http.Transport{
  106. TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  107. }
  108. api.client = &http.Client{
  109. Timeout: time.Duration(time.Second * api.HTTP.Timeout),
  110. Transport: tr,
  111. Jar: cookieJar,
  112. }
  113. }
  114. reqBody := fmt.Sprintf("user[login]=%s&user[password]=%s", api.User, api.Password)
  115. req, err := http.NewRequest("POST", "https://plex.tv/users/sign_in.xml", strings.NewReader(reqBody))
  116. api.setHeader(req)
  117. if err != nil {
  118. return err
  119. }
  120. resp, err := api.client.Do(req)
  121. if err != nil {
  122. return err
  123. }
  124. defer resp.Body.Close()
  125. body, err := ioutil.ReadAll(resp.Body)
  126. if err != nil {
  127. return err
  128. }
  129. err = xml.Unmarshal(body, &api.userInfo)
  130. if err != nil {
  131. log.Debug("LOGIN RESULT\n", string(body))
  132. emsg := &ResponseError{}
  133. if xml.Unmarshal(body, emsg) == nil {
  134. if len(emsg.Errors) > 0 {
  135. return fmt.Errorf("%s", emsg.Errors[0])
  136. }
  137. }
  138. }
  139. return err
  140. }
  141. // GetServers func
  142. func (api *API) GetServers() (servers map[string]*Server, err error) {
  143. if api.userInfo.Token == "" {
  144. err := api.login()
  145. if err != nil {
  146. return nil, err
  147. }
  148. }
  149. req, err := http.NewRequest("GET", "https://plex.tv/pms/servers.xml", nil)
  150. if err != nil {
  151. return nil, err
  152. }
  153. api.setHeader(req)
  154. resp, err := api.client.Do(req)
  155. if err != nil {
  156. return nil, err
  157. }
  158. defer resp.Body.Close()
  159. body, err := ioutil.ReadAll(resp.Body)
  160. if err != nil {
  161. return nil, err
  162. }
  163. var data MediaContainer
  164. err = xml.Unmarshal(body, &data)
  165. api.servers = make(map[string]*Server)
  166. for _, s := range data.Servers {
  167. ns := s
  168. ns.api = api
  169. api.servers[s.Name] = &ns
  170. }
  171. var wg sync.WaitGroup
  172. wg.Add(len(api.servers))
  173. for _, ps := range api.servers {
  174. server := ps
  175. go func() {
  176. server.Check()
  177. wg.Done()
  178. }()
  179. }
  180. wg.Wait()
  181. return api.servers, err
  182. }
  183. // GetServer func
  184. func (api *API) GetServer(name string) (server *Server, err error) {
  185. if api.servers == nil {
  186. _, err := api.GetServers()
  187. if err != nil {
  188. return nil, err
  189. }
  190. }
  191. s, ok := api.servers[name]
  192. if ok {
  193. return s, nil
  194. }
  195. return nil, fmt.Errorf("Server '%s' not found", name)
  196. }