Skip to content

Commit

Permalink
Merge pull request #53 from flbraun/craftofexile-integration
Browse files Browse the repository at this point in the history
Craft of Exile integration
  • Loading branch information
flbraun authored Mar 16, 2024
2 parents 91e4f86 + 4693cd2 commit 3c9e087
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 1 deletion.
Binary file added assets/craftofexile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions data/craftofexile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import dataclasses
import functools
import http
import json
from typing import Any

from .types import URL
from .utils import DefaultHTTPSession


@dataclasses.dataclass(frozen=True)
class CraftOfExileIndex:
raw: dict[str, tuple[int, int]] # (b, bi)

def match(self, item_name: str) -> tuple[int, int] | None:
return self.raw.get(item_name, None)


@functools.cache
def get_craftofexile_index(craftofexile_session: DefaultHTTPSession) -> CraftOfExileIndex:
"""
Downloads current data from Craft of Exile and makes it available as a sort-of index.
"""
index = {}

url = 'https://www.craftofexile.com/json/data/main/poec_data.json'
res = craftofexile_session.get(url)
assert res.status_code == http.HTTPStatus.OK, f'{res.status_code} {url}'

# the endpoint returns a JSON string, but its prefixed with some junk that
# make it invalid JSON. clean that up.
junk = 'poecd='
assert res.text.startswith(junk), f'{res.text[:20]}'
res_parsed = json.loads(res.text[len(junk):])

item: dict[str, Any]
for item in res_parsed['bitems']['seq']:
index[item['name_bitem']] = (int(item['id_base']), int(item['id_bitem']))

return CraftOfExileIndex(raw=index)


def make_craftofexile_url(b: int, bi: int) -> URL | None:
"""
b is CoE's internal id for the type of crafting base, e.g. 33 for "Gloves (STR)".
bi is CoE's internal id for the concrete crafting base, e.g. 7595 for "Spiked Gloves".
"""
return f'https://www.craftofexile.com/?b={b}&bi={bi}'
1 change: 1 addition & 0 deletions data/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Entry:
tft_url: URL | None = None
tool_url: URL | None = None
antiquary_url: URL | None = None
craftofexile_url: URL | None = None


def make_wiki_url(item_name: str) -> URL:
Expand Down
7 changes: 7 additions & 0 deletions data/wiki.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from tabulate import tabulate

from .antiquary import make_antiquary_url
from .craftofexile import get_craftofexile_index, make_craftofexile_url
from .leagues import League
from .ninja import NinjaCategory, get_ninja_index, make_ninja_url
from .trade import automake_trade_url
Expand Down Expand Up @@ -229,9 +230,11 @@ def get_items(league: League) -> Generator[Entry, None, None]:
DefaultHTTPSession() as wiki_session,
DefaultHTTPSession() as ninja_session,
DefaultHTTPSession() as antiquary_session,
DefaultHTTPSession() as craftofexile_session,
):
ninja_unknown = []
ninja_index = get_ninja_index(ninja_session, league)
craftofexile_index = get_craftofexile_index(craftofexile_session)

for item in iter_wiki_query(
wiki_session,
Expand Down Expand Up @@ -272,6 +275,10 @@ def get_items(league: League) -> Generator[Entry, None, None]:
if tradable:
entry_kwargs['trade_url'] = automake_trade_url(league, ninja_category, name, base_item=base_item)

craftofexile_ids = craftofexile_index.match(name)
if craftofexile_ids is not None:
entry_kwargs['craftofexile_url'] = make_craftofexile_url(*craftofexile_ids)

yield Entry(**entry_kwargs)

print(
Expand Down
3 changes: 3 additions & 0 deletions src/main/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const userSettingsSchema = {
tradeEnabled: { type: 'boolean' },
tftEnabled: { type: 'boolean' },
antiquaryEnabled: { type: 'boolean' },
craftofexileEnabled: { type: 'boolean' },
toolsEnabled: { type: 'boolean' },
league: {
type: 'string',
Expand All @@ -29,6 +30,7 @@ setdefault(userSettings, 'ninjaEnabled', true)
setdefault(userSettings, 'tradeEnabled', true)
setdefault(userSettings, 'tftEnabled', false)
setdefault(userSettings, 'antiquaryEnabled', false)
setdefault(userSettings, 'craftofexileEnabled', false)
setdefault(userSettings, 'toolsEnabled', true)
setdefault(userSettings, 'league', 'challenge')
setdefault(userSettings, 'paletteShortcut', 'CommandOrControl+P')
Expand All @@ -41,6 +43,7 @@ userSettings.getEnabledResultTypes = () => {
if (userSettings.get('tradeEnabled')) enabled.push('trade')
if (userSettings.get('tftEnabled')) enabled.push('tft')
if (userSettings.get('antiquaryEnabled')) enabled.push('antiquary')
if (userSettings.get('craftofexileEnabled')) enabled.push('craftofexile')
if (userSettings.get('toolsEnabled')) enabled.push('tools')
return enabled
}
Expand Down
9 changes: 9 additions & 0 deletions src/main/tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ exports.createTray = (leftClickCallback, window) => {
window.webContents.send('enabledResultTypesChanged', userSettings.getEnabledResultTypes())
},
},
{
type: 'checkbox',
label: 'Craft of Exile',
checked: userSettings.get('craftofexileEnabled'),
click: (menuItem) => {
userSettings.set('craftofexileEnabled', menuItem.checked)
window.webContents.send('enabledResultTypesChanged', userSettings.getEnabledResultTypes())
},
},
{
type: 'checkbox',
label: 'Tools',
Expand Down
11 changes: 10 additions & 1 deletion src/renderer/palette.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ const ICONS = {
TRADE: '../../assets/trade.png',
TFT: '../../assets/tft.png',
ANTIQUARY: '../../assets/antiquary.png',
CRAFTOFEXILE: '../../assets/craftofexile.png',
GOTO: '../../assets/goto.png',
}

const resultTypes = ['wiki', 'poedb', 'ninja', 'trade', 'tft', 'antiq', 'tool']
const resultTypes = ['wiki', 'poedb', 'ninja', 'trade', 'tft', 'antiq', 'craft', 'tool']
const specialSearchPrefixes = resultTypes.map(e => `${e}:`)

// register click handlers that hide the window when clicking outside of the palette area
Expand Down Expand Up @@ -172,6 +173,14 @@ const makePalette = (searchInput, resultlist) => {
) {
addResultNode(ICONS.ANTIQUARY, r.display_text, r.antiquary_url)
}
if (
enabledResultTypes.includes('craftofexile')
&& [null, 'craft'].includes(targetedSearch)
&& Object.prototype.hasOwnProperty.call(r, 'craftofexile_url')
&& r.craftofexile_url !== null
) {
addResultNode(ICONS.CRAFTOFEXILE, `Craft ${r.display_text}`, r.craftofexile_url)
}
if (
enabledResultTypes.includes('tools')
&& [null, 'tool'].includes(targetedSearch)
Expand Down
1 change: 1 addition & 0 deletions src/renderer/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const POEPALETTE_MINISEARCH = new MiniSearch({
'trade_url',
'tft_url',
'antiquary_url',
'craftofexile_url',
'tool_url',
],
})
Expand Down

0 comments on commit 3c9e087

Please sign in to comment.