plex.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. return xml.Unmarshal(body, &api.userInfo)
  124. }
  125. // GetServers func
  126. func (api *API) GetServers() (servers map[string]*Server, err error) {
  127. if api.userInfo.Token == "" {
  128. err := api.login()
  129. if err != nil {
  130. return nil, err
  131. }
  132. }
  133. req, err := http.NewRequest("GET", "https://plex.tv/pms/servers.xml", nil)
  134. if err != nil {
  135. return nil, err
  136. }
  137. api.setHeader(req)
  138. resp, err := api.client.Do(req)
  139. if err != nil {
  140. return nil, err
  141. }
  142. defer resp.Body.Close()
  143. body, err := ioutil.ReadAll(resp.Body)
  144. if err != nil {
  145. return nil, err
  146. }
  147. var data MediaContainer
  148. err = xml.Unmarshal(body, &data)
  149. api.servers = make(map[string]*Server)
  150. for _, s := range data.Servers {
  151. ns := s
  152. ns.api = api
  153. api.servers[s.Name] = &ns
  154. }
  155. var wg sync.WaitGroup
  156. wg.Add(len(api.servers))
  157. for _, ps := range api.servers {
  158. server := ps
  159. go func() {
  160. server.Check()
  161. wg.Done()
  162. }()
  163. }
  164. wg.Wait()
  165. return api.servers, err
  166. }
  167. // GetServer func
  168. func (api *API) GetServer(name string) (server *Server, err error) {
  169. if api.servers == nil {
  170. _, err := api.GetServers()
  171. if err != nil {
  172. return nil, err
  173. }
  174. }
  175. s, ok := api.servers[name]
  176. if ok {
  177. return s, nil
  178. }
  179. return nil, fmt.Errorf("Server '%s' not found", name)
  180. }