plex.go 5.3 KB

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