Ctrl K
ComunidadGuías…

src/renderer/store/player-derived.ts

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

Archivo original ↗Preguntar a KiBot
import { calculateNextSong } from '/@/renderer/store/player-queue-math';
import { PlayerData, QueueData, QueueSong } from '/@/shared/types/domain-types';
import { PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/shared/types/types';

export interface GroupedQueue {
    groups: { count: number; name: string }[];
    items: QueueSong[];
}

export interface PlayerSnapshotSlice {
    player: {
        index: number;
        playerNum: 1 | 2;
        repeat: PlayerRepeat;
        shuffle: PlayerShuffle;
        status: PlayerStatus;
    };
    queue: QueueData;
}

export type QueueGroupingProperty = keyof QueueSong;

export const EMPTY_PLAYER_DATA: PlayerData = {
    currentSong: undefined,
    index: -1,
    nextSong: undefined,
    num: 1,
    player1: undefined,
    player2: undefined,
    previousSong: undefined,
    queueLength: 0,
    status: PlayerStatus.PAUSED,
};

export type PlaybackInputs = {
    currentUniqueId: string;
    defaultLen: number;
    index: number;
    playerNum: 1 | 2;
    repeat: PlayerRepeat;
    revision: number;
    shuffle: PlayerShuffle;
    status: PlayerStatus;
};

const resolveCurrentQueueUniqueId = (state: PlayerSnapshotSlice): string => {
    const queueItems = getQueueItemsFromState(state);
    const index = state.player.index;

    if (index < 0 || queueItems.length === 0) {
        return '';
    }

    return queueItems[index]?._uniqueId ?? '';
};

export function computePlayerData(state: PlayerSnapshotSlice): PlayerData {
    const queueItems = getQueueItemsFromState(state);
    const queueIndex = state.player.index;

    const currentSong = queueItems[queueIndex];
    const repeat = state.player.repeat;

    const previousSong = queueIndex > 0 ? queueItems[queueIndex - 1] : undefined;
    const nextSong = calculateNextSong(queueIndex, queueItems, repeat);

    return {
        currentSong,
        index: queueIndex,
        nextSong,
        num: state.player.playerNum,
        player1: state.player.playerNum === 1 ? currentSong : nextSong,
        player2: state.player.playerNum === 2 ? currentSong : nextSong,
        previousSong,
        queueLength: state.queue.default.length,
        status: state.player.status,
    };
}

export function getCurrentSongFromState(state: {
    playbackSnapshot: PlayerData;
}): QueueSong | undefined {
    return state.playbackSnapshot.currentSong;
}

export function getPlaybackInputs(state: PlayerSnapshotSlice): PlaybackInputs {
    return {
        currentUniqueId: resolveCurrentQueueUniqueId(state),
        defaultLen: state.queue.default.length,
        index: state.player.index,
        playerNum: state.player.playerNum,
        repeat: state.player.repeat,
        revision: state.queue.revision ?? 0,
        shuffle: state.player.shuffle,
        status: state.player.status,
    };
}

export function getPlayerDataFromState(state: { playbackSnapshot: PlayerData }): PlayerData {
    return state.playbackSnapshot;
}

export function getQueueFromState(
    state: PlayerSnapshotSlice,
    groupBy?: QueueGroupingProperty,
): GroupedQueue {
    const queue = getQueueOrderFromState(state);

    if (!groupBy) {
        return queue;
    }

    return groupQueueItems(queue, groupBy);
}

export function getQueueItemsFromState(state: PlayerSnapshotSlice): QueueSong[] {
    const songs = state.queue.songs;
    const items: QueueSong[] = [];

    for (const id of state.queue.default) {
        const song = songs[id];
        if (song) {
            items.push(song);
        }
    }

    return items;
}

export function getQueueOrderFromState(state: PlayerSnapshotSlice): GroupedQueue {
    const items = getQueueItemsFromState(state);

    return {
        groups: [{ count: items.length, name: 'All' }],
        items,
    };
}

export function isFirstTrackInQueueFromState(state: PlayerSnapshotSlice): boolean {
    return state.player.index === 0;
}

export function isLastTrackInQueueFromState(state: PlayerSnapshotSlice): boolean {
    const queue = getQueueOrderFromState(state);
    return state.player.index === queue.items.length - 1;
}

export function playbackInputsEqual(a: PlaybackInputs, b: PlaybackInputs): boolean {
    return (
        a.currentUniqueId === b.currentUniqueId &&
        a.index === b.index &&
        a.playerNum === b.playerNum &&
        a.repeat === b.repeat &&
        a.shuffle === b.shuffle &&
        a.status === b.status &&
        a.defaultLen === b.defaultLen &&
        a.revision === b.revision
    );
}

/** Bump when queue song records mutate without changing order/shuffle inputs. */
export function touchQueueRevision(queue: QueueData): void {
    queue.revision = (queue.revision ?? 0) + 1;
}

function groupQueueItems(queue: GroupedQueue, groupBy: QueueGroupingProperty): GroupedQueue {
    const groups: { count: number; name: string }[] = [];
    const seenGroups = new Set<string>();

    queue.items.forEach((item) => {
        const groupValue = String(item[groupBy] || 'Unknown');

        if (!seenGroups.has(groupValue)) {
            seenGroups.add(groupValue);
            groups.push({ count: 1, name: groupValue });
            return;
        }

        const previousGroup = groups[groups.length - 1];
        if (previousGroup.name !== groupValue) {
            groups.push({ count: 1, name: groupValue });
            return;
        }

        groups[groups.length - 1].count++;
    });

    return { groups, items: queue.items };
}