Skip to content

Commit

Permalink
added wiki prices
Browse files Browse the repository at this point in the history
  • Loading branch information
extreme4all committed Oct 29, 2024
1 parent de3d63a commit d634945
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 8 deletions.
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# The project
The goal is to make a wrapper around the various oldschool runescape api's.

# osrs hiscores
## osrs hiscores
```py
import asyncio

Expand All @@ -24,10 +24,11 @@ async def main():
)
print(player_stats)


loop = asyncio.get_running_loop()
await loop.create_task(main())
# Run the asynchronous main function
if __name__ == "__main__":
asyncio.run(main())
```
## osrs itemdb (Catalogue & Grand Exchange)
```py
import asyncio
from aiohttp import ClientSession
Expand Down Expand Up @@ -63,6 +64,7 @@ async def main():
print("Item Detail:", item_detail)

# Example 3: Fetching historical trade data (price graph) for a specific item
item_id = 4151 # Example item ID (Abyssal whip in OSRS)
trade_history = await graph_instance.get_graph(
session,
item_id=item_id,
Expand All @@ -71,5 +73,36 @@ async def main():
print("Trade History:", trade_history)

# Run the asynchronous main function
asyncio.run(main())
```
if __name__ == "__main__":
asyncio.run(main())
```
```py
import asyncio
from aiohttp import ClientSession
from osrs.async_api.wiki.prices import WikiPrices, AveragePrices, LatestPrices, TimeSeries, ItemMapping

async def main():
wiki_prices_instance = WikiPrices(user_agent="Your User Agent")

async with ClientSession() as session:
# Fetch item mappings
mappings = await wiki_prices_instance.get_mapping(session=session)
print("Item Mappings:", mappings)

# Fetch latest prices
latest_prices = await wiki_prices_instance.get_latest_prices(session=session)
print("Latest Prices:", latest_prices)

# Fetch average prices
average_prices = await wiki_prices_instance.get_average_prices(session=session, interval=Interval.FIVE_MIN)
print("Average Prices:", average_prices)

# Fetch time series data
item_id = 4151 # Example item ID (Abyssal whip in OSRS)
time_series = await wiki_prices_instance.get_time_series(session=session, item_id=item_id, timestep=Interval.ONE_HOUR)
print("Time Series Data:", time_series)

# Run the asynchronous main function
if __name__ == "__main__":
asyncio.run(main())
```
2 changes: 0 additions & 2 deletions osrs/async_api/osrs/hiscores.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@ async def get(self, mode: Mode, player: str, session: ClientSession) -> PlayerSt
error_msg = (
f"Redirection occured: {response.url} - {response.history[0].url}"
)
logger.error(error_msg)
raise UnexpectedRedirection(error_msg)
elif response.status == 404:
logger.error(f"player: {player} does not exist.")
raise PlayerDoesNotExist(f"player: {player} does not exist.")
elif response.status != 200:
# raises ClientResponseError
Expand Down
Empty file.
9 changes: 9 additions & 0 deletions osrs/async_api/wiki/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from osrs.async_api.wiki.prices import (
AveragePrices,
ItemMapping,
LatestPrices,
TimeSeries,
WikiPrices,
)

__all__ = ["WikiPrices", "AveragePrices", "LatestPrices", "TimeSeries", "ItemMapping"]
212 changes: 212 additions & 0 deletions osrs/async_api/wiki/prices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import logging
from enum import Enum

from aiohttp import ClientSession
from pydantic import BaseModel

from osrs.exceptions import Undefined
from osrs.utils import RateLimiter

logger = logging.getLogger(__name__)


class Interval(str, Enum):
FIVE_MIN = "5m"
ONE_HOUR = "1h"
SIX_HOUR = "6h"
DAY = "24h"


class ItemMapping(BaseModel):
examine: str
id: int
members: bool
lowalch: int | None = None
limit: int | None = None
value: int
highalch: int | None = None
icon: str
name: str


class PriceData(BaseModel):
high: int | None
highTime: int | None
low: int | None
lowTime: int | None


class LatestPrices(BaseModel):
data: dict[str, PriceData]


class AveragePriceData(BaseModel):
avgHighPrice: int | None
highPriceVolume: int | None
avgLowPrice: int | None
lowPriceVolume: int | None


class AveragePrices(BaseModel):
data: dict[str, AveragePriceData]


class TimeSeriesData(BaseModel):
timestamp: int
avgHighPrice: int | None
avgLowPrice: int | None
highPriceVolume: int | None
lowPriceVolume: int | None


class TimeSeries(BaseModel):
data: list[TimeSeriesData]


class WikiPrices:
BASE_URL = "https://prices.runescape.wiki/api/v1"

def __init__(
self,
user_agent: str = None,
proxy: str = "",
rate_limiter: RateLimiter = RateLimiter(),
) -> None:
"""
Initializes the WikiPrices client for accessing OSRS price data.
Args:
user_agent (str): User-Agent like 'price_tracker - @username on Discord'
proxy (str): Optional proxy URL for requests.
rate_limiter (RateLimiter): Rate limiter to control request frequency.
"""
self.proxy = proxy
self.rate_limiter = rate_limiter

if user_agent:
self.user_agent = user_agent
else:
inp = input("""
User-Agent like 'price_tracker - @username on Discord'\n
user_agent:
""")
if not inp:
raise Exception("invalid input")
self.user_agent = inp

async def fetch_data(self, session: ClientSession, url: str, params: dict = {}):
"""
Utility method to fetch data from a specific endpoint, with ratelimiter,
and basic error handling
Args:
session (ClientSession): The HTTP session for making the request.
url (str): The URL endpoint to fetch data from.
params (Optional[dict]): Query parameters for the request.
Returns:
dict: JSON-parsed data from the API response.
"""
await self.rate_limiter.check()

async with session.get(url, proxy=self.proxy, params=params) as response:
if response.status == 400:
error = await response.json()
raise Exception(error)
elif response.status != 200:
response.raise_for_status()
raise Undefined("Unexpected error.")
return await response.json()

async def get_mapping(self, session: ClientSession):
"""
Fetches item mappings containing metadata.
Args:
session (ClientSession): The HTTP session for making the request.
Returns:
List[ItemMapping]: List of ItemMapping objects with metadata for each item.
Example:
>>> session = ClientSession()
>>> wiki_prices = WikiPrices()
>>> mappings = await wiki_prices.get_mapping(session)
>>> print(mappings[0].name) # e.g., '3rd age amulet'
"""
url = f"{self.BASE_URL}/osrs/mapping"
data = await self.fetch_data(session=session, url=url)
return [ItemMapping(**item) for item in data]

async def get_latest_prices(self, session: ClientSession) -> LatestPrices:
"""
Fetches the latest prices for all items.
Args:
session (ClientSession): The HTTP session for making the request.
Returns:
LatestPrices: A dictionary of item IDs to PriceData.
Example:
>>> session = ClientSession()
>>> wiki_prices = WikiPrices()
>>> latest_prices = await wiki_prices.get_latest_prices(session)
>>> print(latest_prices.data["2"].high) # e.g., 240
"""
url = f"{self.BASE_URL}/osrs/latest"
data = await self.fetch_data(session=session, url=url)
return LatestPrices(**data)

async def get_average_prices(
self,
session: ClientSession,
interval: Interval,
timestamp: int | None = None,
) -> AveragePrices:
"""
Fetches average prices at a specified interval (5-minute, 1-hour, etc.).
Args:
session (ClientSession): The HTTP session for the request.
interval (Interval): The time interval ('5m', '1h', etc.) for averaging.
timestamp (Optional[int]): Optional Unix timestamp to retrieve prices for a specific time.
Returns:
AveragePrices: A dictionary of item IDs to AveragePriceData.
Example:
>>> session = ClientSession()
>>> wiki_prices = WikiPrices()
>>> avg_prices = await wiki_prices.get_average_prices(session, Interval.ONE_HOUR)
>>> print(avg_prices.data["2"].avgHighPrice) # e.g., 235
"""
url = f"{self.BASE_URL}/osrs/{interval.value}"
params = {"timestamp": timestamp} if timestamp else {}
data = await self.fetch_data(session=session, url=url, params=params)
return AveragePrices(**data)

async def get_time_series(
self, session: ClientSession, item_id: int, timestep: Interval
) -> TimeSeries:
"""
Fetches time-series data for a specific item and timestep.
Args:
session (ClientSession): The HTTP session for the request.
item_id (int): The item ID.
timestep (Interval): The timestep (e.g., '5m', '1h').
Returns:
TimeSeries: A list of TimeSeriesData entries for the specified item and timestep.
Example:
>>> session = ClientSession()
>>> wiki_prices = WikiPrices()
>>> time_series = await wiki_prices.get_time_series(session, 2, Interval.ONE_HOUR)
>>> print(time_series.data[0].avgHighPrice) # e.g., 1310000
"""
url = f"{self.BASE_URL}/osrs/timeseries"
params = {"id": item_id, "timestep": timestep.value}
data = await self.fetch_data(session=session, url=url, params=params)
return TimeSeries(**data)
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit d634945

Please sign in to comment.