Jump to content
Frequently Asked Questions
  • Are you not able to open the client? Try following our getting started guide
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS/Crypto gold? You can purchase vouchers from other users
  • Try asking for help in the chatbox
  • Official GE price lookup [Auto-updating]


    Calculus
     Share

    Recommended Posts

    I know, ones already exist. This one just auto-updates itself after 10 minutes, and holds a cache of prices instead of having to spend time checking prices from the API. This one simplifies everything because it keeps prices auto-up to date, and all you have to do is check the price.

     

    Example usage:

    import static BotFarmServer.GrandExchangeApi.*;
    
    public class Test {
        public static void main(String[] args) {
            GrandExchangeApi exchangeApi = new GrandExchangeApi();
            GELookupResult lookupResult = exchangeApi.lookup(333);
            if(lookupResult != null)
                System.out.println("Item: " + lookupResult.name + " Price: " + lookupResult.price);
        }
    }
    

    If you DON'T want to use a cache (i.e. ALWAYS update the prices every check):

    GrandExchangeApi exchangeApi = new GrandExchangeApi(false); //false means NO CACHE (AKA always-lookup new price)
    

    Code:

    package BotFarmServer;
    
    import java.io.IOException;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * Utility class for access to the Grand Exchange API.
     */
    public class GrandExchangeApi {
        private static final String API_LOCATION = "http://services.runescape.com/m=itemdb_oldschool" +
                "/api/catalogue/detail.json?item=%d";
        private static final long TEN_MINUTES = 600000;
        private final Map<Integer, GELookupResult> cache;
        private long startTime;
    
        /**
         * Caching-enabled default constructor
         */
        public GrandExchangeApi() {
            this(true);
        }
    
        /**
         * Creates a new Grand Exchange API instance. Starts cache-refresh timer.
         * @[member='param'] cache Whether to enable caching of results.
         */
        public GrandExchangeApi(boolean cache) {
            startTime = System.currentTimeMillis();
            this.cache = cache ? new HashMap<>() : null;
        }
    
        /**
         * If caching is enabled, clears the cache so that new results are fetched on lookup.
         */
        public void flushCache() {
            if(cache != null) {
                cache.clear();
            }
        }
    
        /**
         * Looks up an item using the Grand Exchange API. This method blocks while waiting for the API result.
         * @[member='param'] itemId the id to look up.
         * @return the result returned by the api. May be null if an error has occurred.
         */
        public GELookupResult lookup(int itemId) {
            if((System.currentTimeMillis() - TEN_MINUTES) > startTime){ //Flush cache after 10 minutes. Auto-update prices.
                flushCache();
                startTime = System.currentTimeMillis();
            }
    
            if(cache != null && !cache.isEmpty()) {
                GELookupResult result = cache.get(itemId);
                if(result != null) {
                    return result;
                }
            }
    
            String json;
            try {
                URL url = new URL(String.format(API_LOCATION, itemId));
                Scanner scan = new Scanner(url.openStream()).useDelimiter("\\A");
                json = scan.next();
                scan.close();
            } catch(IOException e) {
                return null;
            }
    
            GELookupResult result = parse(itemId, json);
    
            if(cache != null) {
                cache.put(itemId, result);
            }
    
            return result;
        }
    
        /**
         * Parses a GELookupResult from the JSON returned by the API.
         * @[member='param'] itemId The item ID.
         * @[member='param'] json The JSON returned by the RuneScape's API.
         * @return The serialized result.
         */
        private static GELookupResult parse(int itemId, String json) {
            Pattern pattern = Pattern.compile("\"(?<key>[^\"]+)\":\"(?<value>[^\"]+)\"");
            Matcher m = pattern.matcher(json);
            Map<String, String> results = new HashMap<>();
            while(m.find()) {
                results.put(m.group("key"), m.group("value"));
            }
    
            int price = 0;
            Matcher priceMatcher = Pattern.compile("\"price\":(?<price>\\d+)").matcher(json);
            if (priceMatcher.find()) {
                price = Integer.parseInt(priceMatcher.group("price"));
            }
    
            return new GELookupResult(
                    results.get("icon"),
                    results.get("icon_large"),
                    results.get("type"),
                    results.get("typeIcon"),
                    results.get("name"),
                    results.get("description"),
                    Boolean.parseBoolean(results.get("members")),
                    itemId,
                    price
            );
        }
    
        /**
         * A class representing a result from an API lookup.
         */
        public static final class GELookupResult {
            public final String smallIconUrl, largeIconUrl, type, typeIcon, name, itemDescription;
            public final boolean isMembers;
            public final int id, price;
    
            private GELookupResult(String smallIconUrl,
                                   String largeIconUrl,
                                   String type,
                                   String typeIcon,
                                   String name,
                                   String itemDescription,
                                   boolean isMembers,
                                   int id,
                                   int price) {
    
                this.smallIconUrl = smallIconUrl;
                this.largeIconUrl = largeIconUrl;
                this.type = type;
                this.typeIcon = typeIcon;
                this.name = name;
                this.itemDescription = itemDescription;
                this.isMembers = isMembers;
                this.id = id;
                this.price = price;
            }
        }
    }
    
    Edited by Calculus
    Link to comment
    Share on other sites

    If you want it to 100% be updated every 10 minutes you could consider having it be a thread, or having the lookup result be a thread which is automatically started on creation, and can be stopped by doing result.stop();

    just a thought, though.

     

    Otherwise I like it :')

    Link to comment
    Share on other sites

    If you want it to 100% be updated every 10 minutes you could consider having it be a thread, or having the lookup result be a thread which is automatically started on creation, and can be stopped by doing result.stop();

    just a thought, though.

     

    Otherwise I like it :')

    I really did think about it, but threading seems like it'd over-complicate the already very simple task. Also, RuneScape's API starts denying requests if you send too many at once, so the point of threading (to speed up the process) is sort of defeated if you can't complete all the tasks anyway, no?

    Link to comment
    Share on other sites

    I really did think about it, but threading seems like it'd over-complicate the already very simple task. Also, RuneScape's API starts denying requests if you send too many at once, so the point of threading (to speed up the process) is sort of defeated if you can't complete all the tasks anyway, no?

    The rsbuddy api doesn't have a request limit and it's more accurate. https://api.rsbuddy.com/grandExchange?a=guidePrice&i=2

    Link to comment
    Share on other sites

    The rsbuddy api doesn't have a request limit and it's more accurate. https://api.rsbuddy.com/grandExchange?a=guidePrice&i=2

    You're correct in that it doesn't have a request limit, but it's definitely NOT more accurate. RS's GE API is real-time, rsbuddy is updated every time someone using the client buys/sells an item.

     

    Some items people buy/sell, they don't buy and sell on an OSBuddy client, so the prices never get updated. That's annoying af, especially to people wanting to use the GE to merch, where specific data-points in real-time are needed.

    Edited by Calculus
    Link to comment
    Share on other sites

    The difference though is RS GE API shows the shown price in game. Rsbuddy shows the actual average traded price that they've observed(unless I am mistaken)

    Link to comment
    Share on other sites

    The difference though is RS GE API shows the shown price in game. Rsbuddy shows the actual average traded price that they've observed(unless I am mistaken)

    That's not the purpose of this API. Other APIs for that purpose already exist, and as I stated before, those MIGHT* be up to date, however I know from personal experience that lots of rarely-traded items are NOT up to date on osbuddy's API.

    Link to comment
    Share on other sites

    You're correct in that it doesn't have a request limit, but it's definitely NOT more accurate. RS's GE API is real-time, rsbuddy is updated every time someone using the client buys/sells an item.

     

    Some items people buy/sell, they don't buy and sell on an OSBuddy client, so the prices never get updated. That's annoying af, especially to people wanting to use the GE to merch, where specific data-points in real-time are needed.

    The GE prices of the official are definitely not in real time. I've switched to using the price from rsbuddy because I've checked many items and compared the official price, the price of rsbuddy, and the price I actually can buy the item in the GE. The rsbuddy is the closest to the actual buy/sell offers I make in the GE every time. I also notice that the prices in the official seem to stay the same for pretty much the whole day. I checked a few items and they definitely do not keep updating.

    Link to comment
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
     Share

    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.