replace zxq.co/ripple/hanayo
This commit is contained in:
133
vendor/zxq.co/ripple/rippleapi/app/peppy/beatmap.go
vendored
Normal file
133
vendor/zxq.co/ripple/rippleapi/app/peppy/beatmap.go
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/thehowl/go-osuapi"
|
||||
"github.com/valyala/fasthttp"
|
||||
"zxq.co/ripple/rippleapi/common"
|
||||
)
|
||||
|
||||
// GetBeatmap retrieves general beatmap information.
|
||||
func GetBeatmap(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
var whereClauses []string
|
||||
var params []interface{}
|
||||
limit := strconv.Itoa(common.InString(1, query(c, "limit"), 500, 500))
|
||||
|
||||
// since value is not stored, silently ignore
|
||||
if query(c, "s") != "" {
|
||||
whereClauses = append(whereClauses, "beatmaps.beatmapset_id = ?")
|
||||
params = append(params, query(c, "s"))
|
||||
}
|
||||
if query(c, "b") != "" {
|
||||
whereClauses = append(whereClauses, "beatmaps.beatmap_id = ?")
|
||||
params = append(params, query(c, "b"))
|
||||
// b is unique, so change limit to 1
|
||||
limit = "1"
|
||||
}
|
||||
// creator is not stored, silently ignore u and type
|
||||
if query(c, "m") != "" {
|
||||
m := genmode(query(c, "m"))
|
||||
if m == "std" {
|
||||
// Since STD beatmaps are converted, all of the diffs must be != 0
|
||||
for _, i := range modes {
|
||||
whereClauses = append(whereClauses, "beatmaps.difficulty_"+i+" != 0")
|
||||
}
|
||||
} else {
|
||||
whereClauses = append(whereClauses, "beatmaps.difficulty_"+m+" != 0")
|
||||
if query(c, "a") == "1" {
|
||||
whereClauses = append(whereClauses, "beatmaps.difficulty_std = 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
if query(c, "h") != "" {
|
||||
whereClauses = append(whereClauses, "beatmaps.beatmap_md5 = ?")
|
||||
params = append(params, query(c, "h"))
|
||||
}
|
||||
|
||||
where := strings.Join(whereClauses, " AND ")
|
||||
if where != "" {
|
||||
where = "WHERE " + where
|
||||
}
|
||||
|
||||
rows, err := db.Query(`SELECT
|
||||
beatmapset_id, beatmap_id, ranked, hit_length,
|
||||
song_name, beatmap_md5, ar, od, bpm, playcount,
|
||||
passcount, max_combo, difficulty_std, difficulty_taiko, difficulty_ctb, difficulty_mania,
|
||||
latest_update
|
||||
|
||||
FROM beatmaps `+where+" ORDER BY id DESC LIMIT "+limit,
|
||||
params...)
|
||||
if err != nil {
|
||||
common.Err(c, err)
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
}
|
||||
|
||||
var bms []osuapi.Beatmap
|
||||
for rows.Next() {
|
||||
var (
|
||||
bm osuapi.Beatmap
|
||||
rawRankedStatus int
|
||||
rawName string
|
||||
rawLastUpdate common.UnixTimestamp
|
||||
diffs [4]float64
|
||||
)
|
||||
err := rows.Scan(
|
||||
&bm.BeatmapSetID, &bm.BeatmapID, &rawRankedStatus, &bm.HitLength,
|
||||
&rawName, &bm.FileMD5, &bm.ApproachRate, &bm.OverallDifficulty, &bm.BPM, &bm.Playcount,
|
||||
&bm.Passcount, &bm.MaxCombo, &diffs[0], &diffs[1], &diffs[2], &diffs[3],
|
||||
&rawLastUpdate,
|
||||
)
|
||||
if err != nil {
|
||||
common.Err(c, err)
|
||||
continue
|
||||
}
|
||||
bm.TotalLength = bm.HitLength
|
||||
bm.LastUpdate = osuapi.MySQLDate(rawLastUpdate)
|
||||
if rawRankedStatus >= 2 {
|
||||
bm.ApprovedDate = osuapi.MySQLDate(rawLastUpdate)
|
||||
}
|
||||
// zero value of ApprovedStatus == osuapi.StatusPending, so /shrug
|
||||
bm.Approved = rippleToOsuRankedStatus[rawRankedStatus]
|
||||
bm.Artist, bm.Title, bm.DiffName = parseDiffName(rawName)
|
||||
for i, diffVal := range diffs {
|
||||
if diffVal != 0 {
|
||||
bm.Mode = osuapi.Mode(i)
|
||||
bm.DifficultyRating = diffVal
|
||||
break
|
||||
}
|
||||
}
|
||||
bms = append(bms, bm)
|
||||
}
|
||||
|
||||
json(c, 200, bms)
|
||||
}
|
||||
|
||||
var rippleToOsuRankedStatus = map[int]osuapi.ApprovedStatus{
|
||||
0: osuapi.StatusPending,
|
||||
1: osuapi.StatusWIP, // it means "needs updating", as the one in the db needs to be updated, but whatever
|
||||
2: osuapi.StatusRanked,
|
||||
3: osuapi.StatusApproved,
|
||||
4: osuapi.StatusQualified,
|
||||
5: osuapi.StatusLoved,
|
||||
}
|
||||
|
||||
// buggy diffname parser
|
||||
func parseDiffName(name string) (author string, title string, diffName string) {
|
||||
parts := strings.SplitN(name, " - ", 2)
|
||||
author = parts[0]
|
||||
if len(parts) > 1 {
|
||||
title = parts[1]
|
||||
if s := strings.Index(title, " ["); s != -1 {
|
||||
diffName = title[s+2:]
|
||||
if len(diffName) != 0 && diffName[len(diffName)-1] == ']' {
|
||||
diffName = diffName[:len(diffName)-1]
|
||||
}
|
||||
title = title[:s]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
75
vendor/zxq.co/ripple/rippleapi/app/peppy/common.go
vendored
Normal file
75
vendor/zxq.co/ripple/rippleapi/app/peppy/common.go
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_json "encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/valyala/fasthttp"
|
||||
"zxq.co/ripple/rippleapi/common"
|
||||
)
|
||||
|
||||
var modes = []string{"std", "taiko", "ctb", "mania"}
|
||||
|
||||
var defaultResponse = []struct{}{}
|
||||
|
||||
func genmode(m string) string {
|
||||
i := genmodei(m)
|
||||
return modes[i]
|
||||
}
|
||||
func genmodei(m string) int {
|
||||
v := common.Int(m)
|
||||
if v > 3 || v < 0 {
|
||||
v = 0
|
||||
}
|
||||
return v
|
||||
}
|
||||
func rankable(m string) bool {
|
||||
x := genmodei(m)
|
||||
return x != 2
|
||||
}
|
||||
|
||||
func genUser(c *fasthttp.RequestCtx, db *sqlx.DB) (string, string) {
|
||||
var whereClause string
|
||||
var p string
|
||||
|
||||
// used in second case of switch
|
||||
s, err := strconv.Atoi(query(c, "u"))
|
||||
|
||||
switch {
|
||||
// We know for sure that it's an username.
|
||||
case query(c, "type") == "string":
|
||||
whereClause = "users.username_safe = ?"
|
||||
p = common.SafeUsername(query(c, "u"))
|
||||
// It could be an user ID, so we look for an user with that username first.
|
||||
case err == nil:
|
||||
err = db.QueryRow("SELECT id FROM users WHERE id = ? LIMIT 1", s).Scan(&p)
|
||||
if err == sql.ErrNoRows {
|
||||
// If no user with that userID were found, assume username.
|
||||
whereClause = "users.username_safe = ?"
|
||||
p = common.SafeUsername(query(c, "u"))
|
||||
} else {
|
||||
// An user with that userID was found. Thus it's an userID.
|
||||
whereClause = "users.id = ?"
|
||||
}
|
||||
// u contains letters, so it's an username.
|
||||
default:
|
||||
whereClause = "users.username_safe = ?"
|
||||
p = common.SafeUsername(query(c, "u"))
|
||||
}
|
||||
return whereClause, p
|
||||
}
|
||||
|
||||
func query(c *fasthttp.RequestCtx, s string) string {
|
||||
return string(c.QueryArgs().Peek(s))
|
||||
}
|
||||
|
||||
func json(c *fasthttp.RequestCtx, code int, data interface{}) {
|
||||
c.SetStatusCode(code)
|
||||
d, err := _json.Marshal(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.Write(d)
|
||||
}
|
12
vendor/zxq.co/ripple/rippleapi/app/peppy/match.go
vendored
Normal file
12
vendor/zxq.co/ripple/rippleapi/app/peppy/match.go
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Package peppy implements the osu! API as defined on the osu-api repository wiki (https://github.com/ppy/osu-api/wiki).
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// GetMatch retrieves general match information.
|
||||
func GetMatch(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
json(c, 200, defaultResponse)
|
||||
}
|
98
vendor/zxq.co/ripple/rippleapi/app/peppy/score.go
vendored
Normal file
98
vendor/zxq.co/ripple/rippleapi/app/peppy/score.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"zxq.co/ripple/rippleapi/common"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/valyala/fasthttp"
|
||||
"gopkg.in/thehowl/go-osuapi.v1"
|
||||
"zxq.co/x/getrank"
|
||||
)
|
||||
|
||||
// GetScores retrieve information about the top 100 scores of a specified beatmap.
|
||||
func GetScores(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
if query(c, "b") == "" {
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
}
|
||||
var beatmapMD5 string
|
||||
err := db.Get(&beatmapMD5, "SELECT beatmap_md5 FROM beatmaps WHERE beatmap_id = ? LIMIT 1", query(c, "b"))
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
case err != nil:
|
||||
common.Err(c, err)
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
}
|
||||
var sb = "scores.score"
|
||||
if rankable(query(c, "m")) {
|
||||
sb = "scores.pp"
|
||||
}
|
||||
var (
|
||||
extraWhere string
|
||||
extraParams []interface{}
|
||||
)
|
||||
if query(c, "u") != "" {
|
||||
w, p := genUser(c, db)
|
||||
extraWhere = "AND " + w
|
||||
extraParams = append(extraParams, p)
|
||||
}
|
||||
mods := common.Int(query(c, "mods"))
|
||||
rows, err := db.Query(`
|
||||
SELECT
|
||||
scores.id, scores.score, users.username, scores.300_count, scores.100_count,
|
||||
scores.50_count, scores.misses_count, scores.gekis_count, scores.katus_count,
|
||||
scores.max_combo, scores.full_combo, scores.mods, users.id, scores.time, scores.pp,
|
||||
scores.accuracy
|
||||
FROM scores
|
||||
INNER JOIN users ON users.id = scores.userid
|
||||
WHERE scores.completed = '3'
|
||||
AND users.privileges & 1 > 0
|
||||
AND scores.beatmap_md5 = ?
|
||||
AND scores.play_mode = ?
|
||||
AND scores.mods & ? = ?
|
||||
`+extraWhere+`
|
||||
ORDER BY `+sb+` DESC LIMIT `+strconv.Itoa(common.InString(1, query(c, "limit"), 100, 50)),
|
||||
append([]interface{}{beatmapMD5, genmodei(query(c, "m")), mods, mods}, extraParams...)...)
|
||||
if err != nil {
|
||||
common.Err(c, err)
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
}
|
||||
var results []osuapi.GSScore
|
||||
for rows.Next() {
|
||||
var (
|
||||
s osuapi.GSScore
|
||||
fullcombo bool
|
||||
mods int
|
||||
date common.UnixTimestamp
|
||||
accuracy float64
|
||||
)
|
||||
err := rows.Scan(
|
||||
&s.ScoreID, &s.Score.Score, &s.Username, &s.Count300, &s.Count100,
|
||||
&s.Count50, &s.CountMiss, &s.CountGeki, &s.CountKatu,
|
||||
&s.MaxCombo, &fullcombo, &mods, &s.UserID, &date, &s.PP,
|
||||
&accuracy,
|
||||
)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
common.Err(c, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
s.FullCombo = osuapi.OsuBool(fullcombo)
|
||||
s.Mods = osuapi.Mods(mods)
|
||||
s.Date = osuapi.MySQLDate(date)
|
||||
s.Rank = strings.ToUpper(getrank.GetRank(osuapi.Mode(genmodei(query(c, "m"))), s.Mods,
|
||||
accuracy, s.Count300, s.Count100, s.Count50, s.CountMiss))
|
||||
results = append(results, s)
|
||||
}
|
||||
json(c, 200, results)
|
||||
return
|
||||
}
|
64
vendor/zxq.co/ripple/rippleapi/app/peppy/user.go
vendored
Normal file
64
vendor/zxq.co/ripple/rippleapi/app/peppy/user.go
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Package peppy implements the osu! API as defined on the osu-api repository wiki (https://github.com/ppy/osu-api/wiki).
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/thehowl/go-osuapi"
|
||||
"github.com/valyala/fasthttp"
|
||||
"gopkg.in/redis.v5"
|
||||
"zxq.co/ripple/ocl"
|
||||
"zxq.co/ripple/rippleapi/common"
|
||||
)
|
||||
|
||||
// R is a redis client.
|
||||
var R *redis.Client
|
||||
|
||||
// GetUser retrieves general user information.
|
||||
func GetUser(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
if query(c, "u") == "" {
|
||||
json(c, 200, defaultResponse)
|
||||
return
|
||||
}
|
||||
var user osuapi.User
|
||||
whereClause, p := genUser(c, db)
|
||||
whereClause = "WHERE " + whereClause
|
||||
|
||||
mode := genmode(query(c, "m"))
|
||||
|
||||
err := db.QueryRow(fmt.Sprintf(
|
||||
`SELECT
|
||||
users.id, users.username,
|
||||
users_stats.playcount_%s, users_stats.ranked_score_%s, users_stats.total_score_%s,
|
||||
users_stats.pp_%s, users_stats.avg_accuracy_%s,
|
||||
users_stats.country
|
||||
FROM users
|
||||
LEFT JOIN users_stats ON users_stats.id = users.id
|
||||
%s
|
||||
LIMIT 1`,
|
||||
mode, mode, mode, mode, mode, whereClause,
|
||||
), p).Scan(
|
||||
&user.UserID, &user.Username,
|
||||
&user.Playcount, &user.RankedScore, &user.TotalScore,
|
||||
&user.PP, &user.Accuracy,
|
||||
&user.Country,
|
||||
)
|
||||
if err != nil {
|
||||
json(c, 200, defaultResponse)
|
||||
if err != sql.ErrNoRows {
|
||||
common.Err(c, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
user.Rank = int(R.ZRevRank("ripple:leaderboard:"+mode, strconv.Itoa(user.UserID)).Val()) + 1
|
||||
user.CountryRank = int(R.ZRevRank("ripple:leaderboard:"+mode+":"+strings.ToLower(user.Country), strconv.Itoa(user.UserID)).Val()) + 1
|
||||
user.Level = ocl.GetLevelPrecise(user.TotalScore)
|
||||
|
||||
json(c, 200, []osuapi.User{user})
|
||||
}
|
95
vendor/zxq.co/ripple/rippleapi/app/peppy/user_x.go
vendored
Normal file
95
vendor/zxq.co/ripple/rippleapi/app/peppy/user_x.go
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package peppy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/valyala/fasthttp"
|
||||
"gopkg.in/thehowl/go-osuapi.v1"
|
||||
"zxq.co/ripple/rippleapi/common"
|
||||
"zxq.co/x/getrank"
|
||||
)
|
||||
|
||||
// GetUserRecent retrieves an user's recent scores.
|
||||
func GetUserRecent(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
getUserX(c, db, "ORDER BY scores.time DESC", common.InString(1, query(c, "limit"), 50, 10))
|
||||
}
|
||||
|
||||
// GetUserBest retrieves an user's best scores.
|
||||
func GetUserBest(c *fasthttp.RequestCtx, db *sqlx.DB) {
|
||||
var sb string
|
||||
if rankable(query(c, "m")) {
|
||||
sb = "scores.pp"
|
||||
} else {
|
||||
sb = "scores.score"
|
||||
}
|
||||
getUserX(c, db, "AND completed = '3' ORDER BY "+sb+" DESC", common.InString(1, query(c, "limit"), 100, 10))
|
||||
}
|
||||
|
||||
func getUserX(c *fasthttp.RequestCtx, db *sqlx.DB, orderBy string, limit int) {
|
||||
whereClause, p := genUser(c, db)
|
||||
sqlQuery := fmt.Sprintf(
|
||||
`SELECT
|
||||
beatmaps.beatmap_id, scores.score, scores.max_combo,
|
||||
scores.300_count, scores.100_count, scores.50_count,
|
||||
scores.gekis_count, scores.katus_count, scores.misses_count,
|
||||
scores.full_combo, scores.mods, users.id, scores.time,
|
||||
scores.pp, scores.accuracy
|
||||
FROM scores
|
||||
LEFT JOIN beatmaps ON beatmaps.beatmap_md5 = scores.beatmap_md5
|
||||
LEFT JOIN users ON scores.userid = users.id
|
||||
WHERE %s AND scores.play_mode = ? AND users.privileges & 1 > 0
|
||||
%s
|
||||
LIMIT %d`, whereClause, orderBy, limit,
|
||||
)
|
||||
scores := make([]osuapi.GUSScore, 0, limit)
|
||||
m := genmodei(query(c, "m"))
|
||||
rows, err := db.Query(sqlQuery, p, m)
|
||||
if err != nil {
|
||||
json(c, 200, defaultResponse)
|
||||
common.Err(c, err)
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var (
|
||||
curscore osuapi.GUSScore
|
||||
rawTime common.UnixTimestamp
|
||||
acc float64
|
||||
fc bool
|
||||
mods int
|
||||
bid *int
|
||||
)
|
||||
err := rows.Scan(
|
||||
&bid, &curscore.Score.Score, &curscore.MaxCombo,
|
||||
&curscore.Count300, &curscore.Count100, &curscore.Count50,
|
||||
&curscore.CountGeki, &curscore.CountKatu, &curscore.CountMiss,
|
||||
&fc, &mods, &curscore.UserID, &rawTime,
|
||||
&curscore.PP, &acc,
|
||||
)
|
||||
if err != nil {
|
||||
json(c, 200, defaultResponse)
|
||||
common.Err(c, err)
|
||||
return
|
||||
}
|
||||
if bid == nil {
|
||||
curscore.BeatmapID = 0
|
||||
} else {
|
||||
curscore.BeatmapID = *bid
|
||||
}
|
||||
curscore.FullCombo = osuapi.OsuBool(fc)
|
||||
curscore.Mods = osuapi.Mods(mods)
|
||||
curscore.Date = osuapi.MySQLDate(rawTime)
|
||||
curscore.Rank = strings.ToUpper(getrank.GetRank(
|
||||
osuapi.Mode(m),
|
||||
curscore.Mods,
|
||||
acc,
|
||||
curscore.Count300,
|
||||
curscore.Count100,
|
||||
curscore.Count50,
|
||||
curscore.CountMiss,
|
||||
))
|
||||
scores = append(scores, curscore)
|
||||
}
|
||||
json(c, 200, scores)
|
||||
}
|
Reference in New Issue
Block a user