plex.go 4.8 KB

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