vendor!
This commit is contained in:
18
vendor/github.com/thehowl/conf/LICENSE
generated
vendored
Normal file
18
vendor/github.com/thehowl/conf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2016 Morgan Bazalgette
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
83
vendor/github.com/thehowl/conf/README.md
generated
vendored
Normal file
83
vendor/github.com/thehowl/conf/README.md
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
# conf [](https://travis-ci.org/thehowl/conf) [](https://godoc.org/github.com/thehowl/conf)
|
||||
|
||||
(yes I am that creative with names)
|
||||
|
||||
I have been using [ini](http://gopkg.in/ini.v1) for managing configuration files in go for quite some time. One of the things that had bothered me though, was that it really was a pain to set up for small projects, as it's just boilerplate code over and over. So I decided to write my own configuration file system, and now I'm here.
|
||||
|
||||
## Quick start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thehowl/conf"
|
||||
)
|
||||
|
||||
type myConf struct {
|
||||
Port string `description:"The port from which the application will take HTTP requests"`
|
||||
Password string
|
||||
MaxUsers int
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := myConf{}
|
||||
err := conf.Load(&c, "myapp.conf")
|
||||
if err == conf.ErrNoFile {
|
||||
// You can export your conf to a file, so you can write default values.
|
||||
conf.Export(myConf{
|
||||
Port: ":8080",
|
||||
Password: "hunter2",
|
||||
MaxUsers: 9001,
|
||||
}, "myapp.conf")
|
||||
fmt.Println("Please compile the configuration file (myapp.conf.)")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// You can now use the values in `c` without thinking about the actual configuration ever again!
|
||||
fmt.Printf("%#v\n", c)
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration file format
|
||||
|
||||
```
|
||||
; This is an example configuration file generated with `conf`. Comments are done using semicolons.
|
||||
;
|
||||
; This is a simple string value in the configuration:
|
||||
String=Hello world!
|
||||
|
||||
; Note that there are no spaces between the field (key) name and its value. Conf does not trim strings.
|
||||
; int, float, uint values are done just as easily. You just need to write that they're of that type in
|
||||
; the struct, and conf will do all the magic!
|
||||
Int=481
|
||||
|
||||
; There are also bools.
|
||||
Bool=1
|
||||
; Bools are retrieved through [ParseBool](https://golang.org/pkg/strconv/#ParseBool), as such they
|
||||
; need to be one of 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
|
||||
|
||||
; But, what about strings with newlines?
|
||||
AreTheyPossible=Yes\
|
||||
They\
|
||||
Are!
|
||||
; If you need to export a flag with a multiline string, conf will automatically escape it.
|
||||
;
|
||||
; By the way, conf automatically ignores lines without a valid field=value combination, including
|
||||
; empty lines, so you can use them as comments, although discouraged.
|
||||
So yes, this line will be silently ignored!
|
||||
=This one, too!
|
||||
And this one, too!=
|
||||
|
||||
; Escaping can not only be done with newlines. Here's what you can possibly escape!
|
||||
Fields\=With\=Equal\=Signs=can be escaped!
|
||||
Comments=Can \; be escaped!
|
||||
Oh yeah, fields=can also have spaces and what not in them.; You can also write comments straight after a value!
|
||||
|
||||
; And that's all you need to know for using `conf`!
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
165
vendor/github.com/thehowl/conf/conf.go
generated
vendored
Normal file
165
vendor/github.com/thehowl/conf/conf.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// Package conf lets you manage configuration files in the easiest way possible, without the unnecessary pain.
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The only custom errors this package will return.
|
||||
var (
|
||||
ErrNoFile = errors.New("conf: the configuration file doesn't exist")
|
||||
ErrNotAStruct = errors.New("conf: the passed into/from variable is not a pointer to a struct")
|
||||
)
|
||||
|
||||
// Load unmarshals a file into the struct passed as the argument "into".
|
||||
func Load(into interface{}, filename string) error {
|
||||
intoValue := reflect.ValueOf(into)
|
||||
if intoValue.Kind() != reflect.Ptr || intoValue.Elem().Kind() != reflect.Struct {
|
||||
return ErrNotAStruct
|
||||
}
|
||||
intoValue = intoValue.Elem()
|
||||
f, err := ioutil.ReadFile(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return ErrNoFile
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return loadRaw(intoValue, f)
|
||||
}
|
||||
|
||||
// LoadRaw allows you to load into a struct some raw data bytes.
|
||||
func LoadRaw(into interface{}, data []byte) error {
|
||||
intoValue := reflect.ValueOf(into)
|
||||
if intoValue.Kind() != reflect.Ptr || intoValue.Elem().Kind() != reflect.Struct {
|
||||
return ErrNotAStruct
|
||||
}
|
||||
intoValue = intoValue.Elem()
|
||||
return loadRaw(intoValue, data)
|
||||
}
|
||||
|
||||
func loadRaw(intoValue reflect.Value, data []byte) error {
|
||||
fvs := Parse(data)
|
||||
for _, v := range fvs {
|
||||
for i := 0; i < intoValue.Type().NumField(); i++ {
|
||||
field := intoValue.Type().Field(i)
|
||||
if !intoValue.Field(i).CanSet() {
|
||||
continue
|
||||
}
|
||||
if field.Name == v.Field {
|
||||
switch field.Type.Kind() {
|
||||
case reflect.String:
|
||||
intoValue.Field(i).SetString(v.Value)
|
||||
case reflect.Bool:
|
||||
boolVal, err := strconv.ParseBool(v.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
intoValue.Field(i).SetBool(boolVal)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intVal, err := strconv.ParseInt(v.Value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
intoValue.Field(i).SetInt(intVal)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
uintVal, err := strconv.ParseUint(v.Value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
intoValue.Field(i).SetUint(uintVal)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
floatVal, err := strconv.ParseFloat(v.Value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
intoValue.Field(i).SetFloat(floatVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustLoad has the same behaviour as Load, but panics if it returns an error.
|
||||
func MustLoad(into interface{}, filename string) {
|
||||
if err := Load(into, filename); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustLoadRaw has the same behaviour as LoadRaw, but panics if it returns an error.
|
||||
func MustLoadRaw(into interface{}, data []byte) {
|
||||
if err := LoadRaw(into, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Export uses ExportRaw to put the data into a file, specified with its name.
|
||||
func Export(from interface{}, filename string) error {
|
||||
data, err := ExportRaw(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filename, data, 0644)
|
||||
}
|
||||
|
||||
// ExportRaw can create a []byte that can then be loaded back by LoadRaw to get a struct's original form back.
|
||||
// I suck at explaining stuff.
|
||||
func ExportRaw(from interface{}) ([]byte, error) {
|
||||
fromValue := reflect.ValueOf(from)
|
||||
if fromValue.Kind() == reflect.Ptr {
|
||||
return ExportRaw(fromValue.Elem().Interface())
|
||||
}
|
||||
if fromValue.Kind() != reflect.Struct {
|
||||
return []byte{}, ErrNotAStruct
|
||||
}
|
||||
return exportRaw(fromValue), nil
|
||||
}
|
||||
|
||||
func exportRaw(fromValue reflect.Value) []byte {
|
||||
var ret []byte
|
||||
for i := 0; i < fromValue.Type().NumField(); i++ {
|
||||
curfield := fromValue.Field(i)
|
||||
curfieldType := fromValue.Type().Field(i)
|
||||
|
||||
// Dirty hack to ignore that field if we don't support that type.
|
||||
if !((curfield.Kind() >= reflect.Bool && curfield.Kind() <= reflect.Uint64) ||
|
||||
curfield.Kind() == reflect.String || curfield.Kind() == reflect.Float32 ||
|
||||
curfield.Kind() == reflect.Float64) {
|
||||
continue
|
||||
}
|
||||
|
||||
/* guten */ tag := curfieldType.Tag.Get("description")
|
||||
if tag != "" {
|
||||
tag = strings.Replace(tag, "\n", "\n; ", -1)
|
||||
ret = append(ret, []byte("; "+tag+"\n")...)
|
||||
}
|
||||
ret = append(ret, []byte(Escape(curfieldType.Name)+"="+Escape(fmt.Sprint(curfield.Interface()))+"\n")...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// MustExport panics if Export returns an error, removing error checking from your code. For the lazy.
|
||||
func MustExport(from interface{}, filename string) {
|
||||
if err := Export(from, filename); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustExportRaw panics if ExportRaw returns an error, removing error checking from your code. For the lazy.
|
||||
func MustExportRaw(from interface{}) []byte {
|
||||
data, err := ExportRaw(from)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
}
|
15
vendor/github.com/thehowl/conf/escape.go
generated
vendored
Normal file
15
vendor/github.com/thehowl/conf/escape.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Escape escapes characters for then putting it into conf field/values without issues.
|
||||
func Escape(s string) string {
|
||||
return strings.NewReplacer(
|
||||
"\n", "\\\n",
|
||||
`\`, `\\`,
|
||||
`;`, `\;`,
|
||||
`=`, `\=`,
|
||||
).Replace(s)
|
||||
}
|
89
vendor/github.com/thehowl/conf/parse.go
generated
vendored
Normal file
89
vendor/github.com/thehowl/conf/parse.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package conf
|
||||
|
||||
// FieldValue is a field=value pair in the configuration.
|
||||
type FieldValue struct {
|
||||
Field string
|
||||
Value string
|
||||
}
|
||||
|
||||
const (
|
||||
currentName = iota
|
||||
currentValue
|
||||
currentComment
|
||||
)
|
||||
|
||||
// Parse converts some bytes into various FieldValue pairs.
|
||||
func Parse(data []byte) []FieldValue {
|
||||
fvs := []FieldValue{}
|
||||
var (
|
||||
fieldName string
|
||||
fieldValue string
|
||||
nextNormal bool
|
||||
current byte
|
||||
)
|
||||
|
||||
for _, c := range data {
|
||||
if current == currentComment && c != '\n' {
|
||||
continue
|
||||
}
|
||||
if nextNormal {
|
||||
switch current {
|
||||
case currentName:
|
||||
fieldName += string(c)
|
||||
case currentValue:
|
||||
fieldValue += string(c)
|
||||
}
|
||||
nextNormal = false
|
||||
continue
|
||||
}
|
||||
switch c {
|
||||
case '=':
|
||||
switch current {
|
||||
// if we are still at the name, let's switch to a value.
|
||||
case currentName:
|
||||
current = currentValue
|
||||
// if we are already at the value, treat the = character like any other sign
|
||||
case currentValue:
|
||||
fieldValue += string(c)
|
||||
}
|
||||
case ';':
|
||||
current = currentComment
|
||||
case '\n':
|
||||
if fieldName != "" && fieldValue != "" {
|
||||
fvs = append(fvs, FieldValue{
|
||||
Field: fieldName,
|
||||
Value: removeTrailingCR(fieldValue),
|
||||
})
|
||||
}
|
||||
fieldName = ""
|
||||
fieldValue = ""
|
||||
current = currentName
|
||||
case '\\':
|
||||
nextNormal = true
|
||||
default:
|
||||
switch current {
|
||||
case currentName:
|
||||
fieldName += string(c)
|
||||
case currentValue:
|
||||
fieldValue += string(c)
|
||||
}
|
||||
nextNormal = false
|
||||
}
|
||||
}
|
||||
if fieldName != "" && fieldValue != "" {
|
||||
fvs = append(fvs, FieldValue{
|
||||
Field: fieldName,
|
||||
Value: removeTrailingCR(fieldValue),
|
||||
})
|
||||
}
|
||||
return fvs
|
||||
}
|
||||
func removeTrailingCR(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
if s[len(s)-1] == '\r' {
|
||||
return s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
21
vendor/github.com/thehowl/go-osuapi/LICENSE
generated
vendored
Normal file
21
vendor/github.com/thehowl/go-osuapi/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Howl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
41
vendor/github.com/thehowl/go-osuapi/README.md
generated
vendored
Normal file
41
vendor/github.com/thehowl/go-osuapi/README.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# go-osuapi [](https://godoc.org/github.com/thehowl/go-osuapi) [](https://travis-ci.org/thehowl/go-osuapi) [](https://goreportcard.com/report/github.com/thehowl/go-osuapi)
|
||||
|
||||
go-osuapi is an osu! API library for Golang.
|
||||
|
||||
## Getting started
|
||||
|
||||
Everything is (more or less) well-documented at [godoc](https://godoc.org/github.com/thehowl/go-osuapi) - the methods that interest you most are probably those under [Client](https://godoc.org/github.com/thehowl/go-osuapi#Client). Also, [client_test.go](client_test.go) contains loads of examples on how you can use the package. If you still want to have an example to simply copypaste and then get straight to coding, well, there you go!
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/thehowl/go-osuapi.v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := osuapi.NewClient("Your API key https://osu.ppy.sh/p/api")
|
||||
beatmaps, err := c.GetBeatmaps(osuapi.GetBeatmapsOpts{
|
||||
BeatmapSetID: 332532,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("An error occurred: %v\n", err)
|
||||
return
|
||||
}
|
||||
for _, beatmap := range beatmaps {
|
||||
fmt.Printf("%s - %s [%s] https://osu.ppy.sh/b/%d\n", beatmap.Artist, beatmap.Title, beatmap.DiffName, beatmap.BeatmapID)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## I want more than that to explore how it works!
|
||||
|
||||
I've made [whosu](https://github.com/thehowl/whosu) for that purpose. Check it out.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Here's what you need to know:
|
||||
|
||||
* Always `go fmt` your code.
|
||||
* If you're writing a big and useful feature, make sure to appropriately write tests!
|
36
vendor/github.com/thehowl/go-osuapi/approved_status.go
generated
vendored
Normal file
36
vendor/github.com/thehowl/go-osuapi/approved_status.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package osuapi
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Approved statuses.
|
||||
const (
|
||||
StatusGraveyard ApprovedStatus = iota - 2
|
||||
StatusWIP
|
||||
StatusPending
|
||||
StatusRanked
|
||||
StatusApproved
|
||||
StatusQualified
|
||||
StatusLoved
|
||||
)
|
||||
|
||||
// ApprovedStatus - also known as ranked status - is the status of a beatmap.
|
||||
// Yeah, no shit, I know. It tells whether the beatmap is ranked, qualified,
|
||||
// graveyarded or other memes.
|
||||
type ApprovedStatus int
|
||||
|
||||
var approvedStatusesString = [...]string{
|
||||
"graveyard",
|
||||
"WIP",
|
||||
"pending",
|
||||
"ranked",
|
||||
"approved",
|
||||
"qualified",
|
||||
"loved",
|
||||
}
|
||||
|
||||
func (a ApprovedStatus) String() string {
|
||||
if a >= -2 && int(a)+2 < len(approvedStatusesString) {
|
||||
return approvedStatusesString[a+2]
|
||||
}
|
||||
return strconv.Itoa(int(a))
|
||||
}
|
66
vendor/github.com/thehowl/go-osuapi/client.go
generated
vendored
Normal file
66
vendor/github.com/thehowl/go-osuapi/client.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Client is an osu! API client that is able to make API requests.
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
key string
|
||||
}
|
||||
|
||||
// NewClient generates a new Client based on an API key.
|
||||
func NewClient(key string) *Client {
|
||||
c := &Client{&http.Client{}, key}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c Client) makerq(endpoint string, queryString url.Values) ([]byte, error) {
|
||||
queryString.Set("k", c.key)
|
||||
req, err := http.NewRequest("GET", "https://osu.ppy.sh/api/"+endpoint+"?"+queryString.Encode(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if we are rate limiting requests, then wait before making request
|
||||
if requestsAvailable != nil {
|
||||
<-requestsAvailable
|
||||
}
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
return data, err
|
||||
}
|
||||
|
||||
type testResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// Test makes sure the API is working (and the API key is valid).
|
||||
func (c Client) Test() error {
|
||||
resp, err := c.makerq("get_user", url.Values{
|
||||
"u": []string{
|
||||
"2",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var tr testResponse
|
||||
err = json.Unmarshal(resp, &tr)
|
||||
// Ignore cannot unmarshal stuff
|
||||
if err != nil && err.Error() != "json: cannot unmarshal array into Go value of type osuapi.testResponse" {
|
||||
return err
|
||||
}
|
||||
if tr.Error != "" {
|
||||
return errors.New("osuapi: " + tr.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
41
vendor/github.com/thehowl/go-osuapi/genre.go
generated
vendored
Normal file
41
vendor/github.com/thehowl/go-osuapi/genre.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package osuapi
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Genres
|
||||
const (
|
||||
GenreAny Genre = iota
|
||||
GenreUnspecified
|
||||
GenreVideoGame
|
||||
GenreAnime
|
||||
GenreRock
|
||||
GenrePop
|
||||
GenreOther
|
||||
GenreNovelty
|
||||
GenreHipHop Genre = iota + 1 // there's no 8, so we must manually increment it by one
|
||||
GenreElectronic
|
||||
)
|
||||
|
||||
// Genre is the genre of a beatmap's song.
|
||||
type Genre int
|
||||
|
||||
var genreString = [...]string{
|
||||
"any",
|
||||
"unspecified",
|
||||
"video game",
|
||||
"anime",
|
||||
"rock",
|
||||
"pop",
|
||||
"other",
|
||||
"novelty",
|
||||
"8",
|
||||
"hip hop",
|
||||
"electronic",
|
||||
}
|
||||
|
||||
func (g Genre) String() string {
|
||||
if g >= 0 && int(g) < len(genreString) {
|
||||
return genreString[g]
|
||||
}
|
||||
return strconv.Itoa(int(g))
|
||||
}
|
110
vendor/github.com/thehowl/go-osuapi/get_beatmaps.go
generated
vendored
Normal file
110
vendor/github.com/thehowl/go-osuapi/get_beatmaps.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetBeatmapsOpts is a struct containing the GET query string parameters to an
|
||||
// /api/get_beatmaps request.
|
||||
type GetBeatmapsOpts struct {
|
||||
Since *time.Time
|
||||
BeatmapSetID int
|
||||
BeatmapID int
|
||||
// If both UserID and Username are set, UserID will be used.
|
||||
UserID int
|
||||
Username string
|
||||
// Using a pointer because we MUST provide a way to make this parameter
|
||||
// optional, and it should be optional by default. This is because simply
|
||||
// doing != 0 won't work, because it wouldn't allow filtering with only
|
||||
// osu!std maps, and setting m=0 and not setting it it all makes the
|
||||
// difference between only allowing STD beatmaps and allowing beatmaps
|
||||
// from all modes.
|
||||
// Simply doing &osuapi.ModeOsuMania (or similiar) should do the trick,
|
||||
// should you need to use this field.
|
||||
// God was this comment long.
|
||||
Mode *Mode
|
||||
IncludeConverted bool
|
||||
BeatmapHash string
|
||||
Limit int
|
||||
}
|
||||
|
||||
// Beatmap is an osu! beatmap.
|
||||
type Beatmap struct {
|
||||
BeatmapSetID int `json:"beatmapset_id,string"`
|
||||
BeatmapID int `json:"beatmap_id,string"`
|
||||
Approved ApprovedStatus `json:"approved,string"`
|
||||
TotalLength int `json:"total_length,string"`
|
||||
HitLength int `json:"hit_length,string"`
|
||||
DiffName string `json:"version"`
|
||||
FileMD5 string `json:"file_md5"`
|
||||
CircleSize float64 `json:"diff_size,string"`
|
||||
OverallDifficulty float64 `json:"diff_overall,string"`
|
||||
ApproachRate float64 `json:"diff_approach,string"`
|
||||
HPDrain float64 `json:"diff_drain,string"`
|
||||
Mode Mode `json:"mode,string"`
|
||||
ApprovedDate MySQLDate `json:"approved_date"`
|
||||
LastUpdate MySQLDate `json:"last_update"`
|
||||
Artist string `json:"artist"`
|
||||
Title string `json:"title"`
|
||||
Creator string `json:"creator"`
|
||||
BPM float64 `json:"bpm,string"`
|
||||
Source string `json:"source"`
|
||||
Tags string `json:"tags"`
|
||||
Genre Genre `json:"genre_id,string"`
|
||||
Language Language `json:"language_id,string"`
|
||||
FavouriteCount int `json:"favourite_count,string"`
|
||||
Playcount int `json:"playcount,string"`
|
||||
Passcount int `json:"passcount,string"`
|
||||
MaxCombo int `json:"max_combo,string"`
|
||||
DifficultyRating float64 `json:"difficultyrating,string"`
|
||||
}
|
||||
|
||||
// GetBeatmaps makes a get_beatmaps request to the osu! API.
|
||||
func (c Client) GetBeatmaps(opts GetBeatmapsOpts) ([]Beatmap, error) {
|
||||
// setup of querystring values
|
||||
vals := url.Values{}
|
||||
switch {
|
||||
case opts.UserID != 0:
|
||||
vals.Add("u", strconv.Itoa(opts.UserID))
|
||||
vals.Add("type", "id")
|
||||
case opts.Username != "":
|
||||
vals.Add("u", opts.Username)
|
||||
vals.Add("type", "string")
|
||||
}
|
||||
if opts.Mode != nil {
|
||||
vals.Add("m", strconv.Itoa(int(*opts.Mode)))
|
||||
}
|
||||
if opts.BeatmapHash != "" {
|
||||
vals.Add("h", opts.BeatmapHash)
|
||||
}
|
||||
if opts.BeatmapID != 0 {
|
||||
vals.Add("b", strconv.Itoa(opts.BeatmapID))
|
||||
}
|
||||
if opts.BeatmapSetID != 0 {
|
||||
vals.Add("s", strconv.Itoa(opts.BeatmapSetID))
|
||||
}
|
||||
if opts.IncludeConverted {
|
||||
vals.Add("a", "1")
|
||||
}
|
||||
if opts.Since != nil {
|
||||
vals.Add("since", MySQLDate(*opts.Since).String())
|
||||
}
|
||||
if opts.Limit != 0 {
|
||||
vals.Add("limit", strconv.Itoa(opts.Limit))
|
||||
}
|
||||
|
||||
// actual request
|
||||
rawData, err := c.makerq("get_beatmaps", vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beatmaps := []Beatmap{}
|
||||
err = json.Unmarshal(rawData, &beatmaps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beatmaps, nil
|
||||
}
|
77
vendor/github.com/thehowl/go-osuapi/get_match.go
generated
vendored
Normal file
77
vendor/github.com/thehowl/go-osuapi/get_match.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Match is a multiplayer match.
|
||||
type Match struct {
|
||||
Info MatchInfo `json:"match"`
|
||||
Games []MatchGame `json:"games"`
|
||||
}
|
||||
|
||||
// MatchInfo contains useful information about a Match.
|
||||
type MatchInfo struct {
|
||||
MatchID int `json:"match_id,string"`
|
||||
Name string `json:"name"`
|
||||
StartTime MySQLDate `json:"start_time"`
|
||||
EndTime *MySQLDate `json:"end_time"`
|
||||
}
|
||||
|
||||
// MatchGame is a single beatmap played in the Match.
|
||||
type MatchGame struct {
|
||||
GameID int `json:"game_id,string"`
|
||||
StartTime MySQLDate `json:"start_time"`
|
||||
EndTime *MySQLDate `json:"end_time"`
|
||||
BeatmapID int `json:"beatmap_id,string"`
|
||||
PlayMode Mode `json:"play_mode,string"`
|
||||
// Refer to the wiki for information about what the three things below
|
||||
// are. I personally think that this information wouldn't be that
|
||||
// necessary to most people, and what is written on the wiki could be
|
||||
// outdated, thus I deemed useless making an appropriate "enum" (like
|
||||
// I did for Genre, Language and that stuff.)
|
||||
// You really can say I love writing long comments.
|
||||
MatchType int `json:"match_type,string"`
|
||||
ScoringType int `json:"scoring_type,string"`
|
||||
TeamType int `json:"team_type,string"`
|
||||
Mods Mods `json:"mods,string"`
|
||||
Scores []MatchGameScore `json:"scores"`
|
||||
}
|
||||
|
||||
// MatchGameScore is a single score done by an user in a specific Game of a
|
||||
// Match. I agree, these descriptions are quite confusing.
|
||||
type MatchGameScore struct {
|
||||
Slot int `json:"slot,string"`
|
||||
Team int `json:"team,string"`
|
||||
UserID int `json:"user_id,string"`
|
||||
Score int64 `json:"score,string"`
|
||||
MaxCombo int `json:"maxcombo,string"`
|
||||
// There should be Rank here, but Rank is not actually used. (always 0)
|
||||
Count50 int `json:"count50,string"`
|
||||
Count100 int `json:"count100,string"`
|
||||
Count300 int `json:"count300,string"`
|
||||
CountMiss int `json:"countmiss,string"`
|
||||
CountGeki int `json:"countgeki,string"`
|
||||
CountKatu int `json:"countkatu,string"`
|
||||
// There should also be Perfect here, but that seems to also not be used. (always 0)
|
||||
Pass OsuBool `json:"pass"`
|
||||
}
|
||||
|
||||
// GetMatch makes a get_match request to the osu! API.
|
||||
func (c Client) GetMatch(matchID int) (*Match, error) {
|
||||
vals := url.Values{
|
||||
"mp": []string{strconv.Itoa(matchID)},
|
||||
}
|
||||
rawData, err := c.makerq("get_match", vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
match := Match{}
|
||||
err = json.Unmarshal(rawData, &match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &match, nil
|
||||
}
|
57
vendor/github.com/thehowl/go-osuapi/get_replay.go
generated
vendored
Normal file
57
vendor/github.com/thehowl/go-osuapi/get_replay.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// GetReplayOpts are the options that MUST be used to fetch a replay.
|
||||
// ALL of the fields are **REQUIRED**, with an exception for UserID/Username,
|
||||
// of which only one is required.
|
||||
type GetReplayOpts struct {
|
||||
UserID int
|
||||
Username string
|
||||
Mode Mode
|
||||
BeatmapID int
|
||||
}
|
||||
|
||||
type replayResponse struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// GetReplay makes a get_replay request to the osu! API. Returns a reader from
|
||||
// which the replay can be retrieved.
|
||||
func (c Client) GetReplay(opts GetReplayOpts) (io.Reader, error) {
|
||||
vals := url.Values{}
|
||||
if opts.BeatmapID == 0 {
|
||||
return nil, errors.New("osuapi: BeatmapID MUST be set in GetReplayOpts")
|
||||
}
|
||||
vals.Add("m", strconv.Itoa(int(opts.Mode)))
|
||||
vals.Add("b", strconv.Itoa(opts.BeatmapID))
|
||||
switch {
|
||||
case opts.UserID != 0:
|
||||
vals.Add("u", strconv.Itoa(opts.UserID))
|
||||
vals.Add("type", "id")
|
||||
case opts.Username != "":
|
||||
vals.Add("u", opts.Username)
|
||||
vals.Add("type", "string")
|
||||
default:
|
||||
return nil, errors.New("osuapi: either UserID or Username MUST be set in GetReplayOpts")
|
||||
}
|
||||
data, err := c.makerq("get_replay", vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rr := replayResponse{}
|
||||
err = json.Unmarshal(data, &rr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader := bytes.NewBuffer([]byte(rr.Content))
|
||||
return base64.NewDecoder(base64.StdEncoding, reader), nil
|
||||
}
|
83
vendor/github.com/thehowl/go-osuapi/get_scores.go
generated
vendored
Normal file
83
vendor/github.com/thehowl/go-osuapi/get_scores.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// GetScoresOpts is a struct containing the GET query string parameters to an
|
||||
// /api/get_scores request.
|
||||
type GetScoresOpts struct {
|
||||
BeatmapID int
|
||||
// As usual, if both UserID and Username are set, UserID will override Username.
|
||||
UserID int
|
||||
Username string
|
||||
Mode Mode
|
||||
Mods *Mods // Pointer because must have the possibility to be 0 (nomod) but also nil (whatever is fine)
|
||||
Limit int
|
||||
}
|
||||
|
||||
// Score is an osu! score. Used in both get_scores, get_user_best and get_user_recent.
|
||||
type Score struct {
|
||||
Score int64 `json:"score,string"`
|
||||
MaxCombo int `json:"maxcombo,string"`
|
||||
Count50 int `json:"count50,string"`
|
||||
Count100 int `json:"count100,string"`
|
||||
Count300 int `json:"count300,string"`
|
||||
CountMiss int `json:"countmiss,string"`
|
||||
CountKatu int `json:"countkatu,string"`
|
||||
CountGeki int `json:"countgeki,string"`
|
||||
FullCombo OsuBool `json:"perfect,string"`
|
||||
Mods Mods `json:"enabled_mods,string"`
|
||||
UserID int `json:"user_id,string"`
|
||||
Date MySQLDate `json:"date"`
|
||||
Rank string `json:"rank"` // Rank = SSH, SS, SH, S, A, B, C, D
|
||||
PP float64 `json:"pp,string"`
|
||||
}
|
||||
|
||||
// GSScore is basically Score, with the exception it also has ScoreID.
|
||||
// (stands for Get Scores Score)
|
||||
type GSScore struct {
|
||||
ScoreID int64 `json:"score_id,string"`
|
||||
Username string `json:"username"`
|
||||
Score
|
||||
}
|
||||
|
||||
// GetScores makes a get_scores request to the osu! API.
|
||||
func (c Client) GetScores(opts GetScoresOpts) ([]GSScore, error) {
|
||||
// setup of querystring values
|
||||
vals := url.Values{}
|
||||
if opts.BeatmapID == 0 {
|
||||
return nil, errors.New("osuapi: BeatmapID must be set in GetScoresOpts")
|
||||
}
|
||||
vals.Add("b", strconv.Itoa(opts.BeatmapID))
|
||||
switch {
|
||||
case opts.UserID != 0:
|
||||
vals.Add("u", strconv.Itoa(opts.UserID))
|
||||
vals.Add("type", "id")
|
||||
case opts.Username != "":
|
||||
vals.Add("u", opts.Username)
|
||||
vals.Add("type", "string")
|
||||
}
|
||||
vals.Add("m", strconv.Itoa(int(opts.Mode)))
|
||||
if opts.Mods != nil {
|
||||
vals.Add("mods", strconv.Itoa(int(*opts.Mods)))
|
||||
}
|
||||
if opts.Limit != 0 {
|
||||
vals.Add("limit", strconv.Itoa(opts.Limit))
|
||||
}
|
||||
|
||||
// actual request
|
||||
rawData, err := c.makerq("get_scores", vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scores := []GSScore{}
|
||||
err = json.Unmarshal(rawData, &scores)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scores, nil
|
||||
}
|
98
vendor/github.com/thehowl/go-osuapi/get_user.go
generated
vendored
Normal file
98
vendor/github.com/thehowl/go-osuapi/get_user.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ErrNoSuchUser is returned when the requested user could not be found.
|
||||
var ErrNoSuchUser = errors.New("osuapi: no such user could be found")
|
||||
|
||||
// GetUserOpts is a struct containing the GET query string parameters to an
|
||||
// /api/get_user request.
|
||||
type GetUserOpts struct {
|
||||
// If both UserID and Username are set, UserID will be used.
|
||||
UserID int
|
||||
Username string
|
||||
Mode Mode
|
||||
EventDays int
|
||||
}
|
||||
|
||||
// User is an osu! user.
|
||||
type User struct {
|
||||
UserID int `json:"user_id,string"`
|
||||
Username string `json:"username"`
|
||||
Count300 int `json:"count300,string"`
|
||||
Count100 int `json:"count100,string"`
|
||||
Count50 int `json:"count50,string"`
|
||||
Playcount int `json:"playcount,string"`
|
||||
RankedScore int64 `json:"ranked_score,string"`
|
||||
TotalScore int64 `json:"total_score,string"`
|
||||
Rank int `json:"pp_rank,string"`
|
||||
Level float64 `json:"level,string"`
|
||||
PP float64 `json:"pp_raw,string"`
|
||||
Accuracy float64 `json:"accuracy,string"`
|
||||
CountSS int `json:"count_rank_ss,string"`
|
||||
CountS int `json:"count_rank_s,string"`
|
||||
CountA int `json:"count_rank_a,string"`
|
||||
Country string `json:"country"`
|
||||
CountryRank int `json:"pp_country_rank,string"`
|
||||
Events []Event `json:"events"`
|
||||
}
|
||||
|
||||
// Event is a notorious action an user has done recently.
|
||||
type Event struct {
|
||||
DisplayHTML string `json:"display_html"`
|
||||
BeatmapID int `json:"beatmap_id,string"`
|
||||
BeatmapsetID int `json:"beatmapset_id,string"`
|
||||
Date MySQLDate `json:"date"`
|
||||
Epicfactor int `json:"epicfactor,string"`
|
||||
}
|
||||
|
||||
// GetUser makes a get_user request to the osu! API.
|
||||
func (c Client) GetUser(opts GetUserOpts) (*User, error) {
|
||||
// setup of querystring values
|
||||
vals := url.Values{}
|
||||
switch {
|
||||
case opts.UserID != 0:
|
||||
vals.Add("u", strconv.Itoa(opts.UserID))
|
||||
vals.Add("type", "id")
|
||||
case opts.Username != "":
|
||||
vals.Add("u", opts.Username)
|
||||
vals.Add("type", "string")
|
||||
default:
|
||||
return nil, errors.New("osuapi: either UserID or Username must be set in GetUserOpts")
|
||||
}
|
||||
vals.Add("m", strconv.Itoa(int(opts.Mode)))
|
||||
if opts.EventDays != 0 {
|
||||
vals.Add("event_days", strconv.Itoa(opts.EventDays))
|
||||
}
|
||||
|
||||
// actual request
|
||||
rawData, err := c.makerq("get_user", vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := []User{}
|
||||
err = json.Unmarshal(rawData, &users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return nil, ErrNoSuchUser
|
||||
}
|
||||
return &users[0], nil
|
||||
}
|
||||
|
||||
// ToGetUserOpts converts an user to a GetUserOpts, so that it can be used
|
||||
// with GetUser. Note that this does not work very well. It won't auto-detect
|
||||
// the game mode, because the bloody osu! API does not return that in a
|
||||
// get_user response. So it will just assume you want the osu! standard data
|
||||
// and return that.
|
||||
func (u User) ToGetUserOpts() GetUserOpts {
|
||||
return GetUserOpts{
|
||||
UserID: u.UserID,
|
||||
}
|
||||
}
|
62
vendor/github.com/thehowl/go-osuapi/get_user_best.go
generated
vendored
Normal file
62
vendor/github.com/thehowl/go-osuapi/get_user_best.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// GetUserScoresOpts are the options that can be passed in GetUserBest or
|
||||
// in GetUserRecent; they use the same parameters.
|
||||
type GetUserScoresOpts struct {
|
||||
// You know it by now. UserID overrides Username.
|
||||
UserID int
|
||||
Username string
|
||||
Mode Mode
|
||||
Limit int
|
||||
}
|
||||
|
||||
// GUSScore is a score from get_user_best or get_user_recent. It differs from
|
||||
// normal Score by having a BeatmapID field. Stands for Get User Scores Score.
|
||||
// Yeah, I suck at choosing names. but that's what programming is all about,
|
||||
// after all.
|
||||
type GUSScore struct {
|
||||
BeatmapID int `json:"beatmap_id,string"`
|
||||
Score
|
||||
}
|
||||
|
||||
func (o GetUserScoresOpts) toValues() url.Values {
|
||||
vals := url.Values{}
|
||||
switch {
|
||||
case o.UserID != 0:
|
||||
vals.Add("u", strconv.Itoa(o.UserID))
|
||||
vals.Add("type", "id")
|
||||
case o.Username != "":
|
||||
vals.Add("u", o.Username)
|
||||
vals.Add("type", "string")
|
||||
}
|
||||
vals.Add("m", strconv.Itoa(int(o.Mode)))
|
||||
if o.Limit != 0 {
|
||||
vals.Add("limit", strconv.Itoa(o.Limit))
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// GetUserBest makes a get_user_best request to the osu! API.
|
||||
func (c Client) GetUserBest(opts GetUserScoresOpts) ([]GUSScore, error) {
|
||||
if opts.UserID == 0 && opts.Username == "" {
|
||||
return nil, errors.New("osuapi: must have either UserID or Username in GetUserScoresOpts")
|
||||
}
|
||||
|
||||
rawData, err := c.makerq("get_user_best", opts.toValues())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scores := []GUSScore{}
|
||||
err = json.Unmarshal(rawData, &scores)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scores, nil
|
||||
}
|
24
vendor/github.com/thehowl/go-osuapi/get_user_recent.go
generated
vendored
Normal file
24
vendor/github.com/thehowl/go-osuapi/get_user_recent.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// GetUserRecent makes a get_user_recent request to the osu! API.
|
||||
func (c Client) GetUserRecent(opts GetUserScoresOpts) ([]GUSScore, error) {
|
||||
if opts.UserID == 0 && opts.Username == "" {
|
||||
return nil, errors.New("osuapi: must have either UserID or Username in GetUserScoresOpts")
|
||||
}
|
||||
|
||||
rawData, err := c.makerq("get_user_recent", opts.toValues())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scores := []GUSScore{}
|
||||
err = json.Unmarshal(rawData, &scores)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scores, nil
|
||||
}
|
44
vendor/github.com/thehowl/go-osuapi/language.go
generated
vendored
Normal file
44
vendor/github.com/thehowl/go-osuapi/language.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package osuapi
|
||||
|
||||
import "strconv"
|
||||
|
||||
// Languages
|
||||
const (
|
||||
LanguageAny Language = iota
|
||||
LanguageOther
|
||||
LanguageEnglish
|
||||
LanguageJapanese
|
||||
LanguageChinese
|
||||
LanguageInstrumental
|
||||
LanguageKorean
|
||||
LanguageFrench
|
||||
LanguageGerman
|
||||
LanguageSwedish
|
||||
LanguageSpanish
|
||||
LanguageItalian
|
||||
)
|
||||
|
||||
// Language is the language of a beatmap's song.
|
||||
type Language int
|
||||
|
||||
var languageString = [...]string{
|
||||
"any",
|
||||
"other",
|
||||
"English",
|
||||
"Japanese",
|
||||
"Chinese",
|
||||
"instrumental",
|
||||
"Korean",
|
||||
"French",
|
||||
"German",
|
||||
"Swedish",
|
||||
"Spanish",
|
||||
"Italian",
|
||||
}
|
||||
|
||||
func (l Language) String() string {
|
||||
if l >= 0 && int(l) < len(languageString) {
|
||||
return languageString[l]
|
||||
}
|
||||
return strconv.Itoa(int(l))
|
||||
}
|
28
vendor/github.com/thehowl/go-osuapi/mode.go
generated
vendored
Normal file
28
vendor/github.com/thehowl/go-osuapi/mode.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package osuapi
|
||||
|
||||
import "strconv"
|
||||
|
||||
// osu! game modes IDs.
|
||||
const (
|
||||
ModeOsu Mode = iota
|
||||
ModeTaiko
|
||||
ModeCatchTheBeat
|
||||
ModeOsuMania
|
||||
)
|
||||
|
||||
// Mode is an osu! game mode.
|
||||
type Mode int
|
||||
|
||||
var modesString = [...]string{
|
||||
"osu!",
|
||||
"Taiko",
|
||||
"Catch the Beat",
|
||||
"osu!mania",
|
||||
}
|
||||
|
||||
func (m Mode) String() string {
|
||||
if m >= 0 && m <= 3 {
|
||||
return modesString[m]
|
||||
}
|
||||
return strconv.Itoa(int(m))
|
||||
}
|
111
vendor/github.com/thehowl/go-osuapi/mods.go
generated
vendored
Normal file
111
vendor/github.com/thehowl/go-osuapi/mods.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package osuapi
|
||||
|
||||
// Mods in the game.
|
||||
const (
|
||||
ModNoFail Mods = 1 << iota
|
||||
ModEasy
|
||||
ModNoVideo
|
||||
ModHidden
|
||||
ModHardRock
|
||||
ModSuddenDeath
|
||||
ModDoubleTime
|
||||
ModRelax
|
||||
ModHalfTime
|
||||
ModNightcore
|
||||
ModFlashlight
|
||||
ModAutoplay
|
||||
ModSpunOut
|
||||
ModRelax2
|
||||
ModPerfect
|
||||
ModKey4
|
||||
ModKey5
|
||||
ModKey6
|
||||
ModKey7
|
||||
ModKey8
|
||||
ModFadeIn
|
||||
ModRandom
|
||||
ModLastMod
|
||||
ModKey9
|
||||
ModKey10
|
||||
ModKey1
|
||||
ModKey3
|
||||
ModKey2
|
||||
ModFreeModAllowed = ModNoFail | ModEasy | ModHidden | ModHardRock | ModSuddenDeath | ModFlashlight | ModFadeIn | ModRelax | ModRelax2 | ModSpunOut | ModKeyMod
|
||||
ModKeyMod = ModKey4 | ModKey5 | ModKey6 | ModKey7 | ModKey8
|
||||
)
|
||||
|
||||
// Mods is a bitwise enum of mods used in a score.
|
||||
//
|
||||
// Mods may appear complicated to use for a beginner programmer. Fear not!
|
||||
// This is how hard they can get for creation of a mod combination:
|
||||
//
|
||||
// myModCombination := osuapi.ModHardRock | osuapi.ModDoubleTime | osuapi.ModHidden | osuapi.ModSpunOut
|
||||
//
|
||||
// As for checking that an existing mod comination is enabled:
|
||||
//
|
||||
// if modCombination&osuapi.ModHardRock != 0 {
|
||||
// // HardRock is enabled
|
||||
// }
|
||||
//
|
||||
// To learn more about bitwise operators, have a look at it on wikipedia:
|
||||
// https://en.wikipedia.org/wiki/Bitwise_operation#Bitwise_operators
|
||||
type Mods int
|
||||
|
||||
var modsString = [...]string{
|
||||
"NF",
|
||||
"EZ",
|
||||
"NV",
|
||||
"HD",
|
||||
"HR",
|
||||
"SD",
|
||||
"DT",
|
||||
"RX",
|
||||
"HT",
|
||||
"NC",
|
||||
"FL",
|
||||
"AU", // Auto.
|
||||
"SO",
|
||||
"AP", // Autopilot.
|
||||
"PF",
|
||||
"K4",
|
||||
"K5",
|
||||
"K6",
|
||||
"K7",
|
||||
"K8",
|
||||
"K9",
|
||||
"RN", // Random
|
||||
"LM", // LastMod. Cinema?
|
||||
"K9",
|
||||
"K0",
|
||||
"K1",
|
||||
"K3",
|
||||
"K2",
|
||||
}
|
||||
|
||||
// ParseMods parse a string with mods in the format "HDHRDT"
|
||||
func ParseMods(mods string) (m Mods) {
|
||||
modsSl := make([]string, len(mods)/2)
|
||||
for n, modPart := range mods {
|
||||
modsSl[n/2] += string(modPart)
|
||||
}
|
||||
for _, mod := range modsSl {
|
||||
for index, availableMod := range modsString {
|
||||
if availableMod == mod {
|
||||
m |= 1 << uint(index)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m Mods) String() (s string) {
|
||||
for i := 0; i < len(modsString); i++ {
|
||||
activated := 1&m == 1
|
||||
if activated {
|
||||
s += modsString[i]
|
||||
}
|
||||
m >>= 1
|
||||
}
|
||||
return
|
||||
}
|
37
vendor/github.com/thehowl/go-osuapi/mysql_date.go
generated
vendored
Normal file
37
vendor/github.com/thehowl/go-osuapi/mysql_date.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// MySQLDate is a wrapper for time.Time that can get a date from an osu! API JSON response.
|
||||
type MySQLDate time.Time
|
||||
|
||||
// UnmarshalJSON takes some JSON data and does some magic to transform it into a native time.Time.
|
||||
func (m *MySQLDate) UnmarshalJSON(data []byte) error {
|
||||
dataString := string(data)
|
||||
if dataString == "null" {
|
||||
m = nil
|
||||
return nil
|
||||
}
|
||||
inTimeLib, err := time.Parse(`"2006-01-02 15:04:05"`, dataString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = MySQLDate(inTimeLib)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts a MySQLDate into JSON.
|
||||
func (m MySQLDate) MarshalJSON() ([]byte, error) {
|
||||
return []byte("\"" + m.String() + "\""), nil
|
||||
}
|
||||
|
||||
// GetTime transforms a MySQLDate into a native time.Time.
|
||||
func (m MySQLDate) GetTime() time.Time {
|
||||
return time.Time(m)
|
||||
}
|
||||
|
||||
func (m MySQLDate) String() string {
|
||||
return m.GetTime().Format("2006-01-02 15:04:05")
|
||||
}
|
25
vendor/github.com/thehowl/go-osuapi/osubool.go
generated
vendored
Normal file
25
vendor/github.com/thehowl/go-osuapi/osubool.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package osuapi
|
||||
|
||||
// OsuBool is just a bool. It's used for unmarshaling of bools in the API that
|
||||
// are either `"1"` or `"0"`. thank mr peppy for the memes
|
||||
//
|
||||
// You can just use it in `if`s and other memes. Should you need to convert it
|
||||
// to a native bool, just do `bool(yourOsuBool)`
|
||||
type OsuBool bool
|
||||
|
||||
// UnmarshalJSON converts `"0"` to false and `"1"` to true.
|
||||
func (o *OsuBool) UnmarshalJSON(data []byte) error {
|
||||
if string(data) == `"0"` {
|
||||
*o = false
|
||||
return nil
|
||||
}
|
||||
*o = true
|
||||
return nil
|
||||
}
|
||||
// MarshalJSON does UnmarshalJSON the other way around.
|
||||
func (o OsuBool) MarshalJSON() ([]byte, error) {
|
||||
if o {
|
||||
return []byte(`"1"`), nil
|
||||
}
|
||||
return []byte(`"0"`), nil
|
||||
}
|
47
vendor/github.com/thehowl/go-osuapi/rate_limit.go
generated
vendored
Normal file
47
vendor/github.com/thehowl/go-osuapi/rate_limit.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package osuapi
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var every time.Duration
|
||||
var requestsAvailable chan struct{}
|
||||
var routStarted bool
|
||||
|
||||
// RateLimit allows you to set the maximum number of requests to do in a
|
||||
// minute to the osu! API.
|
||||
//
|
||||
// Please note that this function is NOT thread safe. It should be executed
|
||||
// only at the start of your program, and never after it.
|
||||
//
|
||||
// The reason for this is that creating a Mutex for a channel is just
|
||||
// absolutely ridiculous.
|
||||
func RateLimit(maxRequests int) {
|
||||
if maxRequests == 0 {
|
||||
requestsAvailable = nil
|
||||
}
|
||||
every = 60000 * time.Millisecond / time.Duration(maxRequests)
|
||||
requestsAvailable = make(chan struct{}, maxRequests)
|
||||
for {
|
||||
var b bool
|
||||
select {
|
||||
case requestsAvailable <- struct{}{}:
|
||||
// nothing, just keep on moving
|
||||
default:
|
||||
b = true
|
||||
}
|
||||
if b {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !routStarted {
|
||||
go requestIncreaser()
|
||||
}
|
||||
routStarted = true
|
||||
}
|
||||
func requestIncreaser() {
|
||||
for {
|
||||
time.Sleep(every)
|
||||
requestsAvailable <- struct{}{}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user