// GetLatestModel returns the asset id of the latest model for a given user. // While this is useful for retrieving the asset id of a newly created model // that was just uploaded, it is not necessarily reliable for this purpose. func GetLatestModel(client *rbxweb.Client, userId int32) (assetId int64, err error) { if userId == 0 { return 0, errors.New("invalid user id") } query := url.Values{ "Category": {"Models"}, "SortType": {"RecentlyUpdated"}, "IncludeNotForSale": {"true"}, "ResultsPerPage": {"1"}, "CreatorID": {client.I32toa(userId)}, } resp, err := client.Get(client.GetURL(`api`, `/catalog/json`, query)) if err = client.AssertResp(resp, err); err != nil { return 0, err } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) var asset []struct { AssetId int64 } if err = dec.Decode(&asset); err != nil { return 0, errors.New("JSON decode failed: " + err.Error()) } return asset[0].AssetId, nil }
// Add adds an asset to a set. The set must belong to the current user, and // the asset must be addable to sets. // // This function requires the client to be logged in. func Add(client *rbxweb.Client, assetId int64, setId int32) (err error) { query := url.Values{ "rqtype": {"addtoset"}, "assetId": {client.I64toa(assetId)}, "setId": {client.I32toa(setId)}, } resp, err := client.Post(client.GetURL(`www`, `/Sets/SetHandler.ashx`, query), "", nil) if err = client.AssertResp(resp, err); err != nil { return err } resp.Body.Close() return nil }
// UploadModel uploads data from `reader` to Roblox as a Model asset. If // updating an existing model, `modelId` should be the id of the model. If // `modelId` is 0, then a new model will be uploaded. If uploading a new // model, `info` can be used to specify information about the model. // // This function requires the client to be logged in. func UploadModel(client *rbxweb.Client, reader io.Reader, modelId int64, info url.Values) (assetVersionId int64, err error) { query := url.Values{ "assetid": {client.I64toa(modelId)}, "type": {"Model"}, // "name": {"Unnamed Model"}, // "description": {""}, // "genreTypeId": {"1"}, // "isPublic": {"False"}, // "allowComments": {"False"}, } if info != nil { for key, value := range info { query[key] = value } } return assetVersionId, err }
// GetInfo returns information about an asset, given an asset id. func GetInfo(client *rbxweb.Client, id int64) (info Info, err error) { query := url.Values{ "assetId": {client.I64toa(id)}, } resp, err := client.Get(client.GetURL(`api`, `/marketplace/productinfo`, query)) if err = client.AssertResp(resp, err); err != nil { return Info{}, err } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) dec.Decode(&info) return }
// UpdatePlace uploads data from `reader` to Roblox as a Place asset. // `placeId` must be the id of an existing place. This function cannot create // a new place. // // This function requires the client to be logged in. func UpdatePlace(client *rbxweb.Client, reader io.Reader, placeId int64) (err error) { query := url.Values{ "assetid": {client.I64toa(placeId)}, "type": {"Place"}, } buf := new(bytes.Buffer) buf.ReadFrom(reader) req, _ := http.NewRequest("POST", client.GetURL(`www`, `/Data/Upload.ashx`, query), buf) req.Header.Set("User-Agent", "Roblox") resp, err := client.Do(req) if err = client.AssertResp(resp, err); err != nil { return err } defer resp.Body.Close() return nil }
func TradeRobux(client *rbxweb.Client, robux int64, tickets int64, limit bool, split bool) (err error) { page := client.GetURL(`www`, `/My/Money.aspx`, nil) query := url.Values{ "__EVENTTARGET": {"ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$SubmitTradeButton"}, "__VIEWSTATE": {}, "__EVENTVALIDATION": {}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$HaveCurrencyDropDownList": {"Robux"}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$HaveAmountTextBoxRestyle": {strconv.Itoa(robux)}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$WantCurrencyDropDownList": {"Tickets"}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$WantAmountTextBox": {strconv.Itoa(tickets)}, } if limit { query.Set("ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$OrderType", "LimitOrderRadioButton") } else { query.Set("ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$OrderType", "MarketOrderRadioButton") } if split { query.Set("ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$AllowSplitTradesCheckBox", "on") } else { query.Set("ctl00$ctl00$cphRoblox$cphMyRobloxContent$ctl00$AllowSplitTradesCheckBox", "off") } err = client.DoRawPost(page, query) return }
// Upload generically uploads data from `reader` as an asset to the ROBLOX // website. `info` can be used to specify information about the model. The // following parameters are known: // // type - The type of asset. // assetid - The id of the asset to update. 0 uploads a new asset. // name - The name of the asset. // description - The asset's description. // genreTypeId - The asset's genre. // isPublic - Whether the asset can be taken by other users. // allowComments - Whether users can comment on the asset. // // The success of this function is highly dependent on these parameters. For // example, most asset types may only be uploaded by authorized users. // Parameters that specify information about the asset only apply for new // assets. That is, updating an asset will only update the contents, but not // the information about it. // // `assetVersionId` is the version id of the uploaded asset. This is unique // for each upload. This can be used with GetIdFromVersion to get the asset // id. // // This function requires the client to be logged in. func Upload(client *rbxweb.Client, reader io.Reader, info url.Values) (assetVersionId int64, err error) { buf := new(bytes.Buffer) buf.ReadFrom(reader) req, _ := http.NewRequest("POST", client.GetURL(`www`, `/Data/Upload.ashx`, info), buf) req.Header.Set("User-Agent", "roblox/rbxweb") resp, err := client.Do(req) if err = client.AssertResp(resp, err); err != nil { return 0, err } defer resp.Body.Close() r := new(bytes.Buffer) r.ReadFrom(resp.Body) assetVersionId, _ = client.Atoi64(r.String()) return assetVersionId, err }
// Wall posts a message to a group wall. The account the client is logged into // must have a group role that has permission to post to the group's wall. // // This function requires the client to be logged in. func Wall(client *rbxweb.Client, groupID int32, message string) (success bool) { page := client.GetURL(`www`, `/My/Groups.aspx`, url.Values{"gid": {client.I32toa(groupID)}}) err := client.DoRawPost(page, url.Values{ "ctl00$ctl00$cphRoblox$cphMyRobloxContent$GroupWallPane$NewPost": {message}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$GroupWallPane$NewPostButton": {}, "ctl00$ctl00$cphRoblox$cphMyRobloxContent$rbxGroupRoleSetMembersPane$currentRoleSetID": {}, }) if err != nil { return false } return true }
// Search is used to perform a search query for Roblox assets. func Search(client *rbxweb.Client, query Query) (result []Result, err error) { values := convertQuery(query) resp, err := client.Get(client.GetURL(`www`, `/catalog/json`, values)) if err = client.AssertResp(resp, err); err != nil { return nil, err } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) dec.Decode(&result) return }
// GetIdFromVersion returns an asset id from an asset version id. func GetIdFromVersion(client *rbxweb.Client, assetVersionId int64) (assetId int64, err error) { query := url.Values{ "avid": {client.I64toa(assetVersionId)}, } // This relies on how asset names are converted to url names. Currently, // if an asset name is "_", its url becomes "unnamed". req, _ := http.NewRequest("HEAD", client.GetURL(`www`, `/_-item`, query), nil) resp, err := client.Do(req) if err = client.AssertResp(resp, err); err != nil { return 0, err } resp.Body.Close() values, err := url.ParseQuery(resp.Header.Get("Location")) if err = client.AssertResp(resp, err); err != nil { return 0, err } return client.Atoi64(values.Get("id")) }