refactor: simplify superchat amount extraction and display logic

This commit is contained in:
Yusuf İpek
2025-10-05 04:42:47 +03:00
parent 29492fb75e
commit 773d35e85e
3 changed files with 17 additions and 51 deletions
+15 -50
View File
@@ -157,7 +157,6 @@ function extractBadges(item: any): Badge[] {
} }
function extractSuperChatInfo(item: any): SuperChatInfo | undefined { function extractSuperChatInfo(item: any): SuperChatInfo | undefined {
// Support multiple superchat-like types from Innertube
const superTypes = new Set([ const superTypes = new Set([
'LiveChatPaidMessage', 'LiveChatPaidMessage',
'LiveChatPaidSticker', 'LiveChatPaidSticker',
@@ -168,8 +167,7 @@ function extractSuperChatInfo(item: any): SuperChatInfo | undefined {
const isSuper = superTypes.has(typeName) || !!(item.purchase_amount_text || item.purchaseAmountText); const isSuper = superTypes.has(typeName) || !!(item.purchase_amount_text || item.purchaseAmountText);
if (!isSuper) return undefined; if (!isSuper) return undefined;
// Try multiple possible field names for the amount (search shallow + nested header) let amountText = '';
let amount = '';
const candidates = [ const candidates = [
item.purchase_amount_text, item.purchase_amount_text,
item.purchaseAmountText, item.purchaseAmountText,
@@ -185,58 +183,25 @@ function extractSuperChatInfo(item: any): SuperChatInfo | undefined {
if (typeof v === 'number') return String(v); if (typeof v === 'number') return String(v);
if (typeof v.simpleText === 'string') return v.simpleText; if (typeof v.simpleText === 'string') return v.simpleText;
if (Array.isArray(v.runs)) return v.runs.map((r: any) => r.text ?? '').join(''); if (Array.isArray(v.runs)) return v.runs.map((r: any) => r.text ?? '').join('');
if (typeof v.toString === 'function') return v.toString();
return ''; return '';
} }
for (const v of candidates) { for (const v of candidates) {
amount = toText(v); amountText = toText(v);
if (amount) break; if (amountText) break;
} }
// Fallback deep scan for a purchase/amount text-like field let amount = 'Super Chat';
if (!amount) { let currency = '';
try {
const stack: any[] = [item]; if (amountText) {
const seen = new Set<any>(); const match = amountText.match(/^([\$\€\£\¥\₹\₺A-Z]+)?\s*([\d,\.]+)/);
while (stack.length) { if (match) {
const cur = stack.pop(); currency = match[1] || '';
if (!cur || typeof cur !== 'object' || seen.has(cur)) continue; amount = match[2];
seen.add(cur);
for (const [k, v] of Object.entries(cur)) {
if (/purchase.*amount.*text|purchaseAmountText|amountText|purchase_amount_text/i.test(k)) {
amount = toText(v);
if (amount) throw new Error('_found');
}
if (v && typeof v === 'object') stack.push(v);
}
}
} catch (e: any) {
if (e?.message !== '_found') throw e;
} }
} }
// Last resort: search any string-like leaf for a currency pattern
if (!amount) {
const currencyPattern = /([€$£¥₹]|AUD|USD|EUR|GBP|JPY|INR)\s?\d{1,3}(?:[\,\s]?\d{3})*(?:[\.,]\d{1,2})?/i;
const stack: any[] = [item];
const seen = new Set<any>();
while (stack.length) {
const cur = stack.pop();
if (!cur || typeof cur !== 'object' || seen.has(cur)) continue;
seen.add(cur);
for (const v of Object.values(cur)) {
if (typeof v === 'string') {
const m = v.match(currencyPattern);
if (m) { amount = m[0]; stack.length = 0; break; }
} else if (v && typeof v === 'object') {
stack.push(v);
}
}
}
}
// Normalize color; Innertube often provides ARGB/number
let rawColor = item.body_background_color ?? item.bodyBackgroundColor ?? item.headerBackgroundColor; let rawColor = item.body_background_color ?? item.bodyBackgroundColor ?? item.headerBackgroundColor;
let color = '#1e3a8a'; let color = '#1e3a8a';
if (rawColor != null) { if (rawColor != null) {
@@ -250,8 +215,8 @@ function extractSuperChatInfo(item: any): SuperChatInfo | undefined {
} }
return { return {
amount: amount || 'Super Chat', amount,
currency: item.currency ?? 'USD', currency,
color color
}; };
} }
@@ -280,10 +245,10 @@ function normalizeAction(action: any): ChatMessage | null {
// Extract membership level for new members // Extract membership level for new members
let membershipLevel: string | undefined; let membershipLevel: string | undefined;
if (isMembership || isGiftPurchase || isGiftReceived) { if (isMembership || isGiftPurchase || isGiftReceived || isPaid) {
membershipLevel = item.header_subtext?.toString() || membershipLevel = item.header_subtext?.toString() ||
item.header_primary_text?.toString() || item.header_primary_text?.toString() ||
'New member'; (isPaid ? undefined : 'New member');
} }
return { return {
+1 -1
View File
@@ -409,7 +409,7 @@ function ChatItem({ message, isSelected, onSelect }: ChatItemProps) {
</div> </div>
{message.superChat && ( {message.superChat && (
<div className="chatItem__superchat" style={{ backgroundColor: message.superChat.color }}> <div className="chatItem__superchat" style={{ backgroundColor: message.superChat.color }}>
💰 {message.superChat.amount} {message.superChat.currency} 💰 {message.superChat.currency}{message.superChat.amount}
</div> </div>
)} )}
<p className="chatItem__text">{message.text}</p> <p className="chatItem__text">{message.text}</p>
+1
View File
@@ -519,6 +519,7 @@ main {
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
padding-right: 0.25rem; padding-right: 0.25rem;
padding-bottom: 1rem; /* Add space at the bottom */
min-height: 0; min-height: 0;
} }