plex.go 5.3 KB

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