Ctrl K
ComunidadGuías…

src/renderer/store/player-queue-math.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { PlayerRepeat } from '@samo/core/playback';

import { shuffleInPlace } from '/@/renderer/utils/shuffle';
import { QueueSong } from '/@/shared/types/domain-types';

export function calculateNextIndex(
    currentIndex: number,
    queueLength: number,
    repeat: PlayerRepeat,
): { nextIndex: number; shouldPause: boolean } {
    const isLastTrack = currentIndex === queueLength - 1;

    if (repeat === PlayerRepeat.ONE) {
        return { nextIndex: currentIndex, shouldPause: false };
    }

    if (repeat === PlayerRepeat.ALL) {
        if (isLastTrack) {
            return { nextIndex: 0, shouldPause: false };
        }
        return { nextIndex: currentIndex + 1, shouldPause: false };
    }

    if (isLastTrack) {
        return { nextIndex: 0, shouldPause: true };
    }
    return { nextIndex: currentIndex + 1, shouldPause: false };
}

/** Calculates the next song based on repeat mode and current position. */
export function calculateNextSong(
    currentIndex: number,
    queueItems: QueueSong[],
    repeat: PlayerRepeat,
): QueueSong | undefined {
    if (queueItems.length === 0) {
        return undefined;
    }

    if (repeat === PlayerRepeat.ONE) {
        return queueItems[currentIndex];
    }

    if (repeat === PlayerRepeat.ALL) {
        const isLastTrack = currentIndex === queueItems.length - 1;
        return isLastTrack ? queueItems[0] : queueItems[currentIndex + 1];
    }

    return queueItems[currentIndex + 1];
}

/**
 * Puts the queue back into the order it held before shuffle was switched on.
 *
 * The snapshot is taken once, when shuffle goes on, and never maintained — so it
 * can be stale in both directions. Tracks removed since are dropped, and tracks
 * queued since (which the snapshot has never heard of) are put back beside the
 * track they currently follow, so a "play next" done while shuffled does not get
 * flung to the end of the queue when shuffle goes off.
 */
export function restoreQueueOrder(current: string[], snapshot: null | string[]): string[] {
    if (!snapshot) {
        return [...current];
    }

    const inCurrent = new Set(current);
    const restored = snapshot.filter((id) => inCurrent.has(id));
    const placed = new Set(restored);

    current.forEach((id, index) => {
        if (placed.has(id)) {
            return;
        }

        let insertAt = 0;
        for (let before = index - 1; before >= 0; before--) {
            const anchor = restored.indexOf(current[before]);
            if (anchor !== -1) {
                insertAt = anchor + 1;
                break;
            }
        }

        restored.splice(insertAt, 0, id);
        placed.add(id);
    });

    return restored;
}

/**
 * Shuffles the queue itself rather than shuffling how it is read back.
 *
 * The playing track moves to the head so it keeps playing uninterrupted and
 * everything else lands behind it — the list the user is looking at is the order
 * that will actually play. Callers set `player.index` to 0 alongside this.
 */
export function shuffleQueueAroundIndex(queue: string[], currentIndex: number): string[] {
    if (queue.length <= 1) {
        return [...queue];
    }

    if (currentIndex < 0 || currentIndex >= queue.length) {
        return shuffleInPlace([...queue]);
    }

    const current = queue[currentIndex];
    const rest = queue.filter((_, index) => index !== currentIndex);

    return [current, ...shuffleInPlace(rest)];
}