diva/gamebanana/download.go
Nico 527994abba
gamebanana: add function for downloading mods
kinda janky with the implementation right now, later i would like to
improve the way files are copied and allow for mods with multiple
downloads attached to the mod. probably split off some of the
functionality later to add installing mods not on gamebanana easier.
2025-08-30 00:04:45 +10:00

143 lines
2.9 KiB
Go

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
}