test card-old merge slim
This commit is contained in:
@@ -52,14 +52,9 @@ function toUtcDatetime(dateStr: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum cards to migrate (ATProto record size limit ~256KB)
|
|
||||||
const MAX_MIGRATE_CARDS = 1200
|
|
||||||
|
|
||||||
// Perform migration
|
// Perform migration
|
||||||
export async function performMigration(user: OldApiUser, cards: OldApiCard[]): Promise<boolean> {
|
export async function performMigration(user: OldApiUser, cards: OldApiCard[]): Promise<boolean> {
|
||||||
// Limit cards to avoid exceeding ATProto record size limit
|
const checksum = generateChecksum(user, cards)
|
||||||
const limitedCards = cards.slice(0, MAX_MIGRATE_CARDS)
|
|
||||||
const checksum = generateChecksum(user, limitedCards)
|
|
||||||
|
|
||||||
// Convert user data (only required + used fields, matching lexicon types)
|
// Convert user data (only required + used fields, matching lexicon types)
|
||||||
// Note: ATProto doesn't support float, so planet is converted to integer
|
// Note: ATProto doesn't support float, so planet is converted to integer
|
||||||
@@ -74,20 +69,70 @@ export async function performMigration(user: OldApiUser, cards: OldApiCard[]): P
|
|||||||
updatedAt: toUtcDatetime(user.updated_at),
|
updatedAt: toUtcDatetime(user.updated_at),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert card data (only required + used fields)
|
// Merge cards by card number (sum cp, keep highest status)
|
||||||
const cardData = limitedCards.map(c => ({
|
const cardGroups = new Map<number, {
|
||||||
id: c.id,
|
card: number
|
||||||
card: c.card,
|
totalCp: number
|
||||||
cp: c.cp,
|
count: number
|
||||||
status: c.status || 'normal',
|
bestStatus: string
|
||||||
skill: c.skill || 'normal',
|
bestSkill: string
|
||||||
createdAt: toUtcDatetime(c.created_at),
|
latestCreatedAt: string
|
||||||
}))
|
}>()
|
||||||
|
|
||||||
|
for (const c of cards) {
|
||||||
|
const existing = cardGroups.get(c.card)
|
||||||
|
if (existing) {
|
||||||
|
existing.totalCp += c.cp
|
||||||
|
existing.count++
|
||||||
|
// Keep highest status (super > shiny > first > normal)
|
||||||
|
if (statusPriority(c.status) > statusPriority(existing.bestStatus)) {
|
||||||
|
existing.bestStatus = c.status || 'normal'
|
||||||
|
}
|
||||||
|
if (c.skill && c.skill !== 'normal') {
|
||||||
|
existing.bestSkill = c.skill
|
||||||
|
}
|
||||||
|
// Keep latest createdAt
|
||||||
|
if (c.created_at > existing.latestCreatedAt) {
|
||||||
|
existing.latestCreatedAt = c.created_at
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cardGroups.set(c.card, {
|
||||||
|
card: c.card,
|
||||||
|
totalCp: c.cp,
|
||||||
|
count: 1,
|
||||||
|
bestStatus: c.status || 'normal',
|
||||||
|
bestSkill: c.skill || 'normal',
|
||||||
|
latestCreatedAt: c.created_at
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert merged data to card array
|
||||||
|
const cardData = Array.from(cardGroups.values())
|
||||||
|
.sort((a, b) => a.card - b.card)
|
||||||
|
.map(g => ({
|
||||||
|
id: g.card, // Use card number as id
|
||||||
|
card: g.card,
|
||||||
|
cp: g.totalCp,
|
||||||
|
status: g.bestStatus,
|
||||||
|
skill: g.bestSkill,
|
||||||
|
createdAt: toUtcDatetime(g.latestCreatedAt),
|
||||||
|
}))
|
||||||
|
|
||||||
const result = await saveMigratedCardData(userData, cardData, checksum)
|
const result = await saveMigratedCardData(userData, cardData, checksum)
|
||||||
return result !== null
|
return result !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status priority for comparison (higher = better)
|
||||||
|
function statusPriority(status: string): number {
|
||||||
|
switch (status) {
|
||||||
|
case 'super': return 3
|
||||||
|
case 'shiny': return 2
|
||||||
|
case 'first': return 1
|
||||||
|
default: return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render migration icon for profile (shown when user has api.syui.ai account)
|
// Render migration icon for profile (shown when user has api.syui.ai account)
|
||||||
export function renderMigrationIcon(handle: string, hasOldApi: boolean, hasMigrated: boolean): string {
|
export function renderMigrationIcon(handle: string, hasOldApi: boolean, hasMigrated: boolean): string {
|
||||||
if (!hasOldApi) return ''
|
if (!hasOldApi) return ''
|
||||||
@@ -102,15 +147,6 @@ export function renderMigrationIcon(handle: string, hasOldApi: boolean, hasMigra
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert status to rarity
|
|
||||||
function statusToRare(status: string): number {
|
|
||||||
switch (status) {
|
|
||||||
case 'super': return 3 // unique
|
|
||||||
case 'shiny': return 2 // shiny (assumed from skill or special status)
|
|
||||||
case 'first': return 1 // rare
|
|
||||||
default: return 0 // normal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render migration page (simplified)
|
// Render migration page (simplified)
|
||||||
export function renderMigrationPage(
|
export function renderMigrationPage(
|
||||||
@@ -147,42 +183,39 @@ export function renderMigrationPage(
|
|||||||
buttonHtml = `<button id="migrate-btn" class="migrate-btn">Migrate</button>`
|
buttonHtml = `<button id="migrate-btn" class="migrate-btn">Migrate</button>`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Card grid (same style as /card page)
|
// Card grid - merge by card number (same as migration logic)
|
||||||
const cardGroups = new Map<number, { card: OldApiCard, count: number, maxCp: number, rare: number }>()
|
const cardGroups = new Map<number, { card: number, totalCp: number, rare: number }>()
|
||||||
for (const card of oldApiCards) {
|
for (const c of oldApiCards) {
|
||||||
const existing = cardGroups.get(card.card)
|
const existing = cardGroups.get(c.card)
|
||||||
const rare = statusToRare(card.status)
|
const rare = statusPriority(c.status)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.count++
|
existing.totalCp += c.cp
|
||||||
if (card.cp > existing.maxCp) existing.maxCp = card.cp
|
|
||||||
if (rare > existing.rare) existing.rare = rare
|
if (rare > existing.rare) existing.rare = rare
|
||||||
} else {
|
} else {
|
||||||
cardGroups.set(card.card, { card, count: 1, maxCp: card.cp, rare })
|
cardGroups.set(c.card, { card: c.card, totalCp: c.cp, rare })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedGroups = Array.from(cardGroups.values())
|
const sortedGroups = Array.from(cardGroups.values())
|
||||||
.sort((a, b) => a.card.card - b.card.card)
|
.sort((a, b) => a.card - b.card)
|
||||||
|
|
||||||
const cardsHtml = sortedGroups.map(({ card, count, maxCp, rare }) => {
|
const cardsHtml = sortedGroups.map(({ card, totalCp, rare }) => {
|
||||||
const rarityClass = rare === 3 ? 'unique' : rare === 2 ? 'shiny' : rare === 1 ? 'rare' : ''
|
const rarityClass = rare === 3 ? 'unique' : rare === 2 ? 'shiny' : rare === 1 ? 'rare' : ''
|
||||||
const effectsHtml = rarityClass ? `
|
const effectsHtml = rarityClass ? `
|
||||||
<div class="card-status pattern-${rarityClass}"></div>
|
<div class="card-status pattern-${rarityClass}"></div>
|
||||||
<div class="card-status color-${rarityClass}"></div>
|
<div class="card-status color-${rarityClass}"></div>
|
||||||
` : ''
|
` : ''
|
||||||
const countBadge = count > 1 ? `<span class="card-count">x${count}</span>` : ''
|
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="card-item">
|
<div class="card-item">
|
||||||
<div class="card-wrapper">
|
<div class="card-wrapper">
|
||||||
<div class="card-reflection">
|
<div class="card-reflection">
|
||||||
<img src="/card/${card.card}.webp" alt="Card ${card.card}" loading="lazy" />
|
<img src="/card/${card}.webp" alt="Card ${card}" loading="lazy" />
|
||||||
</div>
|
</div>
|
||||||
${effectsHtml}
|
${effectsHtml}
|
||||||
${countBadge}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-detail">
|
<div class="card-detail">
|
||||||
<span class="card-cp">${maxCp}</span>
|
<span class="card-cp">${totalCp}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -238,9 +271,9 @@ export function setupMigrationButton(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const migrateCount = Math.min(oldApiCards.length, MAX_MIGRATE_CARDS)
|
// Count unique card types
|
||||||
const limitMsg = oldApiCards.length > MAX_MIGRATE_CARDS ? ` (limited from ${oldApiCards.length})` : ''
|
const uniqueCards = new Set(oldApiCards.map(c => c.card)).size
|
||||||
if (!confirm(`Migrate ${migrateCount} cards${limitMsg} to ATProto?`)) {
|
if (!confirm(`Migrate ${oldApiCards.length} cards (merged to ${uniqueCards} types) to ATProto?`)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user