From 5b8e303d26977f2864bd28c044c3c1bfe666b97a Mon Sep 17 00:00:00 2001 From: Step7750 Date: Mon, 4 Nov 2024 18:51:42 -0700 Subject: [PATCH] Inlines Charms in Market Row Listings Similarly to how stickers are inlined, also improves handling when an item has both stickers and charms applied. --- src/lib/components/market/helpers.ts | 117 +++++++++++++----- src/lib/components/market/item_row_wrapper.ts | 4 +- src/lib/types/steam.d.ts | 10 +- 3 files changed, 92 insertions(+), 39 deletions(-) diff --git a/src/lib/components/market/helpers.ts b/src/lib/components/market/helpers.ts index ab698b8b..bce048fe 100644 --- a/src/lib/components/market/helpers.ts +++ b/src/lib/components/market/helpers.ts @@ -1,4 +1,4 @@ -import {rgAsset} from '../../types/steam'; +import {rgAsset, rgInternalDescription} from '../../types/steam'; import {ItemInfo} from '../../bridge/handlers/fetch_inspect_info'; import {AppId, ContextId} from '../../types/steam_constants'; @@ -17,58 +17,109 @@ export function getMarketInspectLink(listingId: string): string | undefined { return asset.market_actions[0].link.replace('%listingid%', listingId).replace('%assetid%', asset.id); } -/** - * Inlines stickers into a market item row HTML showing the image and wear - * - * @param itemNameBlock Element with `.market_listing_item_name_block` - * @param itemInfo Item Info for the item from csfloat API - * @param asset Steam Asset for the item - */ -export function inlineStickers(itemNameBlock: JQuery, itemInfo: ItemInfo, asset: rgAsset) { - if (!itemNameBlock) return; - - if (itemNameBlock.find('.csfloat-stickers-container').length) { - // Don't inline stickers if they're already inlined +function getStickerDescription(itemInfo: ItemInfo, asset: rgAsset): rgInternalDescription | undefined { + if (!itemInfo.stickers?.length) { return; } - const lastDescription = asset.descriptions[asset.descriptions.length - 1]; + if (itemInfo.keychains?.length > 0) { + // if they have a keychain, it is the second last description + return asset.descriptions[asset.descriptions.length - 2]; + } else { + return asset.descriptions[asset.descriptions.length - 1]; + } +} - if (lastDescription.type !== 'html' || !lastDescription.value.includes('sticker')) { +function getKeychainDescription(itemInfo: ItemInfo, asset: rgAsset): rgInternalDescription | undefined { + if (!itemInfo.keychains?.length) { return; } - const nameMatch = lastDescription.value.match(/
([^<].*?): (.*)<\/center>/); - const imagesHtml = lastDescription.value.match(/()/g); + return asset.descriptions[asset.descriptions.length - 1]; +} + +enum AppliedType { + Charm = 'Charm', + Sticker = 'Sticker', +} + +function generateAppliedInlineHTML( + description: rgInternalDescription, + type: AppliedType, + textFormatFn: (index: number) => string +) { + const nameMatch = description.value.match(/
([^<].*?): (.*)<\/center>/); + const imagesHtml = description.value.match(/()/g); if (!nameMatch || !imagesHtml) { - return; + return []; } - const stickerLang = nameMatch[1]; - const stickerNames = nameMatch[2].split(', '); + const parsedType = nameMatch[1]; + const names = nameMatch[2].split(', '); - const result = imagesHtml - .map((imageHtml, i) => { - const url = - stickerLang === 'Sticker' - ? `https://steamcommunity.com/market/listings/730/${stickerLang} | ${stickerNames[i]}` - : `https://steamcommunity.com/market/search?q=${stickerLang} | ${stickerNames[i]}`; + return imagesHtml.map((imageHtml, i) => { + const url = + parsedType === type + ? `https://steamcommunity.com/market/listings/730/${parsedType} | ${names[i]}` + : `https://steamcommunity.com/market/search?q=${parsedType} | ${names[i]}`; - const sticker = itemInfo.stickers[i]; - - return ` + return ` ${imagesHtml[i]} - ${Math.round(100 * (sticker?.wear || 0)) + '%'} + ${textFormatFn(i)} `; - }) - .reduce((acc, v) => acc + v, ''); + }); +} + +function generateStickerInlineHTML(itemInfo: ItemInfo, asset: rgAsset): string[] { + const description = getStickerDescription(itemInfo, asset); + + if (!description || description.type !== 'html' || !description.value.includes('sticker')) { + return []; + } + + return generateAppliedInlineHTML(description, AppliedType.Sticker, (index) => { + return `${Math.round(100 * (itemInfo.stickers[index]?.wear || 0)) + '%'}`; + }); +} + +function generateKeychainInlineHTML(itemInfo: ItemInfo, asset: rgAsset): string[] { + const description = getKeychainDescription(itemInfo, asset); + + if (!description || description.type !== 'html' || !description.value.includes('sticker')) { + return []; + } + + return generateAppliedInlineHTML(description, AppliedType.Charm, (index) => { + return `#${itemInfo.keychains[index]?.pattern}`; + }); +} + +/** + * Inlines stickers into a market item row HTML showing the image and wear + * + * @param itemNameBlock Element with `.market_listing_item_name_block` + * @param itemInfo Item Info for the item from csfloat API + * @param asset Steam Asset for the item + */ +export function inlineStickersAndKeychains(itemNameBlock: JQuery, itemInfo: ItemInfo, asset: rgAsset) { + if (!itemNameBlock) return; + + if (itemNameBlock.find('.csfloat-stickers-container').length) { + // Don't inline stickers if they're already inlined + return; + } + + const blobs = [...generateStickerInlineHTML(itemInfo, asset), ...generateKeychainInlineHTML(itemInfo, asset)]; + if (blobs.length === 0) { + return; + } itemNameBlock.prepend(`
- ${result} + ${blobs.reduce((acc, v) => acc + v, '')}
`); } diff --git a/src/lib/components/market/item_row_wrapper.ts b/src/lib/components/market/item_row_wrapper.ts index 830ce255..1e7cd156 100644 --- a/src/lib/components/market/item_row_wrapper.ts +++ b/src/lib/components/market/item_row_wrapper.ts @@ -7,7 +7,7 @@ import {cache} from 'decorator-cache-getter'; import {rgAsset, ListingData} from '../../types/steam'; import {gFloatFetcher} from '../../services/float_fetcher'; import {ItemInfo} from '../../bridge/handlers/fetch_inspect_info'; -import {getMarketInspectLink, inlineEasyInspect, inlineStickers} from './helpers'; +import {getMarketInspectLink, inlineEasyInspect, inlineStickersAndKeychains} from './helpers'; import {formatSeed, getFadePercentage, isSkin, renderClickableRank, floor, isCharm} from '../../utils/skin'; import {gFilterService} from '../../services/filter'; import {AppId, ContextId, Currency} from '../../types/steam_constants'; @@ -112,7 +112,7 @@ export class ItemRowWrapper extends FloatElement { } if (this.itemInfo && this.asset) { - inlineStickers( + inlineStickersAndKeychains( $J(this).parent().parent().find('.market_listing_item_name_block'), this.itemInfo, this.asset diff --git a/src/lib/types/steam.d.ts b/src/lib/types/steam.d.ts index bde6eda0..a4abd9e9 100644 --- a/src/lib/types/steam.d.ts +++ b/src/lib/types/steam.d.ts @@ -35,6 +35,11 @@ export interface WalletInfo { wallet_currency: number; } +export interface rgInternalDescription { + type: string; + value: string; +} + // rgDescriptions export interface rgDescription { appid: AppId; @@ -42,10 +47,7 @@ export interface rgDescription { background_color: string; classid: string; commodity: number; - descriptions: { - type: string; - value: string; - }[]; + descriptions: rgInternalDescription[]; fraudwarnings?: string[]; icon_url: string; icon_url_large: string;