diff --git a/bot/downloader.go b/bot/downloader.go deleted file mode 100644 index 57a1ecb..0000000 --- a/bot/downloader.go +++ /dev/null @@ -1,160 +0,0 @@ -package bot - -import ( - "context" - "fmt" - "io" - "net/http" - "os" - "time" -) - -const userAgent = `NeteaseMusic/6.5.0.1575377963(164);Dalvik/2.1.0 (Linux; U; Android 9; MIX 2 MIUI/V12.0.1.0.PDECNXM)` - -// HttpDownloader 下载数据 -type HttpDownloader struct { - url string - filename string - contentLength int - // 是否支持断点续传 - acceptRanges bool - // 同时下载线程数 - numThreads int -} - -// 新建下载任务 -func newDownloader(url string, filename string, numThreads int) (*HttpDownloader, error) { - res, err := http.Head(url) - if err != nil { - return nil, err - } - httpDownload := new(HttpDownloader) - httpDownload.url = url - httpDownload.contentLength = int(res.ContentLength) - httpDownload.numThreads = numThreads - httpDownload.filename = filename - if len(res.Header["Accept-Ranges"]) != 0 && res.Header["Accept-Ranges"][0] == "bytes" { - httpDownload.acceptRanges = true - } else { - httpDownload.acceptRanges = false - } - return httpDownload, nil -} - -// 下载综合调度 -func (h *HttpDownloader) download() (err error) { - f, err := os.Create(cacheDir + "/" + h.filename) - if err != nil { - return err - } - defer func(f *os.File) { - e := f.Close() - if e != nil { - err = fmt.Errorf("%v", e) - } - }(f) - errChan := make(chan error, h.numThreads) - if h.acceptRanges == false || h.numThreads <= 1 { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(downloaderTimeout)*time.Second) - defer cancel() - req, err := http.NewRequestWithContext(ctx, "GET", h.url, nil) - if err != nil { - return err - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - err = save2file(cacheDir+"/"+h.filename, 0, resp) - if err != nil { - return err - } - } else { - // 启动协程开始多线程下载 - for _, ranges := range h.split() { - go func(start, end int) { - errChan <- h.start(start, end) - }(ranges[0], ranges[1]) - } - // 下载错误及超时检测 - for i := 0; i < h.numThreads; i++ { - select { - case err := <-errChan: - if err != nil { - return err - } - } - } - } - return nil -} - -// 下载文件分段 -func (h *HttpDownloader) split() [][]int { - var ranges [][]int - blockSize := h.contentLength / h.numThreads - for i := 0; i < h.numThreads; i++ { - var start = i * blockSize - var end = (i+1)*blockSize - 1 - if i == h.numThreads-1 { - end = h.contentLength - 1 - } - ranges = append(ranges, []int{start, end}) - } - return ranges -} - -// 多线程下载 -func (h *HttpDownloader) start(start, end int) (err error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(downloaderTimeout)*time.Second) - defer cancel() - req, err := http.NewRequestWithContext(ctx, "GET", h.url, nil) - if err != nil { - return err - } - req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", start, end)) - req.Header.Set("User-Agent", userAgent) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer func(Body io.ReadCloser) { - e := Body.Close() - if e != nil { - err = fmt.Errorf("%v", err) - } - }(resp.Body) - err = save2file(cacheDir+"/"+h.filename, int64(start), resp) - if err != nil { - return err - } - return nil -} - -// 保存文件 -func save2file(filename string, offset int64, resp *http.Response) error { - f, err := os.OpenFile(filename, os.O_WRONLY, 0660) - if err != nil { - return err - } - _, err = f.Seek(offset, 0) - if err != nil { - return err - } - defer func(f *os.File) { - e := f.Close() - if e != nil { - err = fmt.Errorf("%v", e) - } - }(f) - content, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - _, err = f.Write(content) - if err != nil { - return err - } - return nil -} diff --git a/bot/init.go b/bot/init.go index 1e4db84..fef63c7 100644 --- a/bot/init.go +++ b/bot/init.go @@ -90,6 +90,8 @@ via @%s` fetchInfoFailed = `获取歌曲信息失败` waitForDown = `等待下载中...` downloading = `下载中...` + downloadStatus = " %s\n%.2fMB/%.2fMB %d%%" + redownloading = `下载失败,尝试重新下载中...` uploading = `下载完成, 发送中...` md5VerFailed = "MD5校验失败" reTrying = "尝试重新下载中 (%d/%d)" diff --git a/bot/processMusic.go b/bot/processMusic.go index e5eff4f..aad5869 100644 --- a/bot/processMusic.go +++ b/bot/processMusic.go @@ -6,12 +6,14 @@ import ( "net/http" "os" "path" + "strconv" "strings" "time" marker "github.com/XiaoMengXinX/163KeyMarker" "github.com/XiaoMengXinX/Music163Api-Go/api" "github.com/XiaoMengXinX/Music163Api-Go/types" + downloader "github.com/XiaoMengXinX/SimpleDownloader" "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -21,6 +23,15 @@ import ( var musicLimiter = make(chan bool, 4) func processMusic(musicID int, message tgbotapi.Message, bot *tgbotapi.BotAPI) (err error) { + d := downloader.NewDownloader().SetSavePath(cacheDir).SetBreakPoint(true) + + timeout, _ := strconv.Atoi(config["DownloadTimeout"]) + if timeout != 0 { + d.SetTimeOut(time.Duration(int64(timeout)) * time.Second) + } else { + d.SetTimeOut(60 * time.Second) // 默认超时时间为 60 秒 + } + defer func() { e := recover() if e != nil { @@ -185,50 +196,66 @@ func processMusic(musicID int, message tgbotapi.Message, bot *tgbotapi.BotAPI) ( return err } - timeStamp := time.Now().UnixMicro() + hostReplacer := strings.NewReplacer("m8.", "m7.", "m801.", "m701.", "m804.", "m701.", "m704.", "m701.") - d, err := newDownloader(url, fmt.Sprintf("%d-%s", timeStamp, path.Base(url)), 8) - if err != nil { - sendFailed(err) + timeStamp := time.Now().UnixMicro() + musicFileName := fmt.Sprintf("%d-%s", timeStamp, path.Base(url)) + + task, _ := d.NewDownloadTask(url) + host := task.GetHostName() + task.ReplaceHostName(hostReplacer.Replace(host)).ForceHttps().ForceMultiThread() + errCh := task.SetFileName(musicFileName).DownloadWithChannel() + + updateStatus := func(task *downloader.DownloadTask, ch chan error, statusText string) (err error) { + var lastUpdateTime int64 + loop: + for { + select { + case err = <-ch: + break loop + default: + writtenBytes := task.GetWrittenBytes() + if task.GetFileSize() == 0 || writtenBytes == 0 || time.Now().Unix()-lastUpdateTime < 5 { + continue + } + editMsg = tgbotapi.NewEditMessageText(message.Chat.ID, msgResult.MessageID, fmt.Sprintf(musicInfoMsg+statusText+downloadStatus, songInfo.SongName, songInfo.SongAlbum, songInfo.FileExt, float64(songInfo.MusicSize)/1024/1024, task.CalculateSpeed(time.Millisecond*500), float64(writtenBytes)/1024/1024, float64(task.GetFileSize())/1024/1024, (writtenBytes*100)/task.GetFileSize())) + _, _ = bot.Send(editMsg) + lastUpdateTime = time.Now().Unix() + } + } return err } - var isMD5Verified = false - for i := 0; i < maxRetryTimes && songURL.Data[0].Md5 != ""; i++ { - err = d.download() - if err != nil && !isTimeout(err) { - sendFailed(err) - return err - } else if err != nil && isTimeout(err) { - sendFailed(fmt.Errorf(downloadTimeout + "\n" + retryLater)) - return err - } - - if isMD5Verified, err = verifyMD5(cacheDir+"/"+fmt.Sprintf("%d-%s", timeStamp, path.Base(url)), songURL.Data[0].Md5); !isMD5Verified && config["AutoRetry"] != "false" { - sendFailed(fmt.Errorf("%s\n"+reTrying, err, i+1, maxRetryTimes)) - err := os.Remove(cacheDir + "/" + fmt.Sprintf("%d-%s", timeStamp, path.Base(url))) + err = updateStatus(task, errCh, downloading) + if err != nil { + if config["ReverseProxy"] != "" { + ch := task.WithResolvedIpOnHost(config["ReverseProxy"]).DownloadWithChannel() + err = updateStatus(task, ch, redownloading) if err != nil { - logrus.Errorln(err) - } - if songUrl, _ := api.GetSongURL(data, api.SongURLConfig{Ids: []int{musicID}}); len(songUrl.Data) != 0 { - d, err = newDownloader(url, fmt.Sprintf("%d-%s", timeStamp, path.Base(songUrl.Data[0].Url)), 2) - if err != nil { - sendFailed(err) - return err - } + sendFailed(err) + task.CleanTempFiles() + return err } } else { - break + sendFailed(err) + task.CleanTempFiles() + return err } } + + isMD5Verified, _ := verifyMD5(cacheDir+"/"+musicFileName, songURL.Data[0].Md5) if !isMD5Verified && songURL.Data[0].Md5 != "" { + err = os.Remove(cacheDir + "/" + fmt.Sprintf("%d-%s", timeStamp, path.Base(url))) + if err != nil { + logrus.Errorln(err) + } sendFailed(fmt.Errorf("%s\n%s", md5VerFailed, retryLater)) return nil } var picPath, resizePicPath string - p, _ := newDownloader(songDetail.Songs[0].Al.PicUrl, fmt.Sprintf("%d-%s", timeStamp, path.Base(songDetail.Songs[0].Al.PicUrl)), 8) - err = p.download() + p, _ := d.NewDownloadTask(songDetail.Songs[0].Al.PicUrl) + err = p.SetFileName(fmt.Sprintf("%d-%s", timeStamp, path.Base(songDetail.Songs[0].Al.PicUrl))).Download() if err != nil { logrus.Errorln(err) } else { @@ -255,6 +282,13 @@ func processMusic(musicID int, message tgbotapi.Message, bot *tgbotapi.BotAPI) ( logrus.Errorln(err) } + var pic *os.File = nil + + if picStat != nil && err == nil { + pic, _ = os.Open(musicPic) + defer pic.Close() + } + var replacer = strings.NewReplacer("/", " ", "?", " ", "*", " ", ":", " ", "|", " ", "\\", " ", "<", " ", ">", " ", "\"", " ") fileName := replacer.Replace(fmt.Sprintf("%v - %v.%v", strings.Replace(songInfo.SongArtists, "/", ",", -1), songInfo.SongName, songInfo.FileExt)) err = os.Rename(cacheDir+"/"+fmt.Sprintf("%d-%s", timeStamp, path.Base(url)), cacheDir+"/"+fileName) @@ -267,10 +301,12 @@ func processMusic(musicID int, message tgbotapi.Message, bot *tgbotapi.BotAPI) ( file, _ := os.Open(cacheDir + "/" + fileName) defer file.Close() - pic, _ := os.Open(musicPic) - defer pic.Close() - err = marker.AddMusicID3V2(file, pic, mark) + if err != nil { + file, _ = os.Open(cacheDir + "/" + fileName) + defer file.Close() + err = marker.AddMusicID3V2(file, nil, mark) + } if err != nil { sendFailed(err) return err diff --git a/config_example.ini b/config_example.ini index 6922331..1a99160 100644 --- a/config_example.ini +++ b/config_example.ini @@ -11,7 +11,7 @@ MUSIC_U = YOUR_MUSIC_U BotAPI = https://api.telegram.org # 设置 bot 管理员 ID, 用 “," 分隔 -BotAdmin = 1234,3456 +BotAdmin = 115414,1919810 # 是否开启 bot 的 debug 功能 BotDebug = false @@ -34,11 +34,5 @@ MaxRetryTimes = 3 # 下载超时时长 (单位秒, 默认为 60) DownloadTimeout = 60 -# 是否校验更新文件 md5 (默认开启), 若设置为 false 相当于 -no-md5-check 参数 -CheckMD5 = true - -# 自定义源码路径 -SrcPath = ./src - -# 自定义 bot 函数入口 (默认为 bot.Start) -BotEntry = bot.Start \ No newline at end of file +# 自定义下载反向代理 +ReverseProxy = 114.5.1.4:8080 \ No newline at end of file diff --git a/go.mod b/go.mod index f13673e..a9d3578 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,17 @@ go 1.17 require ( github.com/XiaoMengXinX/163KeyMarker v0.0.0-20221030134715-67afb724a936 github.com/XiaoMengXinX/Music163Api-Go v0.1.29 + github.com/XiaoMengXinX/SimpleDownloader v0.0.0-20221110191044-7a2606dfcf7c github.com/glebarez/sqlite v1.5.0 - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0 + github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/sirupsen/logrus v1.8.1 - gorm.io/gorm v1.24.0 + github.com/sirupsen/logrus v1.9.0 + gorm.io/gorm v1.24.1 ) require ( github.com/bogem/id3v2 v1.2.0 // indirect - github.com/glebarez/go-sqlite v1.19.1 // indirect + github.com/glebarez/go-sqlite v1.19.2 // indirect github.com/go-flac/flacpicture v0.2.0 // indirect github.com/go-flac/flacvorbis v0.1.0 // indirect github.com/go-flac/go-flac v0.3.1 // indirect @@ -22,11 +23,11 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-isatty v0.0.16 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - golang.org/x/text v0.3.7 // indirect - modernc.org/libc v1.19.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect + modernc.org/libc v1.21.4 // indirect modernc.org/mathutil v1.5.0 // indirect modernc.org/memory v1.4.0 // indirect - modernc.org/sqlite v1.19.1 // indirect + modernc.org/sqlite v1.19.4 // indirect ) diff --git a/go.sum b/go.sum index 6e98f92..263801c 100644 --- a/go.sum +++ b/go.sum @@ -2,15 +2,19 @@ github.com/XiaoMengXinX/163KeyMarker v0.0.0-20221030134715-67afb724a936 h1:to5zI github.com/XiaoMengXinX/163KeyMarker v0.0.0-20221030134715-67afb724a936/go.mod h1:L6oR/uZwUSBO7o57qbul/zwUuuKpP4EVnFKmTBscvLY= github.com/XiaoMengXinX/Music163Api-Go v0.1.29 h1:c7ekfgo4qgEJ3Wjm9rMhGm7ggN8XqbD1idQka4unJ+Q= github.com/XiaoMengXinX/Music163Api-Go v0.1.29/go.mod h1:kLU/CkLxKnEJFCge0URvQ0lHt6ImoG1/2aVeNbgV2RQ= +github.com/XiaoMengXinX/SimpleDownloader v0.0.0-20221110191044-7a2606dfcf7c h1:n94y1K+aKHkz0OdvdIIod880fl+gwz6Api1lDC6Wap8= +github.com/XiaoMengXinX/SimpleDownloader v0.0.0-20221110191044-7a2606dfcf7c/go.mod h1:Fh8cPEMvudeU3D+sBG4FAoC4iOH8aGI7Z39oaN6/2iA= github.com/bogem/id3v2 v1.2.0 h1:hKDF+F1gOgQ5r1QmBCEZUk4MveJbKxCeIDSBU7CQ4oI= github.com/bogem/id3v2 v1.2.0/go.mod h1:t78PK5AQ56Q47kizpYiV6gtjj3jfxlz87oFpty8DYs8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ddliu/go-httpclient v0.5.1 h1:ys4KozrhBaGdI1yuWIFwNNILqhnMU9ozTvRNfCTorvs= github.com/ddliu/go-httpclient v0.5.1/go.mod h1:8QVbjq00YK2f2MQyiKuWMdaKOFRcoD9VuubkNCNOuZo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/glebarez/go-sqlite v1.19.1 h1:o2XhjyR8CQ2m84+bVz10G0cabmG0tY4sIMiCbrcUTrY= github.com/glebarez/go-sqlite v1.19.1/go.mod h1:9AykawGIyIcxoSfpYWiX1SgTNHTNsa/FVc75cDkbp4M= +github.com/glebarez/go-sqlite v1.19.2 h1:mTtntWN3wk9UNjIf6F7Upqnfq96p+cjhfgCsupUd1hY= +github.com/glebarez/go-sqlite v1.19.2/go.mod h1:DoubC3Kn5X6EBvDa2iaxAdIJqPNmY7M/sOCpfa8fus0= github.com/glebarez/sqlite v1.5.0 h1:+8LAEpmywqresSoGlqjjT+I9m4PseIM3NcerIJ/V7mk= github.com/glebarez/sqlite v1.5.0/go.mod h1:0wzXzTvfVJIN2GqRhCdMbnYd+m+aH5/QV7B30rM6NgY= github.com/go-flac/flacpicture v0.2.0 h1:rS/ZOR/ZxlEwMf3yOPFcTAmGyoV6rDtcYdd+6CwWQAw= @@ -19,11 +23,12 @@ github.com/go-flac/flacvorbis v0.1.0 h1:xStJfPrZ/IoA2oBUEwgrlaSf+Opo6/YuQfkqVhkP github.com/go-flac/flacvorbis v0.1.0/go.mod h1:70N9vVkQ4Jew0oBWkwqDMIE21h7pMUtQJpnMD0js6XY= github.com/go-flac/go-flac v0.3.1 h1:BWA7HdO67S4ZLWSVHCxsDHuedFFu5RiV/wmuhvO6Hxo= github.com/go-flac/go-flac v0.3.1/go.mod h1:jG9IumOfAXr+7J40x0AiQIbJzXf9Y7+Zs/2CNWe4LMk= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0 h1:BtndtqqCQfPsL2uMkYmduOip1+dPcSmh40l82mBUPKk= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.0/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -40,58 +45,86 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa h1:tEkEyxYeZ43TR55QU/hsIt9aRGBxbgGuz9CGykjvogY= +github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= +gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v3 v3.16.12/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= +modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.19.0 h1:bXyVhGQg6KIClTr8FMVIDPl7jtbcs7aS5WP7vLDaxPs= modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= +modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= +modernc.org/libc v1.21.4 h1:CzTlumWeIbPV5/HVIMzYHNPCRP8uiU/CWiN2gtd/Qu8= +modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= @@ -102,11 +135,15 @@ modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.19.1 h1:8xmS5oLnZtAK//vnd4aTVj8VOeTAccEFOtUnIzfSw+4= modernc.org/sqlite v1.19.1/go.mod h1:UfQ83woKMaPW/ZBruK0T7YaFCrI+IE0LeWVY6pmnVms= +modernc.org/sqlite v1.19.2/go.mod h1:fEgebDYAGTFJj2c/ukKmnaq/0ZQZg0PSYxRa/bHyCDs= +modernc.org/sqlite v1.19.4 h1:nlPIDqumn6/mSvs7T5C8MNYEuN73sISzPdKtMdURpUI= +modernc.org/sqlite v1.19.4/go.mod h1:x/yZNb3h5+I3zGQSlwIv4REL5eJhiRkUH5MReogAeIc= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.14.0/go.mod h1:gQ7c1YPMvryCHCcmf8acB6VPabE59QBeuRQLL7cTUlM= +modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.6.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= +modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=