166 lines
3.6 KiB
Go
166 lines
3.6 KiB
Go
package soundcloud
|
|
|
|
//go:generate go run ../../util/apigen/main.go --pkg soundcloud v2.yml
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
type v2Kind string
|
|
|
|
const (
|
|
// FIXME - not yet supported
|
|
//v2KindApp v2Kind = "app"
|
|
v2KindGroup v2Kind = "group"
|
|
v2KindPlaylist v2Kind = "playlist"
|
|
v2KindTrack v2Kind = "track"
|
|
v2KindUser v2Kind = "user"
|
|
)
|
|
|
|
var (
|
|
ErrUnsupportedKind = errors.New("Unsupported kind")
|
|
)
|
|
|
|
func (p *Parser) v2url(path string, urlvalues url.Values) *url.URL {
|
|
u := &url.URL{
|
|
Scheme: "https",
|
|
Host: "api-v2.soundcloud.com",
|
|
RawQuery: urlvalues.Encode(),
|
|
Path: path,
|
|
}
|
|
q := u.Query()
|
|
q.Set("client_id", p.Config.ClientId)
|
|
q.Set("app_version", "0.0") // TODO - Versioning
|
|
u.RawQuery = q.Encode()
|
|
log.Printf("SoundCloud parser: v2url: %s", u.String())
|
|
return u
|
|
}
|
|
|
|
func (p *Parser) v2call(path string, urlvalues url.Values) (v2Result, error) {
|
|
resp, err := p.http.Do(&http.Request{
|
|
URL: p.v2url(path, urlvalues),
|
|
Method: "GET",
|
|
Header: http.Header{
|
|
"Accept": []string{"application/json"},
|
|
"User-Agent": []string{"Icedream-YouTubeIRC/0.0"}, // TODO - Versioning
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 200 {
|
|
return nil, errors.New(resp.Status)
|
|
}
|
|
b := new(bytes.Buffer)
|
|
io.Copy(b, resp.Body)
|
|
log.Printf("v2call: Response is %s", b.String())
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
func (p *Parser) v2resolve(u string) (*v2ResolveResult, error) {
|
|
r, err := p.v2call("/resolve", url.Values{
|
|
"url": []string{u},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// First find out the kind via the most generic type possible
|
|
obj := new(v2Object)
|
|
if err := r.Decoder().Decode(obj); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Now decode as correct type
|
|
switch obj.Kind {
|
|
case v2KindTrack:
|
|
exactObj := new(v2Track)
|
|
if err := r.Decoder().Decode(exactObj); err != nil {
|
|
return nil, err
|
|
}
|
|
return &v2ResolveResult{exactObj, obj.Kind}, nil
|
|
case v2KindUser:
|
|
exactObj := new(v2User)
|
|
if err := r.Decoder().Decode(exactObj); err != nil {
|
|
return nil, err
|
|
}
|
|
return &v2ResolveResult{exactObj, obj.Kind}, nil
|
|
case v2KindGroup:
|
|
exactObj := new(v2Group)
|
|
if err := r.Decoder().Decode(exactObj); err != nil {
|
|
return nil, err
|
|
}
|
|
return &v2ResolveResult{exactObj, obj.Kind}, nil
|
|
case v2KindPlaylist:
|
|
exactObj := new(v2Playlist)
|
|
if err := r.Decoder().Decode(exactObj); err != nil {
|
|
return nil, err
|
|
}
|
|
return &v2ResolveResult{exactObj, obj.Kind}, nil
|
|
default:
|
|
return nil, ErrUnsupportedKind
|
|
}
|
|
}
|
|
|
|
type v2Result []byte
|
|
|
|
func (r v2Result) Decoder() *json.Decoder {
|
|
return json.NewDecoder(bytes.NewReader([]byte(r)))
|
|
}
|
|
|
|
type v2ResolveResult struct {
|
|
result interface{}
|
|
Kind v2Kind
|
|
}
|
|
|
|
func (r *v2ResolveResult) AsUser() *v2User {
|
|
return r.result.(*v2User)
|
|
}
|
|
|
|
// FIXME - not supported yet
|
|
/*func (r *v2ResolveResult) AsApp() *v2App {
|
|
return r.result.(*v2App)
|
|
}*/
|
|
|
|
func (r *v2ResolveResult) AsTrack() *v2Track {
|
|
return r.result.(*v2Track)
|
|
}
|
|
|
|
func (r *v2ResolveResult) AsPlaylist() *v2Playlist {
|
|
return r.result.(*v2Playlist)
|
|
}
|
|
|
|
func (r *v2ResolveResult) AsGroup() *v2Group {
|
|
return r.result.(*v2Group)
|
|
}
|
|
|
|
// FIXME - See https://github.com/golang/go/issues/9037 - Revert to using time.Time in the API as soon as this is fixed!
|
|
|
|
type timeString string
|
|
|
|
func (t timeString) ToTime(layout string) (parsedTime time.Time) {
|
|
if t == "" {
|
|
return // default time value
|
|
}
|
|
|
|
if len(layout) == 0 {
|
|
layout = time.RFC3339
|
|
}
|
|
|
|
parsedTime, err := time.Parse(layout, string(t))
|
|
if err != nil {
|
|
// It's just a temporary fix anyways
|
|
panic(err)
|
|
}
|
|
|
|
return
|
|
}
|