-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Expand file tree
/
Copy pathytmda.go
More file actions
144 lines (110 loc) · 3.2 KB
/
Copy pathytmda.go
File metadata and controls
144 lines (110 loc) · 3.2 KB
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
134
135
136
137
138
139
140
141
142
143
144
package tui
import (
"encoding/json"
"errors"
"fmt"
"net"
httplib "net/http"
"strings"
"github.com/jandedobbeleer/oh-my-posh/src/build"
"github.com/jandedobbeleer/oh-my-posh/src/cache"
"github.com/jandedobbeleer/oh-my-posh/src/cli/auth"
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
"github.com/jandedobbeleer/oh-my-posh/src/runtime/http"
)
const (
tokenURL = auth.YTMDABASEURL + "/auth/request"
codeURL = auth.YTMDABASEURL + "/auth/requestcode"
)
func NewYtmda(env runtime.Environment) *Ytmda {
flow := &Ytmda{
env: env,
}
flow.model.status = flow.status
return flow
}
type Ytmda struct {
model
lastState state
}
func (y *Ytmda) Authenticate() {
setState(code)
y.lastState = code
code, err := y.requestCode()
if err != nil {
y.err = err
setState(done)
return
}
y.code = code
setState(token)
y.lastState = token
token, err := y.requestToken(code)
if err != nil {
y.err = err
setState(done)
return
}
if token == "" {
y.err = fmt.Errorf("received empty token")
setState(done)
return
}
cache.Device.Set(auth.YTMDATOKEN, token, cache.INFINITE)
setState(done)
}
func (y *Ytmda) requestCode() (string, error) {
body := fmt.Sprintf(`{"appId": "ohmyposh", "appName": "oh-my-posh", "appVersion": "%s"}`, strings.TrimPrefix(build.Version, "v"))
type codeResponse struct {
Code string `json:"code"`
}
result, err := ytmdaRequest[codeResponse](httplib.MethodPost, codeURL, body, y.env)
return result.Code, err
}
func (y *Ytmda) requestToken(code string) (string, error) {
body := fmt.Sprintf(`{"appId": "ohmyposh", "code": "%s"}`, code)
type tokenResponse struct {
Token string `json:"token"`
}
result, err := ytmdaRequest[tokenResponse](httplib.MethodPost, tokenURL, body, y.env)
return result.Token, err
}
func ytmdaRequest[a any](method, url, body string, env runtime.Environment, requestModifiers ...http.RequestModifier) (a, error) {
if requestModifiers == nil {
requestModifiers = []http.RequestModifier{}
}
modifyRequest := func(request *httplib.Request) {
request.Method = method
request.Header.Set("Content-Type", "application/json")
}
requestModifiers = append(requestModifiers, modifyRequest)
var result a
response, err := env.HTTPRequest(url, strings.NewReader(body), 50000, requestModifiers...)
if err != nil {
return result, err
}
err = json.Unmarshal(response, &result)
return result, err
}
func (y *Ytmda) status(err error) string {
// get the status code from the error if available
if err == nil {
return "Successfully authenticated with YouTube Music Desktop App"
}
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
return "There was a timeout while trying to connect to the YouTube Music Desktop App Companion API. Please try again"
}
httpErr, ok := err.(*http.Error)
if !ok {
// if the error is not an http.Error, the service isn't running
return "YouTube Music Desktop App is not running, please start the Companion API"
}
if httpErr.StatusCode != httplib.StatusForbidden {
return err.Error()
}
if y.lastState == token {
return "Failed to request token with code. Please press Allow in the pop-up window"
}
return "Please enable companion authorization in the YouTube Music Desktop App settings"
}