plex.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package plexapi
  2. import (
  3. "crypto/tls"
  4. "encoding/xml"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "net/http/cookiejar"
  10. "strings"
  11. "sync"
  12. "time"
  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) {
  72. cfg, err := ioutil.ReadFile(name)
  73. if err != nil {
  74. log.Fatal("Unable to load config", err)
  75. }
  76. yaml.Unmarshal(cfg, &api)
  77. }
  78. func (api *API) setHeader(req *http.Request) {
  79. req.Header.Add("X-Plex-Product", "plex-sync")
  80. req.Header.Add("X-Plex-Version", "1.0.0")
  81. req.Header.Add("X-Plex-Client-Identifier", "donkey")
  82. if api.userInfo.Token != "" {
  83. req.Header.Add("X-Plex-Token", api.userInfo.Token)
  84. }
  85. }
  86. // Login func
  87. func (api *API) login() error {
  88. if api.client == nil {
  89. cookieJar, _ := cookiejar.New(nil)
  90. tr := &http.Transport{
  91. TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  92. }
  93. api.client = &http.Client{
  94. Timeout: time.Duration(time.Second * api.HTTP.Timeout),
  95. Transport: tr,
  96. Jar: cookieJar,
  97. }
  98. }
  99. reqBody := fmt.Sprintf("user[login]=%s&user[password]=%s", api.User, api.Password)
  100. req, err := http.NewRequest("POST", "https://plex.tv/users/sign_in.xml", strings.NewReader(reqBody))
  101. api.setHeader(req)
  102. if err != nil {
  103. return err
  104. }
  105. resp, err := api.client.Do(req)
  106. if err != nil {
  107. return err
  108. }
  109. defer resp.Body.Close()
  110. body, err := ioutil.ReadAll(resp.Body)
  111. if err != nil {
  112. return err
  113. }
  114. return xml.Unmarshal(body, &api.userInfo)
  115. }
  116. // GetServers func
  117. func (api *API) GetServers() (servers map[string]*Server, err error) {
  118. if api.userInfo.Token == "" {
  119. err := api.login()
  120. if err != nil {
  121. return nil, err
  122. }
  123. }
  124. req, err := http.NewRequest("GET", "https://plex.tv/pms/servers.xml", nil)
  125. if err != nil {
  126. return nil, err
  127. }
  128. api.setHeader(req)
  129. resp, err := api.client.Do(req)
  130. if err != nil {
  131. return nil, err
  132. }
  133. defer resp.Body.Close()
  134. body, err := ioutil.ReadAll(resp.Body)
  135. if err != nil {
  136. return nil, err
  137. }
  138. var data MediaContainer
  139. err = xml.Unmarshal(body, &data)
  140. api.servers = make(map[string]*Server)
  141. for _, s := range data.Servers {
  142. ns := s
  143. ns.api = api
  144. api.servers[s.Name] = &ns
  145. }
  146. var wg sync.WaitGroup
  147. wg.Add(len(api.servers))
  148. for _, ps := range api.servers {
  149. server := ps
  150. go func() {
  151. server.Check()
  152. wg.Done()
  153. }()
  154. }
  155. wg.Wait()
  156. return api.servers, err
  157. }
  158. // GetServer func
  159. func (api *API) GetServer(name string) (server *Server, err error) {
  160. if api.servers == nil {
  161. _, err := api.GetServers()
  162. if err != nil {
  163. return nil, err
  164. }
  165. }
  166. s, ok := api.servers[name]
  167. if ok {
  168. return s, nil
  169. }
  170. return nil, fmt.Errorf("Server '%s' not found", name)
  171. }