Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: swap to uicons.js lib #908

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"strip-json-comments": "^3.1.1",
"suncalc": "^1.9.0",
"telegraf": "^4.12.0",
"uicons.js": "2.0.2",
"winston": "^3.9.0",
"winston-daily-rotate-file": "^5.0.0"
},
Expand Down
211 changes: 52 additions & 159 deletions src/lib/uicons.js
Original file line number Diff line number Diff line change
@@ -1,123 +1,25 @@
const axios = require('axios')
// @ts-check

const { default: axios } = require('axios')
const { Mutex } = require('async-mutex')
const { UICONS } = require('uicons.js')

const mutex = new Mutex()
const uiconsIndex = {}
const lastRetrieved = {}

function resolvePokemonIcon(availPokemon, imageType, pokemonId, form = 0, evolution = 0, gender = 0, costume = 0, alignment = 0, shiny = false) {
const evolutionSuffixes = evolution ? [`_e${evolution}`, ''] : ['']
const formSuffixes = form ? [`_f${form}`, ''] : ['']
const costumeSuffixes = costume ? [`_c${costume}`, ''] : ['']
const genderSuffixes = gender ? [`_g${gender}`, ''] : ['']
const alignmentSuffixes = alignment ? [`_a${alignment}`, ''] : ['']
const shinySuffixes = shiny ? ['_s', ''] : ['']
for (const evolutionSuffix of evolutionSuffixes) {
for (const formSuffix of formSuffixes) {
for (const costumeSuffix of costumeSuffixes) {
for (const genderSuffix of genderSuffixes) {
for (const alignmentSuffix of alignmentSuffixes) {
for (const shinySuffix of shinySuffixes) {
const result = `${pokemonId}${evolutionSuffix}${formSuffix}${costumeSuffix}${genderSuffix}${alignmentSuffix}${shinySuffix}.${imageType}`
if (availPokemon.has(result)) return result
}
}
}
}
}
}
return `0.${imageType}` // substitute
}

function resolveGymIcon(availGym, imageType, teamId, trainerCount = 0, inBattle = false, ex = false) {
const trainerSuffixes = trainerCount ? [`_t${trainerCount}`, ''] : ['']
const inBattleSuffixes = inBattle ? ['_b', ''] : ['']
const exSuffixes = ex ? ['_ex', ''] : ['']
for (const trainerSuffix of trainerSuffixes) {
for (const inBattleSuffix of inBattleSuffixes) {
for (const exSuffix of exSuffixes) {
const result = `${teamId}${trainerSuffix}${inBattleSuffix}${exSuffix}.${imageType}`
if (availGym.has(result)) return result
}
}
}
return `0.${imageType}` // substitute
}

function resolvePokestopIcon(availPokestop, imageType, lureId, invasionActive = false, incidentDisplayType = 0, questActive = false) {
const invasionSuffixes = invasionActive ? ['_i', ''] : ['']
const incidentDisplayTypeSuffixes = incidentDisplayType ? [`${incidentDisplayType}`, ''] : ['']
const questSuffixes = questActive ? ['_q', ''] : ['']
for (const invasionSuffix of invasionSuffixes) {
for (const incidentDisplayTypeSuffix of incidentDisplayTypeSuffixes) {
for (const questSuffix of questSuffixes) {
const result = `${lureId}${invasionSuffix}${incidentDisplayTypeSuffix}${questSuffix}.${imageType}`
if (availPokestop.has(result)) return result
}
}
}
return `0.${imageType}` // substitute
}

function resolveEggIcon(availEgg, imageType, level, hatched = false, ex = false) {
const hatchedSuffixes = hatched ? ['_h', ''] : ['']
const exSuffixes = ex ? ['_ex', ''] : ['']
for (const hatchedSuffix of hatchedSuffixes) {
for (const exSuffix of exSuffixes) {
const result = `${level}${hatchedSuffix}${exSuffix}.${imageType}`
if (availEgg.has(result)) return result
}
}
return `0.${imageType}` // substitute
}

function resolveWeatherIcon(availWeather, imageType, weatherId) {
const result = `${weatherId}.${imageType}`
if (availWeather.has(result)) return result

return `0.${imageType}` // substitute
}

function resolveInvasionIcon(availInvasion, imageType, gruntType) {
const result = `${gruntType}.${imageType}`
if (availInvasion.has(result)) return result

return `0.${imageType}` // substitute
}

function resolveTypeIcon(availTypes, imageType, typeId) {
const result = `${typeId}.${imageType}`
if (availTypes.has(result)) return result

return `0.${imageType}` // substitute
}

function resolveTeamIcon(availTeams, imageType, teamId) {
const result = `${teamId}.${imageType}`
if (availTeams.has(result)) return result

return `0.${imageType}` // substitute
}

function resolveItemIcon(itemAvail, imageType, id, amount = 0) {
if (amount) {
const resultAmount = `${id}_a${amount}.${imageType}`
if (itemAvail.has(resultAmount)) return resultAmount
}
const result = `${id}.${imageType}`
if (itemAvail.has(result)) return result

return `0.${imageType}` // substitute
}
const uiconsIndex = /** @type {Record<string, UICONS | null>} */ ({})
const lastRetrieved = /** @type {Record<string, number>} */ ({})

const maxAge = 60 * 60 * 1000 // 1 hour

/**
* @param {any} log
* @param {string} baseUrl
* @returns {Promise<UICONS | null>}
*/
async function getAvailableIcons(log, baseUrl) {
let currentSet
let lastRetrievedDate
let currentSet = uiconsIndex[baseUrl]
let lastRetrievedDate = lastRetrieved[baseUrl]
try {
currentSet = uiconsIndex[baseUrl]
lastRetrievedDate = lastRetrieved[baseUrl]
if (currentSet === undefined || lastRetrievedDate === undefined || Date.now() - lastRetrievedDate > maxAge) {
await mutex.runExclusive(async () => {
currentSet = uiconsIndex[baseUrl]
Expand Down Expand Up @@ -147,27 +49,8 @@ async function getAvailableIcons(log, baseUrl) {
break
}
case 200: {
const results = response.data
currentSet = {
raid: {
egg: new Set(results.raid ? results.raid.egg : []),
},
gym: new Set(results.gym),
team: new Set(results.team),
weather: new Set(results.weather),
pokestop: new Set(results.pokestop),
reward: {
item: new Set(results.reward ? results.reward.item : []),
stardust: new Set(results.reward ? results.reward.stardust : []),
candy: new Set(results.reward ? results.reward.candy : []),
xl_candy: new Set(results.reward ? results.reward.xl_candy : []),
mega_resource: new Set(results.reward ? results.reward.mega_resource : []),
},
invasion: new Set(results.invasion),
pokemon: new Set(results.pokemon),
type: new Set(results.type),
}
uiconsIndex[baseUrl] = currentSet
uiconsIndex[baseUrl] = new UICONS(baseUrl).init(response.data)
currentSet = uiconsIndex[baseUrl]
break
}
default: {
Expand All @@ -188,6 +71,12 @@ async function getAvailableIcons(log, baseUrl) {
}

class Uicons {
/**
* @param {string} url
* @param {string} [imageType]
* @param {Console} [log]
* @param {boolean} [fallback]
*/
constructor(url, imageType, log, fallback) {
this.url = url.endsWith('/') ? url.slice(0, -1) : url
this.imageType = imageType || 'png'
Expand All @@ -197,85 +86,89 @@ class Uicons {

async isUiconsRepository() {
const currentSet = await getAvailableIcons(this.log, this.url)

return !!currentSet
}

async pokemonIcon(pokemonId, form = 0, evolution = 0, gender = 0, costume = 0, alignment = 0, shiny = false) {
async pokemonIcon(pokemonId = 0, form = 0, evolution = 0, gender = 0, costume = 0, alignment = 0, shiny = false, bread = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/pokemon/${resolvePokemonIcon(currentSet.pokemon, this.imageType, pokemonId, form, evolution, gender, costume, alignment, shiny)}`
if (currentSet) return currentSet.pokemon(pokemonId, evolution, form, costume, gender, alignment, bread, shiny)
if (this.fallback) return `${this.url}/pokemon_icon_${pokemonId.toString().padStart(3, '0')}_${form ? form.toString() : '00'}${evolution > 0 ? `_${evolution.toString()}` : ''}.${this.imageType}`
TurtIeSocks marked this conversation as resolved.
Show resolved Hide resolved
return null
}

async eggIcon(level, hatched = false, ex = false) {
async eggIcon(level = 0, hatched = false, ex = false) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/raid/egg/${resolveEggIcon(currentSet.raid.egg, this.imageType, level, hatched, ex)}`
if (currentSet) return currentSet.raidEgg(level, hatched, ex)
if (this.fallback) return `${this.url}/egg${level}.${this.imageType}`
return null
}

async invasionIcon(gruntType) {
async invasionIcon(gruntType = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/invasion/${resolveInvasionIcon(currentSet.invasion, this.imageType, gruntType)}` : null
return currentSet ? currentSet.invasion(gruntType) : null
}

async typeIcon(typeId) {
async typeIcon(typeId = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/type/${resolveTypeIcon(currentSet.type, this.imageType, typeId)}` : null
return currentSet ? currentSet.type(typeId) : null
}

async teamIcon(teamId) {
async teamIcon(teamId = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/team/${resolveTeamIcon(currentSet.type, this.imageType, teamId)}` : null
return currentSet ? currentSet.team(teamId) : null
}

async rewardItemIcon(itemId) {
async rewardItemIcon(itemId = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/reward/item/${resolveItemIcon(currentSet.reward.item, this.imageType, itemId)}`
if (currentSet) return currentSet.reward('item', itemId)
if (this.fallback) return `${this.url}/rewards/reward_${itemId}_1.${this.imageType}`
return null
}

async rewardStardustIcon(amount) {
async rewardStardustIcon(amount = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/reward/stardust/${resolveItemIcon(currentSet.reward.stardust, this.imageType, amount)}`
if (currentSet) return currentSet.reward('stardust', amount)
if (this.fallback) return `${this.url}/rewards/reward_stardust.${this.imageType}`
return null
}

async rewardMegaEnergyIcon(pokemonId, amount) {
async rewardMegaEnergyIcon(pokemonId = 0, amount = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/reward/mega_resource/${resolveItemIcon(currentSet.reward.mega_resource, this.imageType, pokemonId, amount)}`
if (currentSet) return currentSet.reward('mega_resource', pokemonId, amount)
if (this.fallback) return `${this.url}/rewards/reward_mega_energy_${pokemonId}.${this.imageType}`
return null
}

async rewardCandyIcon(pokemonId, amount) {
async rewardCandyIcon(pokemonId = 0, amount = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
if (currentSet) return `${this.url}/reward/candy/${resolveItemIcon(currentSet.reward.candy, this.imageType, pokemonId, amount)}`
if (currentSet) return currentSet.reward('candy', pokemonId, amount)
if (this.fallback) return `${this.url}/rewards/reward_candy_${pokemonId}.${this.imageType}`
return null
}

async rewardXlCandyIcon(pokemonId, amount) {
async rewardXlCandyIcon(pokemonId = 0, amount = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? currentSet.reward('xl_candy', pokemonId, amount) : null
}

async gymIcon(teamId = 0, trainerCount = 0, inBattle = false, ex = false, ar = false, power = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/reward/xl_candy/${resolveItemIcon(currentSet.reward.xl_candy, this.imageType, pokemonId, amount)}` : null
return currentSet ? currentSet.gym(teamId, trainerCount, inBattle, ex, ar, power) : null
}

async gymIcon(teamId, trainerCount = 0, inBattle = false, ex = false) {
async weatherIcon(weatherId = 0, severity = 0, timeOfDay = 'day') {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/gym/${resolveGymIcon(currentSet.gym, this.imageType, teamId, trainerCount, inBattle, ex)}` : null
return currentSet ? currentSet.weather(weatherId, severity, timeOfDay) : null
}

async weatherIcon(weatherId) {
async pokestopIcon(lureId = 0, invasionActive = false, incidentDisplayType = 0, questActive = false, ar = false, power = 0) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/weather/${resolveWeatherIcon(currentSet.weather, this.imageType, weatherId)}` : null
return currentSet ? currentSet.pokestop(lureId, incidentDisplayType || !!invasionActive, questActive, ar, power) : null
}

async pokestopIcon(lureId = 0, invasionActive = false, incidentDisplayType = 0, questActive = false) {
async stationIcon(active = false) {
const currentSet = await getAvailableIcons(this.log, this.url)
return currentSet ? `${this.url}/pokestop/${resolvePokestopIcon(currentSet.pokestop, this.imageType, lureId, invasionActive, incidentDisplayType, questActive)}` : null
return currentSet ? currentSet.station(active) : null
}
}

Expand Down