plex.go 4.9 KB

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