Array of AniList media entries to sync.
The user's authentication token.
Optional
onProgress: (progress: SyncProgress) => voidOptional callback for progress updates.
Optional
abortSignal: AbortSignalOptional abort signal to cancel the sync.
Optional
displayOrderMediaIds: number[]Optional array of media IDs to control sync order.
A promise resolving to a SyncReport object.
export async function syncMangaBatch(
entries: AniListMediaEntry[],
token: string,
onProgress?: (progress: SyncProgress) => void,
abortSignal?: AbortSignal,
displayOrderMediaIds?: number[],
): Promise<SyncReport> {
const errors: { mediaId: number; error: string }[] = [];
// Organize entries by media ID for handling incremental sync properly
const entriesByMediaId = organizeEntriesByMediaId(entries);
// Determine processing order
const userOrderMediaIds = determineProcessingOrder(
displayOrderMediaIds,
entriesByMediaId,
);
// Use the original entries length for progress calculation, not media IDs
const progress: SyncProgress = {
total: entries.length,
completed: 0,
successful: 0,
failed: 0,
skipped: 0,
currentEntry: null,
currentStep: null,
totalSteps: null,
rateLimited: false,
retryAfter: null,
};
if (onProgress) {
onProgress({ ...progress });
}
const apiCallsCompleted = { count: 0 };
// Process each media ID in order
for (const mediaIdNum of userOrderMediaIds) {
if (abortSignal?.aborted) {
console.log("Sync operation aborted by user");
break;
}
const result = await processMediaEntries(
mediaIdNum,
entriesByMediaId,
token,
apiCallsCompleted,
progress,
onProgress,
abortSignal,
);
// Update progress counters
progress.completed++;
if (result.success) {
progress.successful++;
} else {
progress.failed++;
if (result.error) {
errors.push({
mediaId: mediaIdNum,
error: result.error,
});
}
}
// Clear current entry info
progress.currentEntry = null;
progress.currentStep = null;
if (onProgress) {
onProgress({ ...progress });
}
}
return generateSyncReport(entries, progress, errors);
}
Process a batch of manga updates with rate limiting and progress tracking.