add bgeatmapget
This commit is contained in:
		
							
								
								
									
										186
									
								
								beatmapget/beatmapget.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								beatmapget/beatmapget.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | ||||
| // Package beatmapget is an helper package to retrieve beatmap information from | ||||
| // the osu! API, if the beatmap in the database is too old. | ||||
| package beatmapget | ||||
|  | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"git.zxq.co/ripple/rippleapi/common" | ||||
| 	"github.com/jmoiron/sqlx" | ||||
| 	"gopkg.in/thehowl/go-osuapi.v1" | ||||
| ) | ||||
|  | ||||
| // Expire is the duration after which a beatmap expires. | ||||
| const Expire = time.Hour * 12 | ||||
|  | ||||
| // DB is the database. | ||||
| var DB *sqlx.DB | ||||
|  | ||||
| // Client is the osu! api client to use | ||||
| var Client *osuapi.Client | ||||
|  | ||||
| // BeatmapDefiningQuality is the defining quality of the beatmap to be updated, | ||||
| // which is to say either the ID, the set ID or the md5 hash. | ||||
| type BeatmapDefiningQuality struct { | ||||
| 	ID     int | ||||
| 	MD5    string | ||||
| 	frozen bool | ||||
| 	ranked int | ||||
| } | ||||
|  | ||||
| func (b BeatmapDefiningQuality) String() string { | ||||
| 	if b.MD5 != "" { | ||||
| 		return "#/" + b.MD5 | ||||
| 	} | ||||
| 	if b.ID != 0 { | ||||
| 		return "b/" + strconv.Itoa(b.ID) | ||||
| 	} | ||||
| 	return "n/a" | ||||
| } | ||||
|  | ||||
| func (b BeatmapDefiningQuality) isSomethingSet() error { | ||||
| 	if b.ID == 0 && b.MD5 == "" { | ||||
| 		return errors.New("beatmapget: at least one field in BeatmapDefiningQuality must be set") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b BeatmapDefiningQuality) whereAndParams() (where string, params []interface{}) { | ||||
| 	var wheres []string | ||||
| 	if b.ID != 0 { | ||||
| 		wheres = append(wheres, "beatmap_id = ?") | ||||
| 		params = append(params, b.ID) | ||||
| 	} | ||||
| 	if b.MD5 != "" { | ||||
| 		wheres = append(wheres, "beatmap_md5 = ?") | ||||
| 		params = append(params, b.MD5) | ||||
| 	} | ||||
| 	where = strings.Join(wheres, " AND ") | ||||
| 	if where == "" { | ||||
| 		where = "1" | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // UpdateIfRequired updates the beatmap in the database if an update is required. | ||||
| func UpdateIfRequired(b BeatmapDefiningQuality) error { | ||||
| 	required, err := UpdateRequired(&b) | ||||
| 	if err != nil && err != sql.ErrNoRows { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !required { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return Update(b, err != sql.ErrNoRows) | ||||
| } | ||||
|  | ||||
| // UpdateRequired checks an update is required. If error is sql.ErrNoRows, | ||||
| // it means that the beatmap should be updated, and that there was not the | ||||
| // beatmap in the database previously. | ||||
| func UpdateRequired(b *BeatmapDefiningQuality) (bool, error) { | ||||
| 	if err := b.isSomethingSet(); err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	where, params := b.whereAndParams() | ||||
| 	var data struct { | ||||
| 		Difficulties [3]float64 | ||||
| 		Ranked       int | ||||
| 		Frozen       bool | ||||
| 		LatestUpdate common.UnixTimestamp | ||||
| 	} | ||||
| 	err := DB.QueryRow("SELECT difficulty_taiko, difficulty_ctb, difficulty_mania, ranked,"+ | ||||
| 		"ranked_status_freezed, latest_update FROM beatmaps WHERE "+ | ||||
| 		where+" LIMIT 1", params...). | ||||
| 		Scan( | ||||
| 			&data.Difficulties[0], &data.Difficulties[1], &data.Difficulties[2], | ||||
| 			&data.Ranked, &data.Frozen, &data.LatestUpdate, | ||||
| 		) | ||||
| 	b.frozen = data.Frozen | ||||
| 	if b.frozen { | ||||
| 		b.ranked = data.Ranked | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		if err == sql.ErrNoRows { | ||||
| 			return true, err | ||||
| 		} | ||||
| 		return false, err | ||||
| 	} | ||||
| 	if data.Difficulties[0] == 0 && data.Difficulties[1] == 0 && data.Difficulties[2] == 0 { | ||||
| 		return true, nil | ||||
| 	} | ||||
|  | ||||
| 	expire := Expire | ||||
| 	if data.Ranked == 2 { | ||||
| 		expire *= 6 | ||||
| 	} | ||||
|  | ||||
| 	if expire != 0 && time.Now().After(time.Time(data.LatestUpdate).Add(expire)) && | ||||
| 		!data.Frozen { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| // Update updates a beatmap. | ||||
| func Update(b BeatmapDefiningQuality, beatmapInDB bool) error { | ||||
| 	var data [4]osuapi.Beatmap | ||||
| 	for i := 0; i <= 3; i++ { | ||||
| 		mode := osuapi.Mode(i) | ||||
| 		beatmaps, err := Client.GetBeatmaps(osuapi.GetBeatmapsOpts{ | ||||
| 			BeatmapID:   b.ID, | ||||
| 			BeatmapHash: b.MD5, | ||||
| 			Mode:        &mode, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if len(beatmaps) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		data[i] = beatmaps[0] | ||||
| 	} | ||||
| 	var main *osuapi.Beatmap | ||||
| 	for _, el := range data { | ||||
| 		if el.FileMD5 != "" { | ||||
| 			main = &el | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if main == nil { | ||||
| 		return fmt.Errorf("beatmapget: beatmap %s not found", b.String()) | ||||
| 	} | ||||
| 	if beatmapInDB { | ||||
| 		w, p := b.whereAndParams() | ||||
| 		DB.MustExec("DELETE FROM beatmaps WHERE "+w, p...) | ||||
| 	} | ||||
| 	if b.frozen { | ||||
| 		main.Approved = osuapi.ApprovedStatus(b.ranked) | ||||
| 	} | ||||
| 	songName := fmt.Sprintf("%s - %s [%s]", main.Artist, main.Title, main.DiffName) | ||||
| 	_, err := DB.Exec(`INSERT INTO  | ||||
| 	beatmaps ( | ||||
| 		beatmap_id, beatmapset_id, beatmap_md5, | ||||
| 		song_name, ar, od, difficulty_std, difficulty_taiko, | ||||
| 		difficulty_ctb, difficulty_mania, max_combo, hit_length, | ||||
| 		bpm, ranked, latest_update, ranked_status_freezed | ||||
| 	)  | ||||
| 	VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, | ||||
| 		main.BeatmapID, main.BeatmapSetID, main.FileMD5, | ||||
| 		songName, main.ApproachRate, main.OverallDifficulty, data[0].DifficultyRating, data[1].DifficultyRating, | ||||
| 		data[2].DifficultyRating, data[3].DifficultyRating, main.MaxCombo, main.HitLength, | ||||
| 		int(main.BPM), main.Approved, time.Now().Unix(), b.frozen, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	osuapi.RateLimit(200) | ||||
| } | ||||
							
								
								
									
										63
									
								
								beatmapget/fullset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								beatmapget/fullset.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| package beatmapget | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"git.zxq.co/ripple/rippleapi/common" | ||||
| 	"gopkg.in/thehowl/go-osuapi.v1" | ||||
| ) | ||||
|  | ||||
| // Set checks if an update is required for all beatmaps in a set. | ||||
| func Set(s int) error { | ||||
| 	var ( | ||||
| 		lastUpdated common.UnixTimestamp | ||||
| 		ranked      int | ||||
| 	) | ||||
| 	err := DB.QueryRow("SELECT last_updated, ranked FROM beatmaps WHERE beatmapset_id = ? LIMIT 1", s). | ||||
| 		Scan(&lastUpdated, &ranked) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return set(s, lastUpdated, ranked) | ||||
| } | ||||
|  | ||||
| // Beatmap check if an update is required for all beatmaps in the set | ||||
| // containing this beatmap. | ||||
| func Beatmap(b int) error { | ||||
| 	var ( | ||||
| 		setID       int | ||||
| 		lastUpdated common.UnixTimestamp | ||||
| 		ranked      int | ||||
| 	) | ||||
| 	err := DB.QueryRow("SELECT beatmapset_id, last_updated, ranked FROM beatmaps WHERE beatmap_id = ? LIMIT 1", b). | ||||
| 		Scan(&setID, &lastUpdated, &ranked) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return set(setID, lastUpdated, ranked) | ||||
| } | ||||
|  | ||||
| func set(s int, updated common.UnixTimestamp, ranked int) error { | ||||
| 	expire := Expire | ||||
| 	if ranked == 2 { | ||||
| 		expire *= 6 | ||||
| 	} | ||||
| 	if time.Now().Before(time.Time(updated).Add(expire)) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	beatmaps, err := Client.GetBeatmaps(osuapi.GetBeatmapsOpts{ | ||||
| 		BeatmapSetID: s, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, beatmap := range beatmaps { | ||||
| 		err := UpdateIfRequired(BeatmapDefiningQuality{ | ||||
| 			ID: beatmap.BeatmapID, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -21,6 +21,7 @@ type Conf struct { | ||||
| 	HanayoKey              string | ||||
| 	BeatmapRequestsPerUser int | ||||
| 	RankQueueSize          int | ||||
| 	OsuAPIKey              string | ||||
| } | ||||
|  | ||||
| var cachedConf *Conf | ||||
|   | ||||
							
								
								
									
										6
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.go
									
									
									
									
									
								
							| @@ -7,11 +7,13 @@ import ( | ||||
| 	"syscall" | ||||
|  | ||||
| 	"git.zxq.co/ripple/rippleapi/app" | ||||
| 	"git.zxq.co/ripple/rippleapi/beatmapget" | ||||
| 	"git.zxq.co/ripple/rippleapi/common" | ||||
| 	"git.zxq.co/ripple/schiavolib" | ||||
| 	// Golint pls dont break balls | ||||
| 	_ "github.com/go-sql-driver/mysql" | ||||
| 	"github.com/jmoiron/sqlx" | ||||
| 	"gopkg.in/thehowl/go-osuapi.v1" | ||||
| ) | ||||
|  | ||||
| // Version is the git hash of the application. Do not edit. This is | ||||
| @@ -54,6 +56,10 @@ func main() { | ||||
| 		schiavo.Bunker.Send(err.Error()) | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|  | ||||
| 	beatmapget.Client = osuapi.NewClient(conf.OsuAPIKey) | ||||
| 	beatmapget.DB = db | ||||
|  | ||||
| 	engine := app.Start(conf, db) | ||||
|  | ||||
| 	startuato(engine) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user