This commit is contained in:
Morgan Bazalgette
2017-01-14 18:42:10 +01:00
parent 41ee4c90b3
commit 3961e310b1
444 changed files with 179208 additions and 0 deletions

21
vendor/github.com/thehowl/go-osuapi/LICENSE generated vendored Normal file
View 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
View File

@@ -0,0 +1,41 @@
# go-osuapi [![docs](https://godoc.org/github.com/thehowl/go-osuapi?status.svg)](https://godoc.org/github.com/thehowl/go-osuapi) [![Build Status](https://travis-ci.org/thehowl/go-osuapi.svg?branch=master)](https://travis-ci.org/thehowl/go-osuapi) [![Go Report Card](https://goreportcard.com/badge/github.com/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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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{}{}
}
}