diff --git a/gamebanana/download.go b/gamebanana/download.go new file mode 100644 index 0000000..c93dcae --- /dev/null +++ b/gamebanana/download.go @@ -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 +} diff --git a/gamebanana/download_test.go b/gamebanana/download_test.go new file mode 100644 index 0000000..5ca1ed4 --- /dev/null +++ b/gamebanana/download_test.go @@ -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") + } +} diff --git a/gamebanana/mods.go b/gamebanana/mods.go index b4ce7da..823eff8 100644 --- a/gamebanana/mods.go +++ b/gamebanana/mods.go @@ -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 diff --git a/gamebanana/mods_test.go b/gamebanana/mods_test.go index 6e40128..5cc756f 100644 --- a/gamebanana/mods_test.go +++ b/gamebanana/mods_test.go @@ -12,7 +12,7 @@ func TestGetGameBananaModValid(t *testing.T) { data, err := GetGameBananaMod("409728") // data - compdata := `{"apps_used":"","authors":"{\"Key Author\":[[\"2VE\",\"Made the mod\",\"2329267\",\"\"]],\"Model Sources\":[[\" jc-starstorm\",\"Walter White\",\"0\",\"https:\\/\\/www.deviantart.com\\/jc-starstorm\\/art\\/Walter-White-650574338\"],[\" SovietMentality\",\"Jesse Pinkman\",\"0\",\"https:\\/\\/www.deviantart.com\\/sovietmentality\\/art\\/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989\"]],\"Special Thanks\":[[\"Skyth\",\"DML, MMM and DBConverter\",\"1614680\",\"\"],[\"Bubble39\",\"DivaTableManager\",\"0\",\"\"]]}","Category().name":"Modules","catid":17293,"contestid":0,"creator":"true","Credits().aAuthors()":[["2VE","Made the mod","2329267",""],[" jc-starstorm","Walter White","0","https://www.deviantart.com/jc-starstorm/art/Walter-White-650574338"],[" SovietMentality","Jesse Pinkman","0","https://www.deviantart.com/sovietmentality/art/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989"],["Skyth","DML, MMM and DBConverter","1614680",""],["Bubble39","DivaTableManager","0",""]],"Credits().aAuthorsAndGroups()":{"Key Author":[["2VE","Made the mod","2329267",""]],"Model Sources":[[" jc-starstorm","Walter White","0","https://www.deviantart.com/jc-starstorm/art/Walter-White-650574338"],[" SovietMentality","Jesse Pinkman","0","https://www.deviantart.com/sovietmentality/art/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989"]],"Special Thanks":[["Skyth","DML, MMM and DBConverter","1614680",""],["Bubble39","DivaTableManager","0",""]]},"Credits().ssvAuthorNames()":"2VE jc-starstorm SovietMentality Skyth Bubble39","date":1667222980,"description":"Jesse, it's time to dance.","downloads":7335,"feedback_instructions":"","Files().aFiles()":{"884808":{"_idRow":"884808","_sFile":"breaking_bad.rar","_nFilesize":24933477,"_tsDateAdded":1667221651,"_nDownloadCount":7335,"_sDownloadUrl":"https://gamebanana.com/dl/884808","_sMd5Checksum":"0f38122833f1b73c0451c51b4381b301","_sAnalysisState":"done","_sAnalysisResult":"ok","_sAnalysisResultVerbose":"File passed preliminary analysis","_sAvState":"done","_sAvResult":"clean","_bIsArchived":false,"_bHasContents":true}},"Game().name":"Hatsune Miku: Project DIVA Mega Mix+","install_instructions":"","is_obsolete":"false","lastpost_date":1731516780,"lastpost_userid":3011973,"likes":42,"mdate":1667222980,"modnote":"","name":"Breaking Bad","Nsfw().bIsNsfw()":false,"obsol_notice":"","Owner().name":"2VE","postcount":17,"Posts().LastPost().idPosterRow()":3011973,"Posts().LastPost().sText()":"\u003cp\u003eBRBA IN DIVA!1!\u003c/p\u003e","Posts().LastPost().tsDateAdded()":1731516780,"Posts().Postcount().nPostCount()":17,"Preview().sStructuredDataFullsizeUrl()":"https://gamebanana.com/mods/embeddables/409728?variant=sd_image","Preview().sSubFeedImageUrl()":"https://images.gamebanana.com/img/ss/mods/220-90_635fc7a11487a.jpg","RootCategory().id":17315,"RootCategory().name":"Customization","screenshots":"[{\"_sCaption\":\"\",\"_sFile\":\"635fc7a11487a.jpg\",\"_nFilesize\":234709,\"_sFile220\":\"220-90_635fc7a11487a.jpg\",\"_hFile220\":124,\"_wFile220\":220,\"_sFile530\":\"530-90_635fc7a11487a.jpg\",\"_hFile530\":299,\"_wFile530\":530,\"_sFile100\":\"100-90_635fc7a11487a.jpg\",\"_hFile100\":56,\"_wFile100\":100,\"_sFile800\":\"800-90_635fc7a11487a.jpg\",\"_hFile800\":452,\"_wFile800\":800},{\"_sCaption\":\"\",\"_sFile\":\"635fc7d692f95.jpg\",\"_nFilesize\":390948,\"_sFile100\":\"100-90_635fc7d692f95.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7e16fd2a.jpg\",\"_nFilesize\":398123,\"_sFile100\":\"100-90_635fc7e16fd2a.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7eb51efb.jpg\",\"_nFilesize\":308231,\"_sFile100\":\"100-90_635fc7eb51efb.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7f4e96f7.jpg\",\"_nFilesize\":316402,\"_sFile100\":\"100-90_635fc7f4e96f7.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7ff0bc69.jpg\",\"_nFilesize\":272481,\"_sFile100\":\"100-90_635fc7ff0bc69.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc80915a9c.jpg\",\"_nFilesize\":215135,\"_sFile100\":\"100-90_635fc80915a9c.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc811375e5.jpg\",\"_nFilesize\":271437,\"_sFile100\":\"100-90_635fc811375e5.jpg\",\"_hFile100\":56,\"_wFile100\":100}]","studioid":0,"text":"\u003ci\u003eThis mod ports Walter White and Jesse Pinkman from the hit TV series Breaking Badâ„¢!\u003cbr\u003e\u003c/i\u003e\u003cbr\u003e\u003cbr\u003e\u003ci\u003e\u003cb\u003eMod features\u003c/b\u003e-\u003c/i\u003e\u003cbr\u003e\u003cb\u003eAdded modules:\u003c/b\u003e Both Walter and Jesse are their separate modules with their own portraits, so you can still use official modules without any conflicts.\u003cbr\u003e\u003cb\u003eWorking expressions: \u003c/b\u003eYes, the lips move and will sing along to songs.\u003cbr\u003e\u003cb\u003eFunny:\u003c/b\u003e\u0026nbsp;This mod was initially made as a joke and tested on intel hd in 480p.\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cb\u003eCompatibility and Known issues-\u003cbr\u003e\u003c/b\u003eWhile this mod doesn't seem to conflict with official assets, the same cannot be said for the other mods on the site as I cannot test or adjust the files to account for mods other than my own.\u003cbr\u003e\u003cbr\u003eAnd as for the issues-\u003cbr\u003eConsidering the nature of the mod (and it being my first for MM+), the character proportions might seem a bit off in some places. This is due to matching the proportions with the official models (or at least their bones), though the mod looks decent otherwise.\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003ci\u003eThanks for reading.\u003c/i\u003e","Trash().bIsTrashed()":false,"udate":1667222980,"Updates().aGetLatestUpdates()":[],"Updates().aLatestUpdates()":[],"Updates().bSubmissionHasUpdates()":false,"Updates().nUpdatesCount()":0,"Url().sDownloadUrl()":"https://gamebanana.com/mods/download/409728","Url().sEditUrl()":"https://gamebanana.com/mods/edit/409728","Url().sEmbeddablesUrl()":"https://gamebanana.com/mods/embeddables/409728","Url().sHistoryUrl()":"https://gamebanana.com/mods/admin/history/409728","Url().sProfileUrl()":"https://gamebanana.com/mods/409728","Url().sTrashUrl()":"https://gamebanana.com/mods/admin/trash/409728","Url().sUntrashUrl()":"https://gamebanana.com/mods/admin/untrash/409728","Url().sUpdatesUrl()":"https://gamebanana.com/mods/updates/409728","Url().sWithholdUrl()":"https://gamebanana.com/mods/admin/withhold/409728","userid":2329267,"views":53290,"Withhold().bIsWithheld()":false}` + compdata := `{"apps_used":"","authors":"{\"Key Author\":[[\"2VE\",\"Made the mod\",\"2329267\",\"\"]],\"Model Sources\":[[\" jc-starstorm\",\"Walter White\",\"0\",\"https:\\\/\\\/www.deviantart.com\\\/jc-starstorm\\\/art\\\/Walter-White-650574338\"],[\" SovietMentality\",\"Jesse Pinkman\",\"0\",\"https:\\\/\\\/www.deviantart.com\\\/sovietmentality\\\/art\\\/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989\"]],\"Special Thanks\":[[\"Skyth\",\"DML, MMM and DBConverter\",\"1614680\",\"\"],[\"Bubble39\",\"DivaTableManager\",\"0\",\"\"]]}","Category().name":"Modules","catid":17293,"contestid":0,"creator":"true","Credits().aAuthors()":[["2VE","Made the mod","2329267",""],[" jc-starstorm","Walter White","0","https:\/\/www.deviantart.com\/jc-starstorm\/art\/Walter-White-650574338"],[" SovietMentality","Jesse Pinkman","0","https:\/\/www.deviantart.com\/sovietmentality\/art\/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989"],["Skyth","DML, MMM and DBConverter","1614680",""],["Bubble39","DivaTableManager","0",""]],"Credits().aAuthorsAndGroups()":{"Key Author":[["2VE","Made the mod","2329267",""]],"Model Sources":[[" jc-starstorm","Walter White","0","https:\/\/www.deviantart.com\/jc-starstorm\/art\/Walter-White-650574338"],[" SovietMentality","Jesse Pinkman","0","https:\/\/www.deviantart.com\/sovietmentality\/art\/XNA-Breaking-Bad-Jesse-And-Skinny-Pete-DL-483365989"]],"Special Thanks":[["Skyth","DML, MMM and DBConverter","1614680",""],["Bubble39","DivaTableManager","0",""]]},"Credits().ssvAuthorNames()":"2VE jc-starstorm SovietMentality Skyth Bubble39","date":1667222980,"description":"Jesse, it's time to dance.","downloads":7339,"feedback_instructions":"","Files().aFiles()":{"884808":{"_idRow":"884808","_sFile":"breaking_bad.rar","_nFilesize":24933477,"_tsDateAdded":1667221651,"_nDownloadCount":7339,"_sDownloadUrl":"https:\/\/gamebanana.com\/dl\/884808","_sMd5Checksum":"0f38122833f1b73c0451c51b4381b301","_sAnalysisState":"done","_sAnalysisResult":"ok","_sAnalysisResultVerbose":"File passed preliminary analysis","_sAvState":"done","_sAvResult":"clean","_bIsArchived":false,"_bHasContents":true}},"Game().name":"Hatsune Miku: Project DIVA Mega Mix+","install_instructions":"","is_obsolete":"false","lastpost_date":1731516780,"lastpost_userid":3011973,"likes":42,"mdate":1667222980,"modnote":"","name":"Breaking Bad","Nsfw().bIsNsfw()":false,"obsol_notice":"","Owner().name":"2VE","postcount":17,"Posts().LastPost().idPosterRow()":3011973,"Posts().LastPost().sText()":"
BRBA IN DIVA!1!<\/p>","Posts().LastPost().tsDateAdded()":1731516780,"Posts().Postcount().nPostCount()":17,"Preview().sStructuredDataFullsizeUrl()":"https:\/\/gamebanana.com\/mods\/embeddables\/409728?variant=sd_image","Preview().sSubFeedImageUrl()":"https:\/\/images.gamebanana.com\/img\/ss\/mods\/220-90_635fc7a11487a.jpg","RootCategory().id":17315,"RootCategory().name":"Customization","screenshots":"[{\"_sCaption\":\"\",\"_sFile\":\"635fc7a11487a.jpg\",\"_nFilesize\":234709,\"_sFile220\":\"220-90_635fc7a11487a.jpg\",\"_hFile220\":124,\"_wFile220\":220,\"_sFile530\":\"530-90_635fc7a11487a.jpg\",\"_hFile530\":299,\"_wFile530\":530,\"_sFile100\":\"100-90_635fc7a11487a.jpg\",\"_hFile100\":56,\"_wFile100\":100,\"_sFile800\":\"800-90_635fc7a11487a.jpg\",\"_hFile800\":452,\"_wFile800\":800},{\"_sCaption\":\"\",\"_sFile\":\"635fc7d692f95.jpg\",\"_nFilesize\":390948,\"_sFile100\":\"100-90_635fc7d692f95.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7e16fd2a.jpg\",\"_nFilesize\":398123,\"_sFile100\":\"100-90_635fc7e16fd2a.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7eb51efb.jpg\",\"_nFilesize\":308231,\"_sFile100\":\"100-90_635fc7eb51efb.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7f4e96f7.jpg\",\"_nFilesize\":316402,\"_sFile100\":\"100-90_635fc7f4e96f7.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc7ff0bc69.jpg\",\"_nFilesize\":272481,\"_sFile100\":\"100-90_635fc7ff0bc69.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc80915a9c.jpg\",\"_nFilesize\":215135,\"_sFile100\":\"100-90_635fc80915a9c.jpg\",\"_hFile100\":56,\"_wFile100\":100},{\"_sCaption\":\"\",\"_sFile\":\"635fc811375e5.jpg\",\"_nFilesize\":271437,\"_sFile100\":\"100-90_635fc811375e5.jpg\",\"_hFile100\":56,\"_wFile100\":100}]","studioid":0,"text":"This mod ports Walter White and Jesse Pinkman from the hit TV series Breaking Bad\u2122!
<\/i>
Mod features<\/b>-<\/i>
Added modules:<\/b> Both Walter and Jesse are their separate modules with their own portraits, so you can still use official modules without any conflicts.
Working expressions: <\/b>Yes, the lips move and will sing along to songs.
Funny:<\/b> This mod was initially made as a joke and tested on intel hd in 480p.
Compatibility and Known issues-
<\/b>While this mod doesn't seem to conflict with official assets, the same cannot be said for the other mods on the site as I cannot test or adjust the files to account for mods other than my own.
And as for the issues-
Considering the nature of the mod (and it being my first for MM+), the character proportions might seem a bit off in some places. This is due to matching the proportions with the official models (or at least their bones), though the mod looks decent otherwise.
Thanks for reading.<\/i>","Trash().bIsTrashed()":false,"udate":1667222980,"Updates().aGetLatestUpdates()":[],"Updates().aLatestUpdates()":[],"Updates().bSubmissionHasUpdates()":false,"Updates().nUpdatesCount()":0,"Url().sDownloadUrl()":"https:\/\/gamebanana.com\/mods\/download\/409728","Url().sEditUrl()":"https:\/\/gamebanana.com\/mods\/edit\/409728","Url().sEmbeddablesUrl()":"https:\/\/gamebanana.com\/mods\/embeddables\/409728","Url().sHistoryUrl()":"https:\/\/gamebanana.com\/mods\/admin\/history\/409728","Url().sProfileUrl()":"https:\/\/gamebanana.com\/mods\/409728","Url().sTrashUrl()":"https:\/\/gamebanana.com\/mods\/admin\/trash\/409728","Url().sUntrashUrl()":"https:\/\/gamebanana.com\/mods\/admin\/untrash\/409728","Url().sUpdatesUrl()":"https:\/\/gamebanana.com\/mods\/updates\/409727","Url().sWithholdUrl()":"https:\/\/gamebanana.com\/mods\/admin\/withhold\/409728","userid":2329267,"views":53316,"Withhold().bIsWithheld()":false}`
var compDataStruct GameBananaMod
err = json.Unmarshal([]byte(compdata), &compDataStruct)
diff --git a/go.mod b/go.mod
index cf9254e..27df0a8 100644
--- a/go.mod
+++ b/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
)
diff --git a/go.sum b/go.sum
index fe5804d..78ea2ae 100644
--- a/go.sum
+++ b/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=