-
Notifications
You must be signed in to change notification settings - Fork 0
/
service.go
133 lines (122 loc) · 4.63 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"fmt"
"net/http"
"time"
)
var (
//TODO: Order handler priority via configuration
handlers = map[string]Handler{
"tidal": &TidalClient{},
"spotify": &SpotifyClient{},
}
providers = make([]string, 0)
)
// Handler is an interface to satisfy a libremedia service handler (a media or metadata provider, respond to something)
type Handler interface {
Provider() string //Used for service identification
SetService(*Service) //Provides the handler access to the libremedia service
Authenticate(*HandlerConfig) (Handler, error) //Attempts to authenticate with the given configuration
Creator(id string) (*ObjectCreator, error) //Returns the matching creator object for metadata
Album(id string) (*ObjectAlbum, error) //Returns the matching album object for metadata
Stream(id string) (*ObjectStream, error) //Returns the matching stream object for metadata
StreamFormat(w http.ResponseWriter, r *http.Request, stream *ObjectStream, format int) error
FormatList() []*ObjectFormat //Returns all the possible formats as templates ordered from best to worst
Search(query string) (*ObjectSearchResults, error) //Returns all the available search results that match the query
Transcribe(obj *ObjectStream) error //Fills in the stream's transcript with lyrics, closed captioning, subtitles, etc
ReplaceURI(text string) string //Replaces all instances of a URI with a libremedia-acceptable URI, for dynamic hyperlinking
}
// HandlerConfig defines a handler's login credentials and/or active status
type HandlerConfig struct {
Active bool `json:"active"`
Username string `json:"username"`
Password string `json:"password"`
DeviceName string `json:"deviceName"`
BlobPath string `json:"blobPath"`
}
// Service hosts a libremedia service instance's sessions and configuration
type Service struct {
AccessKeys []string `json:"accessKeys"`
BaseURL string `json:"baseURL"`
Handlers map[string]*HandlerConfig `json:"handlers"`
HostAddr string `json:"httpAddr"`
Grants map[string]*ServiceUser `json:"-"`
}
// Login logs into all of the active providers, blocking execution if any require action
func (s *Service) Login() error {
if s.BaseURL[len(s.BaseURL)-1] != '/' {
s.BaseURL += "/"
}
for provider, config := range s.Handlers {
if handler, exists := handlers[provider]; exists {
if config.Active {
newHandler, err := handler.Authenticate(config)
if err != nil {
Error.Println("Failed to authenticate "+provider+": ", err)
return err
}
newHandler.SetService(s)
handlers[provider] = newHandler
providers = append(providers, provider)
} else {
Trace.Println("Skipping authenticating inactive provider " + provider)
delete(handlers, provider)
}
}
}
return nil
}
// Auth checks the authentication key
func (s *Service) Auth(accessKey string) (*ServiceUser, error) {
allow := false
for i := 0; i < len(s.AccessKeys); i++ {
if s.AccessKeys[i] == accessKey {
allow = true
break
}
}
if !allow {
return nil, fmt.Errorf("invalid accessKey")
}
return nil, nil
}
// Stream transports a media stream for the specified format
func (s *Service) Stream(w http.ResponseWriter, r *http.Request, stream *ObjectStream, format int) error {
if stream == nil {
return fmt.Errorf("stream is nil")
}
if stream.Provider == "" {
return fmt.Errorf("provider not specified")
}
/* if stream.Formats == nil || len(stream.Formats) <= format {
objStream := GetObject(stream.URI, false)
if objStream != nil {
stream = objStream.Stream()
if stream.Formats == nil || len(stream.Formats) <= format {
return fmt.Errorf("format not available to stream")
}
} else {
return fmt.Errorf("stream not available right now")
}
}
*/
if handler, exists := handlers[stream.Provider]; exists {
return handler.StreamFormat(w, r, stream, format)
}
return fmt.Errorf("no handler for provider " + stream.Provider)
}
// Download transports a media download for the specified format
func (s *Service) Download(w http.ResponseWriter, r *http.Request, stream *ObjectStream, format int) error {
if stream.Provider == "" {
return fmt.Errorf("provider not specified")
}
if handler, exists := handlers[stream.Provider]; exists {
w.Header().Set("Content-Disposition", "attachment; filename=\""+stream.FileName()+"\"")
return handler.StreamFormat(w, r, stream, format)
}
return fmt.Errorf("no handler for provider " + stream.Provider)
}
// ServiceUser hosts a user's live session
type ServiceUser struct {
LastPing time.Time
}