From b5818a047ed018f370c231a068538b2bb006b183 Mon Sep 17 00:00:00 2001 From: PraiseSatan Date: Sat, 22 May 2021 21:33:47 +1000 Subject: [PATCH] Fix obtaining Pack URL --- db.go | 63 ++++++++++++++++++++++++++++++++++++++++++------------ main.go | 26 ++++++++++++---------- modpack.go | 19 +++++++++++----- 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/db.go b/db.go index ecf16ff..b4b2d34 100644 --- a/db.go +++ b/db.go @@ -23,6 +23,8 @@ import ( "fmt" "os" "path/filepath" + "strconv" + "math" "regexp" @@ -314,25 +316,58 @@ func (db *Database) getDeps(fileID int) ([]string, error) { return result, nil } -func (db *Database) getLatestPackURL(slug string) (string, error) { +func (db *Database) getLatestPackURL(slug string, fileID string) (string, error) { // First try to find the pack by looking for the specific slug - pid, err := db.findProjectBySlug(slug, 1) + projectID, err := db.findProjectBySlug(slug, 1) if err != nil { - return "", err + projectID, err = strconv.Atoi(slug) + if err != nil { + return "", fmt.Errorf("No modpack found %s", slug) + } else { + fmt.Printf("Interpretting %s as project ID\n", slug); + } } + + + url := "" + + if fileID != "" { + // Retrieve the JSON descriptor for this file so we can get the CDN url + descriptorUrl := fmt.Sprintf("https://addons-ecs.forgesvc.net/api/v2/addon/%d/file/%s", projectID, fileID) + descriptor, err := getJSONFromURL(descriptorUrl) + if err != nil { + return "", fmt.Errorf("failed to retrieve descriptor for %s: %+v", slug, err) + } - // Find the latest file given the project ID; we don't need to worry about matching the MC version, - // since modpacks are always locked to a specific version anyways - var fileID int - err = db.sqlDb.QueryRow("select fileid from files where projectid = ? order by tstamp desc limit 1", pid).Scan(&fileID) - switch { - case err == sql.ErrNoRows: - return "", fmt.Errorf("No modpack file found for %s", slug) - case err != nil: - return "", err + // Download the file to the pack mod directory + url = descriptor.Path("downloadUrl").Data().(string) + } else { + projectUrl := fmt.Sprintf("https://addons-ecs.forgesvc.net/api/v2/addon/%d", projectID) + project, err := getJSONFromURL(projectUrl) + if err != nil { + return "", fmt.Errorf("failed to retrieve project for %s: %+v", slug, err) + } + + selectedFileType := math.MaxInt8 + + // Look for the file with most stable release type + files, _ := project.Path("latestFiles").Children() + for _, file := range files { + fileType, _ := intValue(file, "releaseType") // 1 = release, 2 = beta, 3 = alpha + fileUrl, _ := file.Path("downloadUrl").Data().(string) + + // Prefer releases over beta/alpha + if fileType < selectedFileType { + selectedFileType = fileType + url = fileUrl + } + } + + if url == "" { + return "", fmt.Errorf("Unable to find download URL for %s\n", slug) + } } - // Construct a URL using the slug and file ID - return fmt.Sprintf("https://minecraft.curseforge.com/projects/%d/files/%d/download", pid, fileID), nil + return url, nil } diff --git a/main.go b/main.go index 71e530b..328041d 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,6 @@ import ( "path/filepath" "regexp" "sort" - "strings" "time" "github.com/xeonx/timeago" @@ -67,9 +66,9 @@ var gCommands = map[string]command{ }, "pack.install": { Fn: cmdPackInstall, - Desc: fmt.Sprintf("Install a mod pack, optionally using a URL to download. Use %s for the directory with a URL to use the name from the downloaded manifest", NamePlaceholder), + Desc: fmt.Sprintf("Install a mod pack, using either a manifest in the provided folder, or using slug or project ID.\nOptionally using a fileID to specify a specific version of the mod pack to download.\nUse %s for the directory with a slug/projectID to use the name from the downloaded manifest", NamePlaceholder), ArgsCount: 1, - Args: " []", + Args: " [ ]", }, "info": { Fn: cmdInfo, @@ -149,7 +148,7 @@ func cmdPackCreate() error { } // Create a new pack directory - cp, err := NewModPack(dir, false, ARG_MMC) + cp, err := NewModPack(dir, 0, ARG_MMC) if err != nil { return err } @@ -180,22 +179,27 @@ func cmdPackCreate() error { func cmdPackInstall() error { dir := flag.Arg(1) - url := flag.Arg(2) + slug := flag.Arg(2) + fileID := flag.Arg(3) + url := "" db, err := OpenDatabase() if err != nil { return err } - if dir != "" && !strings.HasPrefix(url, "https://") { - url, err = db.getLatestPackURL(dir) + if slug != "" { + url, err = db.getLatestPackURL(slug, fileID) if err != nil { return err } } // Only require a manifest if we're not installing from a URL - requireManifest := url == "" + requireManifest := 0 + if url == "" { + requireManifest = 2 + } cp, err := NewModPack(dir, requireManifest, ARG_MMC) if err != nil { @@ -285,7 +289,7 @@ var curseForgeRegex = regexp.MustCompile("/projects/([\\w-]*)(/files/(\\d+))?") func _modSelect(dir, modId, url string, clientOnly bool) error { // Try to open the mod pack - cp, err := NewModPack(dir, true, ARG_MMC) + cp, err := NewModPack(dir, 1, ARG_MMC) if err != nil { return err } @@ -345,7 +349,7 @@ func cmdPackListLatest() error { func cmdModUpdateAll() error { dir := flag.Arg(1) - cp, err := NewModPack(dir, true, ARG_MMC) + cp, err := NewModPack(dir, 1, ARG_MMC) if err != nil { return err } @@ -378,7 +382,7 @@ func cmdServerInstall() error { // Open the pack; we require the manifest and any // config files to already be present - cp, err := NewModPack(dir, true, false) + cp, err := NewModPack(dir, 1, false) if err != nil { return err } diff --git a/modpack.go b/modpack.go index b402535..4a57df3 100644 --- a/modpack.go +++ b/modpack.go @@ -69,8 +69,12 @@ func (pack *ModPack) fullName() string { ) } -func NewModPack(dir string, requireManifest bool, enableMultiMC bool) (*ModPack, error) { +func NewModPack(dir string, TrequireManifest int, enableMultiMC bool) (*ModPack, error) { pack := new(ModPack) + requireManifest := false; + if TrequireManifest > 0 { + requireManifest = true; + } // Open a copy of the database for modpack related ops db, err := OpenDatabase() @@ -110,7 +114,11 @@ func NewModPack(dir string, requireManifest bool, enableMultiMC bool) (*ModPack, // Try to load the manifest; only raise an error if we require it to be loaded err = pack.loadManifest() if requireManifest && err != nil { - return nil, err + if TrequireManifest == 2 { + return nil, fmt.Errorf("%v\nIf you meant to install a modpack identified by %[2]s run:\n\tmcdex pack.install %[2]s %[2]s\n", err, dir) + } else { + return nil, err + } } fmt.Printf("-- %s --\n", pack.gamePath()) @@ -157,10 +165,11 @@ func (pack *ModPack) download(url string) error { fmt.Printf("Starting download of modpack: %s\n", url) + // This doesn't work any more. // For the moment, we only support modpacks from Curseforge or FTB; check and enforce these conditions - if !hasAnyPrefix(url, VALID_URL_PREFIXES...) { - return fmt.Errorf("Invalid modpack URL; we only support Curseforge & feed-the-beast.com right now") - } + //if !hasAnyPrefix(url, VALID_URL_PREFIXES...) { + // return fmt.Errorf("Invalid modpack URL; we only support Curseforge & feed-the-beast.com right now") + //} // Start the download resp, err := HttpGet(url)