Compare commits
2 commits
baccafb8ce
...
527994abba
| Author | SHA1 | Date | |
|---|---|---|---|
| 527994abba | |||
| 226c6a0e93 |
6 changed files with 189 additions and 20 deletions
143
gamebanana/download.go
Normal file
143
gamebanana/download.go
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
package gamebanana
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gen2brain/go-unarr"
|
||||
)
|
||||
|
||||
var dlurl string
|
||||
|
||||
func DownloadGameBananaMod(id, outdir string) (error) {
|
||||
modData, err := GetGameBananaMod(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create temporary file to download mod to
|
||||
tmpFolderDownload, err := os.MkdirTemp("", "diva-mod-download-*")
|
||||
log.Info("created temp folder for downloading", "name", tmpFolderDownload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// really really jank, but api doesn't really have a better way of doing this
|
||||
for _, x := range modData.FilesAFiles {
|
||||
dlurl = x.SDownloadURL
|
||||
break
|
||||
}
|
||||
|
||||
fileDlPath := path.Join(tmpFolderDownload, "download")
|
||||
fileDl, err := os.Create(fileDlPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileDl.Close()
|
||||
|
||||
// download mod
|
||||
resp, err := http.Get(dlurl)
|
||||
log.Info("downloading mod", "url", dlurl, "modid", id, "path", fileDl)
|
||||
// TODO: handle error code properly
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// save to temp file
|
||||
_, err = io.Copy(fileDl, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// extract files to same directory
|
||||
a, err := unarr.NewArchive(fileDlPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = a.Extract(tmpFolderDownload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// such jank but ive spent wayyy too long on this
|
||||
var moddir string = ""
|
||||
err = filepath.Walk(tmpFolderDownload, func(filePath string, _ fs.FileInfo, err error) error {
|
||||
if path.Base(filePath) == "config.toml" {
|
||||
moddir = path.Dir(filePath)
|
||||
log.Info("found mod folder", "configloc", filePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if moddir == "" {
|
||||
errors.New("config.toml not found in mod dir")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create a folder put the mod in
|
||||
outpath := path.Join(outdir, fmt.Sprintf("%s@%d", id, modData.Udate))
|
||||
err = os.Mkdir(outpath, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = filepath.Walk(moddir, func(filePath string, fileinfo fs.FileInfo, err error) error {
|
||||
relativepath := strings.Replace(filePath, moddir, "", 1)
|
||||
newpath := path.Join(outdir, relativepath)
|
||||
|
||||
if relativepath == "" { return nil }
|
||||
|
||||
if fileinfo.IsDir() == true {
|
||||
log.Warn("found directory, creating it!", "path", filePath, "relpath", relativepath, "newpath", newpath)
|
||||
err = os.Mkdir(newpath, 0744)
|
||||
if err != nil { return err }
|
||||
return nil
|
||||
}
|
||||
|
||||
var src *os.File
|
||||
var dst *os.File
|
||||
|
||||
if src, err = os.Open(filePath); err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
if dst, err = os.Create(newpath); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
if _, err = io.Copy(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("copied file!!!", "src", filePath, "dst", newpath, "relativepath", relativepath)
|
||||
return os.Chmod(newpath, 0744)
|
||||
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: cleanup temp files
|
||||
err = os.RemoveAll(fileDlPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
24
gamebanana/download_test.go
Normal file
24
gamebanana/download_test.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package gamebanana
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDownloadGameBananaMod(t *testing.T) {
|
||||
tmpdir := t.TempDir()
|
||||
err := DownloadGameBananaMod("602180", tmpdir)
|
||||
if err != nil {
|
||||
t.Error("failed to download game banana mod", err)
|
||||
}
|
||||
|
||||
// udate is the time the mod was last updated
|
||||
// in unix time, used here as a version number
|
||||
// modID@udate
|
||||
expectedPathToExist := path.Join(tmpdir, "602180@1750696716")
|
||||
|
||||
if _, err := os.Stat(expectedPathToExist); err != nil {
|
||||
t.Error("mod doesn't have expected name or doesn't exist")
|
||||
}
|
||||
}
|
||||
|
|
@ -29,24 +29,7 @@ type GameBananaMod struct {
|
|||
Description string `json:"description"`
|
||||
Downloads int `json:"downloads"`
|
||||
FeedbackInstructions string `json:"feedback_instructions"`
|
||||
FilesAFiles struct {
|
||||
Num884808 struct {
|
||||
IDRow string `json:"_idRow"`
|
||||
SFile string `json:"_sFile"`
|
||||
NFilesize int `json:"_nFilesize"`
|
||||
TsDateAdded int `json:"_tsDateAdded"`
|
||||
NDownloadCount int `json:"_nDownloadCount"`
|
||||
SDownloadURL string `json:"_sDownloadUrl"`
|
||||
SMd5Checksum string `json:"_sMd5Checksum"`
|
||||
SAnalysisState string `json:"_sAnalysisState"`
|
||||
SAnalysisResult string `json:"_sAnalysisResult"`
|
||||
SAnalysisResultVerbose string `json:"_sAnalysisResultVerbose"`
|
||||
SAvState string `json:"_sAvState"`
|
||||
SAvResult string `json:"_sAvResult"`
|
||||
BIsArchived bool `json:"_bIsArchived"`
|
||||
BHasContents bool `json:"_bHasContents"`
|
||||
} `json:"884808"`
|
||||
} `json:"Files().aFiles()"`
|
||||
FilesAFiles map[string]gamebananaDownloadInformation `json:"Files().aFiles()"`
|
||||
GameName string `json:"Game().name"`
|
||||
InstallInstructions string `json:"install_instructions"`
|
||||
IsObsolete string `json:"is_obsolete"`
|
||||
|
|
@ -91,6 +74,22 @@ type GameBananaMod struct {
|
|||
WithholdBIsWithheld bool `json:"Withhold().bIsWithheld()"`
|
||||
}
|
||||
|
||||
type gamebananaDownloadInformation struct {
|
||||
IDRow string `json:"_idRow"`
|
||||
SFile string `json:"_sFile"`
|
||||
NFilesize int `json:"_nFilesize"`
|
||||
TsDateAdded int `json:"_tsDateAdded"`
|
||||
NDownloadCount int `json:"_nDownloadCount"`
|
||||
SDownloadURL string `json:"_sDownloadUrl"`
|
||||
SMd5Checksum string `json:"_sMd5Checksum"`
|
||||
SAnalysisState string `json:"_sAnalysisState"`
|
||||
SAnalysisResult string `json:"_sAnalysisResult"`
|
||||
SAnalysisResultVerbose string `json:"_sAnalysisResultVerbose"`
|
||||
SAvState string `json:"_sAvState"`
|
||||
SAvResult string `json:"_sAvResult"`
|
||||
BIsArchived bool `json:"_bIsArchived"`
|
||||
BHasContents bool `json:"_bHasContents"`
|
||||
}
|
||||
|
||||
func GetGameBananaMod(id string) (GameBananaMod, error) {
|
||||
// build URL params
|
||||
|
|
@ -105,7 +104,7 @@ func GetGameBananaMod(id string) (GameBananaMod, error) {
|
|||
params.Add("itemid", id)
|
||||
params.Add("format", "json_min")
|
||||
params.Add("return_keys", "1")
|
||||
params.Add("fields", "apps_used,authors,Category().name,catid,contestid,creator,Credits().aAuthors(),Credits().aAuthorsAndGroups(),Credits().ssvAuthorNames(),date,description,downloads,feedback_instructions,Files().aFiles(),Game().name,install_instructions,is_obsolete,lastpost_date,lastpost_userid,likes,mdate,modnote,name,Nsfw().bIsNsfw(),obsol_notice,Owner().name,postcount,Posts().LastPost().idPosterRow(),Posts().LastPost().sText(),Posts().LastPost().tsDateAdded(),Posts().Postcount().nPostCount(),Preview().sStructuredDataFullsizeUrl(),Preview().sSubFeedImageUrl(),RootCategory().id,RootCategory().name,screenshots,studioid,text,Trash().bIsTrashed(),udate,Updates().aGetLatestUpdates(),Updates().aLatestUpdates(),Updates().bSubmissionHasUpdates(),Updates().nUpdatesCount(),Url().sDownloadUrl(),Url().sEditUrl(),Url().sEmbeddablesUrl(),Url().sHistoryUrl(),Url().sProfileUrl(),Url().sTrashUrl(),Url().sUntrashUrl(),Url().sUpdatesUrl(),Url().sWithholdUrl(),userid,views,Withhold().bIsWithheld()")
|
||||
params.Add("fields", "apps_used,authors,Category().name,catid,contestid,creator,Credits().ssvAuthorNames(),date,description,downloads,feedback_instructions,Files().aFiles(),Game().name,install_instructions,is_obsolete,lastpost_date,lastpost_userid,likes,mdate,modnote,name,Nsfw().bIsNsfw(),obsol_notice,Owner().name,postcount,Posts().LastPost().idPosterRow(),Posts().LastPost().sText(),Posts().LastPost().tsDateAdded(),Posts().Postcount().nPostCount(),Preview().sStructuredDataFullsizeUrl(),Preview().sSubFeedImageUrl(),RootCategory().id,RootCategory().name,screenshots,studioid,text,Trash().bIsTrashed(),udate,Updates().aGetLatestUpdates(),Updates().aLatestUpdates(),Updates().bSubmissionHasUpdates(),Updates().nUpdatesCount(),Url().sDownloadUrl(),Url().sEditUrl(),Url().sEmbeddablesUrl(),Url().sHistoryUrl(),Url().sProfileUrl(),Url().sTrashUrl(),Url().sUntrashUrl(),Url().sUpdatesUrl(),Url().sWithholdUrl(),userid,views,Withhold().bIsWithheld()")
|
||||
base.RawQuery = params.Encode()
|
||||
|
||||
// send request
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
1
go.mod
1
go.mod
|
|
@ -4,6 +4,7 @@ go 1.24.5
|
|||
|
||||
require (
|
||||
github.com/charmbracelet/log v0.4.2
|
||||
github.com/gen2brain/go-unarr v0.2.4
|
||||
github.com/google/go-cmp v0.5.8
|
||||
)
|
||||
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -14,6 +14,8 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ
|
|||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
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/gen2brain/go-unarr v0.2.4 h1:Iu2kqtGfkLBSQoTFwMkSCmp0g3GrEM/XMVWzo9TQr/Y=
|
||||
github.com/gen2brain/go-unarr v0.2.4/go.mod h1:0kdy3HtjKBcEaewifXZguHCvt4qD9V8iJCx4FPEOWT8=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue