update
This commit is contained in:
parent
24c9f21743
commit
1df8b395ce
5 changed files with 207 additions and 21 deletions
86
bot.go
86
bot.go
|
@ -17,6 +17,7 @@ type Bot struct {
|
||||||
*discordgo.Session
|
*discordgo.Session
|
||||||
mentionRe *regexp.Regexp
|
mentionRe *regexp.Regexp
|
||||||
db *Db
|
db *Db
|
||||||
|
api *Osuapi
|
||||||
requests chan int
|
requests chan int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ func NewBot(token string, db *Db, requests chan int) (bot *Bot, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bot = &Bot{s, re, db, requests}
|
bot = &Bot{s, re, db, db.api, requests}
|
||||||
s.AddHandler(bot.errWrap(bot.newMessageHandler))
|
s.AddHandler(bot.errWrap(bot.newMessageHandler))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -66,6 +67,89 @@ func (bot *Bot) errWrap(fn interface{}) interface{} {
|
||||||
return newFunc.Interface()
|
return newFunc.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bot *Bot) NotifyNewEvent(channelId string, newMaps []Event) (err error) {
|
||||||
|
for _, event := range newMaps {
|
||||||
|
var (
|
||||||
|
gotBeatmapInfo = false
|
||||||
|
beatmapSet Beatmapset
|
||||||
|
gotDownloadedBeatmap = false
|
||||||
|
downloadedBeatmap BeatmapsetDownloaded
|
||||||
|
)
|
||||||
|
beatmapSet, err = bot.getBeatmapsetInfo(event)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("failed to retrieve beatmap info:", err)
|
||||||
|
} else {
|
||||||
|
gotBeatmapInfo = true
|
||||||
|
downloadedBeatmap, err = bot.downloadBeatmap(&beatmapSet)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("failed to download beatmap:", err)
|
||||||
|
} else {
|
||||||
|
gotDownloadedBeatmap = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("BEATMAP SET", beatmapSet)
|
||||||
|
embed := &discordgo.MessageEmbed{
|
||||||
|
URL: "https://osu.ppy.sh" + event.Beatmapset.URL,
|
||||||
|
Title: event.Type + ": " + event.Beatmapset.Title,
|
||||||
|
Timestamp: event.CreatedAt,
|
||||||
|
Footer: &discordgo.MessageEmbedFooter{
|
||||||
|
Text: fmt.Sprintf("Event ID: %d", event.ID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if gotBeatmapInfo {
|
||||||
|
embed.Author = &discordgo.MessageEmbedAuthor{
|
||||||
|
URL: "https://osu.ppy.sh/u/" + strconv.Itoa(beatmapSet.UserId),
|
||||||
|
Name: beatmapSet.Creator,
|
||||||
|
IconURL: fmt.Sprintf(
|
||||||
|
"https://a.ppy.sh/%d?%d.png",
|
||||||
|
beatmapSet.UserId,
|
||||||
|
time.Now().Unix,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
embed.Thumbnail = &discordgo.MessageEmbedThumbnail{
|
||||||
|
URL: beatmapSet.Covers.SlimCover2x,
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotDownloadedBeatmap {
|
||||||
|
log.Println(downloadedBeatmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bot.ChannelMessageSendEmbed(channelId, embed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type BeatmapsetDownloaded struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bot *Bot) downloadBeatmap(beatmapSet *Beatmapset) (downloadedBeatmap BeatmapsetDownloaded, err error) {
|
||||||
|
beatmapFile, err := bot.api.BeatmapsetDownload(beatmapSet.Id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadedBeatmap.Path = beatmapFile
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bot *Bot) getBeatmapsetInfo(event Event) (beatmapSet Beatmapset, err error) {
|
||||||
|
beatmapSetId, err := strconv.Atoi(strings.TrimPrefix(event.Beatmapset.URL, "/s/"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("beatmap set id", beatmapSetId)
|
||||||
|
beatmapSet, err = bot.api.GetBeatmapSet(beatmapSetId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (bot *Bot) newMessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) (err error) {
|
func (bot *Bot) newMessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) (err error) {
|
||||||
mentionsMe := false
|
mentionsMe := false
|
||||||
for _, user := range m.Mentions {
|
for _, user := range m.Mentions {
|
||||||
|
|
|
@ -12,6 +12,7 @@ type Config struct {
|
||||||
BotToken string `toml:"bot_token"`
|
BotToken string `toml:"bot_token"`
|
||||||
ClientId int `toml:"client_id"`
|
ClientId int `toml:"client_id"`
|
||||||
ClientSecret string `toml:"client_secret"`
|
ClientSecret string `toml:"client_secret"`
|
||||||
|
Repos string `toml:"repos"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadConfig(path string) (config Config, err error) {
|
func ReadConfig(path string) (config Config, err error) {
|
||||||
|
|
47
models.go
47
models.go
|
@ -1,31 +1,66 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
CountryCode string `json:"country_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Beatmapset struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
|
||||||
|
Artist string `json:"artist"`
|
||||||
|
ArtistUnicode string `json:"artist_unicode"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
TitleUnicode string `json:"title_unicode"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
UserId int `json:"user_id"`
|
||||||
|
|
||||||
|
Covers BeatmapCovers `json:"covers"`
|
||||||
|
Beatmaps []Beatmap `json:"beatmaps,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Beatmap struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
DifficultyRating float64 `json:"difficulty_rating"`
|
||||||
|
DifficultyName string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BeatmapCovers struct {
|
||||||
|
Cover string `json:"cover"`
|
||||||
|
Cover2x string `json:"cover@2x"`
|
||||||
|
Card string `json:"card"`
|
||||||
|
Card2x string `json:"card@2x"`
|
||||||
|
SlimCover string `json:"slimcover"`
|
||||||
|
SlimCover2x string `json:"slimcover@2x"`
|
||||||
|
}
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
// type: achievement
|
// type: achievement
|
||||||
Achievement Achievement `json:"achievement,omitempty"`
|
Achievement EventAchievement `json:"achievement,omitempty"`
|
||||||
|
|
||||||
// type: beatmapsetApprove
|
// type: beatmapsetApprove
|
||||||
// type: beatmapsetDelete
|
// type: beatmapsetDelete
|
||||||
// type: beatmapsetRevive
|
// type: beatmapsetRevive
|
||||||
// type: beatmapsetUpdate
|
// type: beatmapsetUpdate
|
||||||
// type: beatmapsetUpload
|
// type: beatmapsetUpload
|
||||||
Beatmapset Beatmapset `json:"beatmapset,omitempty"`
|
Beatmapset EventBeatmapset `json:"beatmapset,omitempty"`
|
||||||
|
|
||||||
User User `json:"user,omitempty"`
|
User EventUser `json:"user,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Achievement struct{}
|
type EventAchievement struct{}
|
||||||
|
|
||||||
type Beatmapset struct {
|
type EventBeatmapset struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type EventUser struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
PreviousUsername string `json:"previousUsername,omitempty"`
|
PreviousUsername string `json:"previousUsername,omitempty"`
|
||||||
|
|
79
osuapi.go
79
osuapi.go
|
@ -4,9 +4,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -64,7 +66,7 @@ func (api *Osuapi) Token() (token string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Osuapi) Request(action string, url string, result interface{}) (err error) {
|
func (api *Osuapi) Request0(action string, url string) (resp *http.Response, err error) {
|
||||||
err = api.lock.Acquire(context.TODO(), 1)
|
err = api.lock.Acquire(context.TODO(), 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -82,10 +84,36 @@ func (api *Osuapi) Request(action string, url string, result interface{}) (err e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err = http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
var respBody []byte
|
||||||
|
respBody, err = ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fmt.Errorf("not 200: %s", string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// release the lock after 1 minute
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
api.lock.Release(1)
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Osuapi) Request(action string, url string, result interface{}) (err error) {
|
||||||
|
resp, err := api.Request0(action, url)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -96,11 +124,48 @@ func (api *Osuapi) Request(action string, url string, result interface{}) (err e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the lock after 1 minute
|
return
|
||||||
go func() {
|
}
|
||||||
time.Sleep(time.Minute)
|
|
||||||
api.lock.Release(1)
|
func (api *Osuapi) GetBeatmapSet(beatmapSetId int) (beatmapSet Beatmapset, err error) {
|
||||||
}()
|
url := fmt.Sprintf("/beatmapsets/%d", beatmapSetId)
|
||||||
|
err = api.Request("GET", url, &beatmapSet)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Osuapi) BeatmapsetDownload(beatmapSetId int) (path string, err error) {
|
||||||
|
url := fmt.Sprintf("/beatmapsets/%d/download", beatmapSetId)
|
||||||
|
resp, err := api.Request0("GET", url)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := ioutil.TempFile(os.TempDir(), "beatmapsetDownload")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(file, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
path = file.Name()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Osuapi) GetUser(userId int) (user User, err error) {
|
||||||
|
url := fmt.Sprintf("/users/%d", userId)
|
||||||
|
err = api.Request("GET", url, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
scrape.go
15
scrape.go
|
@ -23,9 +23,7 @@ func RunScraper(bot *Bot, db *Db, api *Osuapi, requests chan int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
db.IterTrackingChannels(userId, func(channelId string) error {
|
db.IterTrackingChannels(userId, func(channelId string) error {
|
||||||
for _, beatmap := range newMaps {
|
bot.NotifyNewEvent(channelId, newMaps)
|
||||||
bot.ChannelMessageSend(channelId, fmt.Sprintf("new beatmap event [%s](%s)", beatmap.Title, beatmap.URL))
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -37,10 +35,10 @@ func RunScraper(bot *Bot, db *Db, api *Osuapi, requests chan int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewMaps(db *Db, api *Osuapi, userId int) (newMaps []Beatmapset, err error) {
|
func getNewMaps(db *Db, api *Osuapi, userId int) (newMaps []Event, err error) {
|
||||||
// see if there's a last event
|
// see if there's a last event
|
||||||
hasLastEvent, lastEventId := db.MapperLastEvent(userId)
|
hasLastEvent, lastEventId := db.MapperLastEvent(userId)
|
||||||
newMaps = make([]Beatmapset, 0)
|
newMaps = make([]Event, 0)
|
||||||
var (
|
var (
|
||||||
events []Event
|
events []Event
|
||||||
newLatestEvent = 0
|
newLatestEvent = 0
|
||||||
|
@ -75,7 +73,7 @@ func getNewMaps(db *Db, api *Osuapi, userId int) (newMaps []Beatmapset, err erro
|
||||||
if event.Type == "beatmapsetUpload" ||
|
if event.Type == "beatmapsetUpload" ||
|
||||||
event.Type == "beatmapsetRevive" ||
|
event.Type == "beatmapsetRevive" ||
|
||||||
event.Type == "beatmapsetUpdate" {
|
event.Type == "beatmapsetUpdate" {
|
||||||
newMaps = append(newMaps, event.Beatmapset)
|
newMaps = append(newMaps, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,11 +95,14 @@ func getNewMaps(db *Db, api *Osuapi, userId int) (newMaps []Beatmapset, err erro
|
||||||
if event.Type == "beatmapsetUpload" ||
|
if event.Type == "beatmapsetUpload" ||
|
||||||
event.Type == "beatmapsetRevive" ||
|
event.Type == "beatmapsetRevive" ||
|
||||||
event.Type == "beatmapsetUpdate" {
|
event.Type == "beatmapsetUpdate" {
|
||||||
newMaps = append(newMaps, event.Beatmapset)
|
newMaps = append(newMaps, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: debug
|
||||||
|
// updateLatestEvent = false
|
||||||
|
|
||||||
if updateLatestEvent {
|
if updateLatestEvent {
|
||||||
err = db.UpdateMapperLatestEvent(userId, newLatestEvent)
|
err = db.UpdateMapperLatestEvent(userId, newLatestEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Add table
Reference in a new issue