feat(playlists): библиотека плейлистов приложения
CRUD в редакторе, read-only окно на пульте, отдельный аудиоканал, экспорт/импорт и маппинг из Foundry. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
import { filterPlaylistsByQuery } from '../../shared/types/appPlaylists';
|
||||
import { asPlaylistAudioId, asPlaylistId, asPlaylistTrackId } from '../../shared/types/ids';
|
||||
|
||||
import { PlaylistsStore } from './playlistsStore';
|
||||
|
||||
void test('filterPlaylistsByQuery: matches playlist name and track title', () => {
|
||||
const state = {
|
||||
playlists: [
|
||||
{
|
||||
id: asPlaylistId('p1'),
|
||||
name: 'Battle',
|
||||
tracks: [{ id: asPlaylistTrackId('t1'), audioId: asPlaylistAudioId('a1') }],
|
||||
},
|
||||
{
|
||||
id: asPlaylistId('p2'),
|
||||
name: 'Town',
|
||||
tracks: [{ id: asPlaylistTrackId('t2'), audioId: asPlaylistAudioId('a2') }],
|
||||
},
|
||||
],
|
||||
audios: [
|
||||
{
|
||||
id: asPlaylistAudioId('a1'),
|
||||
title: 'Drums',
|
||||
originalName: 'drums.mp3',
|
||||
relPath: 'files/a.mp3',
|
||||
sha256: '1',
|
||||
mime: 'audio/mpeg',
|
||||
sizeBytes: 1,
|
||||
},
|
||||
{
|
||||
id: asPlaylistAudioId('a2'),
|
||||
title: 'Market',
|
||||
originalName: 'market.mp3',
|
||||
relPath: 'files/b.mp3',
|
||||
sha256: '2',
|
||||
mime: 'audio/mpeg',
|
||||
sizeBytes: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
const byName = filterPlaylistsByQuery(state, 'bat');
|
||||
assert.equal(byName.playlists.length, 1);
|
||||
assert.equal(byName.playlists[0]?.id, asPlaylistId('p1'));
|
||||
|
||||
const byTrack = filterPlaylistsByQuery(state, 'market');
|
||||
assert.equal(byTrack.playlists.length, 1);
|
||||
assert.ok(byTrack.matchedAudioIds.has(asPlaylistAudioId('a2')));
|
||||
});
|
||||
|
||||
void test('PlaylistsStore: create playlist and add audio by hash reuse', async () => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'dnd-pl-'));
|
||||
const store = new PlaylistsStore(dir);
|
||||
await store.ensureLoaded();
|
||||
const pl = await store.createPlaylist('Test');
|
||||
const audioPath = path.join(dir, 'sample.mp3');
|
||||
fs.writeFileSync(audioPath, Buffer.from('ID3fake-audio-bytes'));
|
||||
|
||||
await store.addAudioFiles(pl.id, [audioPath]);
|
||||
await store.addAudioFiles(pl.id, [audioPath]);
|
||||
const state = store.getState();
|
||||
assert.equal(state.audios.length, 1);
|
||||
assert.equal(state.playlists[0]?.tracks.length, 2);
|
||||
assert.equal(state.playlists[0]?.tracks[0]?.audioId, state.playlists[0]?.tracks[1]?.audioId);
|
||||
});
|
||||
Reference in New Issue
Block a user