Skip to content

Commit

Permalink
download BSP files from workshop
Browse files Browse the repository at this point in the history
  • Loading branch information
markus-wa committed Oct 8, 2021
1 parent 00ed3c6 commit 5ebacc2
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 5 deletions.
92 changes: 88 additions & 4 deletions internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ package core
import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"

"github.com/galaco/bsp"
"github.com/pkg/errors"
)

func extractRadarImage(f *zip.File) error {
func extractRadarImage(f *zip.File, targetDir string) error {
r, err := f.Open()
if err != nil {
return errors.Wrapf(err, "failed to open DDS file %q from archive", f.Name)
}
defer r.Close()

ddsFileName := filepath.Base(f.Name)
ddsFileName := filepath.Join(targetDir, filepath.Base(f.Name))
ddsF, err := os.Create(ddsFileName)
if err != nil {
return errors.Wrapf(err, "failed to create DDS file %q on disk", ddsFileName)
Expand All @@ -33,7 +37,12 @@ func extractRadarImage(f *zip.File) error {
return nil
}

func ExtractRadarImages(f *bsp.Bsp) error {
func ExtractRadarImages(f *bsp.Bsp, targetDir string) error {
err := os.MkdirAll(targetDir, 0744)
if err != nil {
return errors.Wrapf(err, "failed to create target dir %q", targetDir)
}

b := f.RawLump(bsp.LumpPakfile).RawContents()
r := bytes.NewReader(b)
zipR, err := zip.NewReader(r, int64(len(b)))
Expand All @@ -43,7 +52,7 @@ func ExtractRadarImages(f *bsp.Bsp) error {

for _, pakF := range zipR.File {
if filepath.Ext(pakF.Name) == ".dds" {
err := extractRadarImage(pakF)
err := extractRadarImage(pakF, targetDir)
if err != nil {
return errors.Wrapf(err, "failed to extract radar image %q", pakF.Name)
}
Expand All @@ -52,3 +61,78 @@ func ExtractRadarImages(f *bsp.Bsp) error {

return nil
}

type GetPublishedFileDetailsResponse struct {
Response struct {
Result int `json:"result"`
Resultcount int `json:"resultcount"`
Publishedfiledetails []struct {
Publishedfileid string `json:"publishedfileid"`
Result int `json:"result"`
Creator string `json:"creator"`
CreatorAppID int `json:"creator_app_id"`
ConsumerAppID int `json:"consumer_app_id"`
Filename string `json:"filename"`
FileSize int `json:"file_size"`
FileURL string `json:"file_url"`
HcontentFile string `json:"hcontent_file"`
PreviewURL string `json:"preview_url"`
HcontentPreview string `json:"hcontent_preview"`
Title string `json:"title"`
Description string `json:"description"`
TimeCreated int `json:"time_created"`
TimeUpdated int `json:"time_updated"`
Visibility int `json:"visibility"`
Banned int `json:"banned"`
BanReason string `json:"ban_reason"`
Subscriptions int `json:"subscriptions"`
Favorited int `json:"favorited"`
LifetimeSubscriptions int `json:"lifetime_subscriptions"`
LifetimeFavorited int `json:"lifetime_favorited"`
Views int `json:"views"`
Tags []struct {
Tag string `json:"tag"`
} `json:"tags"`
} `json:"publishedfiledetails"`
} `json:"response"`
}

func GetWorkshopFileDetails(workshopID int) (GetPublishedFileDetailsResponse, error) {
payload := url.Values{
"itemcount": []string{"1"},
"publishedfileids[0]": []string{fmt.Sprint(workshopID)},
}

resp, err := http.PostForm("http://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1", payload)
if err != nil {
return GetPublishedFileDetailsResponse{}, err
}

defer resp.Body.Close()

var respData GetPublishedFileDetailsResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&respData)
if err != nil {
return GetPublishedFileDetailsResponse{}, err
}

return respData, nil
}

func DownloadWorkshopItem(workshopID int, w io.Writer) error {
details, err := GetWorkshopFileDetails(workshopID)
if err != nil {
return err
}

resp, err := http.Get(details.Response.Publishedfiledetails[0].FileURL)
if err != nil {
return err
}
defer resp.Body.Close()

_, err = io.Copy(w, resp.Body)

return err
}
74 changes: 73 additions & 1 deletion internal/core/core_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package core_test

import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"

"github.com/galaco/bsp"
Expand All @@ -14,6 +20,72 @@ func TestCore(t *testing.T) {
f, err := bsp.ReadFromFile(bspFilePath)
assert.NoErrorf(t, err, "failed to open BSP file %q", bspFilePath)

err = core.ExtractRadarImages(f)
err = core.ExtractRadarImages(f, filepath.Join(os.TempDir(), "radar-overviews"))
assert.NoError(t, err, "failed to extract radar images from BSP file %q", bspFilePath)
}

type crcTable struct {
Maps []struct {
Name string `json:"map_name"`
Crc uint32 `json:"map_crc"`
WorkshopID int `json:"workshop_id"`
} `json:"maps"`
}

func TestDownload(t *testing.T) {
const crcTablePath = "../../test/data/crc_table.json"

f, err := os.Open(crcTablePath)
assert.NoErrorf(t, err, "failed to open CRC table file %q", crcTablePath)
defer f.Close()

var tab crcTable
dec := json.NewDecoder(f)
err = dec.Decode(&tab)
assert.NoErrorf(t, err, "failed to decode CRC table %q as JSON", crcTablePath)

fDownload, err := os.Create(filepath.Join(os.TempDir(), fmt.Sprintf("%s.bsp.zip", tab.Maps[0].Name)))
assert.NoErrorf(t, err, "failed to create target file for download %q", fDownload.Name())
defer f.Close()

err = core.DownloadWorkshopItem(tab.Maps[0].WorkshopID, fDownload)
assert.NoErrorf(t, err, "failed to download workshop item %q", tab.Maps[0].WorkshopID)
}

func TestE2E(t *testing.T) {
const crcTablePath = "../../test/data/crc_table.json"

f, err := os.Open(crcTablePath)
assert.NoErrorf(t, err, "failed to open CRC table file %q", crcTablePath)
defer f.Close()

var tab crcTable
dec := json.NewDecoder(f)
err = dec.Decode(&tab)
assert.NoErrorf(t, err, "failed to decode CRC table %q as JSON", crcTablePath)

var buf bytes.Buffer

workshopID := tab.Maps[0].WorkshopID
err = core.DownloadWorkshopItem(workshopID, &buf)
assert.NoErrorf(t, err, "failed to download workshop item %q", workshopID)

b := buf.Bytes()
r := bytes.NewReader(b)

zipR, err := zip.NewReader(r, int64(len(b)))
assert.NoErrorf(t, err, "failed to open zip reader for workshop file with ID %q", workshopID)

for _, zipF := range zipR.File {
if filepath.Ext(zipF.Name) == ".bsp" {
bspR, err := zipF.Open()
assert.NoErrorf(t, err, "failed to open BSP file in zip %q", zipF.Name)

bsp, err := bsp.ReadFromStream(bspR)
assert.NoErrorf(t, err, "failed to read BSP data from zip file stream %q", zipF.Name)

err = core.ExtractRadarImages(bsp, filepath.Join(os.TempDir(), "radar-overviews"))
assert.NoErrorf(t, err, "failed to extract radar images from BSP data of file %q", zipF.Name)
}
}
}
Loading

0 comments on commit 5ebacc2

Please sign in to comment.