Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#build--distribution)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)
[![Downloads](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=downloads)](https://github.com/CaYatur/SoundVisualizer/releases)
[![Tests](https://img.shields.io/badge/tests-2032%20passing-2ea043.svg)](#tests)
[![Tests](https://img.shields.io/badge/tests-2052%20passing-2ea043.svg)](#tests)
[![cayadev.com](https://img.shields.io/badge/cayadev.com-e11d2a.svg)](https://cayadev.com)

</div>
Expand Down Expand Up @@ -339,6 +339,14 @@ that asserts the bar profile has no step in it.
the presets in view with them, and importing the pack attaches them to the new copies. Checked in
an isolated copy: with the pool set to three favourites, the visualizer window went round those
three and nothing else.
- **Large preset libraries stay light.** Every save or delete used to re-read every preset file
and send the whole list, sources included, to the panel, each window and every web client. With
the 10,347 presets of a full MilkDrop library (116 MB) one delete held the app for about 2.4
seconds and the panel used 631 MB. Presets are now read once and kept; a change sends only what
changed. At the same size a save now takes 91 ms and the panel uses 273 MB. Deleting or adding
MilkDrop presets no longer restarts the MilkDrop picture on screen. Web clients get MilkDrop
presets without their sources (271 KB instead of about 30 MB for 2,000 presets), and the web
overlay fetches the source of a preset only when it is about to draw it.
- **Sprites from `milk_img.ini`.** MilkDrop 2 draws images of your own over the picture during a
show: each one is defined in `milk_img.ini` with an image, code that runs once and code that
runs every frame, and launched by number. Choose the file in the MilkDrop panel and launch from
Expand Down Expand Up @@ -1238,7 +1246,7 @@ npm test
npm start -- --smoke
```

**2032 unit tests, all passing.** They are written to check answers, not to exercise lines:
**2052 unit tests, all passing.** They are written to check answers, not to exercise lines:

- **Formulas** are checked against values derived by hand from their definitions — Viviani's curve
staying on its sphere, the torus tube radius, Chladni's m↔n antisymmetry, every attractor
Expand Down
12 changes: 10 additions & 2 deletions README.tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#paketleme--dağıtım)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)
[![İndirme](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=indirme)](https://github.com/CaYatur/SoundVisualizer/releases)
[![Test](https://img.shields.io/badge/test-2032%20geçiyor-2ea043.svg)](#testler)
[![Test](https://img.shields.io/badge/test-2052%20geçiyor-2ea043.svg)](#testler)
[![cayadev.com](https://img.shields.io/badge/cayadev.com-e11d2a.svg)](https://cayadev.com)

</div>
Expand Down Expand Up @@ -332,6 +332,14 @@ profilinde basamak olmadığını doğruluyor.
üçünü de taşıyor: *Görünenleri Paketle* listede görünen presetleri onlarla birlikte yazıyor, paketi
içe aktarmak onları yeni kopyalara bağlıyor. Yalıtılmış bir kopyada denetlendi: havuz üç favoriye
ayarlıyken görselleştirici penceresi o üçünde döndü, başka hiçbir presete geçmedi.
- **Büyük preset kütüphaneleri hafif kalıyor.** Her kayıt ya da silme bütün preset dosyalarını
yeniden okuyor ve bütün listeyi kaynaklarıyla panele, her pencereye ve her web istemcisine
gönderiyordu. Tam bir MilkDrop kütüphanesinin 10.347 presetiyle (116 MB) tek bir silme uygulamayı
~2,4 saniye tutuyordu ve panel 631 MB kullanıyordu. Presetler artık bir kez okunup tutuluyor; bir
değişiklik yalnız değişeni gönderiyor. Aynı büyüklükte bir kayıt artık 91 ms sürüyor, panel 273 MB
kullanıyor. MilkDrop presetleri eklenip silindiğinde ekrandaki MilkDrop görüntüsü artık baştan
başlamıyor. Web istemcileri MilkDrop presetlerini kaynaksız alıyor (2.000 presette ~30 MB yerine
271 KB) ve web çıkışı bir presetin kaynağını ancak onu çizecekken istiyor.
- **`milk_img.ini`'den sprite'lar.** MilkDrop 2 gösteri sırasında kendi resimlerinizi görüntünün
üstüne çiziyor: her biri `milk_img.ini`de bir resim, bir kez çalışan ve her kare çalışan koduyla
tanımlı ve numarasıyla başlatılıyor. Dosyayı MilkDrop panelinde seçin; panelin listesinden, bir
Expand Down Expand Up @@ -1235,7 +1243,7 @@ npm test
npm start -- --smoke
```

**2032 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:
**2052 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:

- **Formüller**, tanımlarından elle türetilmiş değerlerle sınanıyor — Viviani eğrisinin küre
üzerinde kalması, simidin boru yarıçapı, Chladni'nin m↔n antisimetrisi, her çekicinin sınırlı
Expand Down
52 changes: 50 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ npm test
npm start -- --smoke
```

- **2032 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
- **2052 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
105 came with v3.1.1; 163 came with v3.1.2; 157 came with v3.1.3 — 1128 at
that tag — 469 more with v3.1.4, most of them from the MilkDrop work, and 435
that tag — 469 more with v3.1.4, most of them from the MilkDrop work, and 455
on `main` since.
Formulas are checked against values derived
by hand from their definitions — Viviani's curve staying on its sphere, the
Expand Down Expand Up @@ -1615,6 +1615,54 @@ rest after. No version number yet.
longer holds, and the panel drawn with a fake DOM — its own pack buttons
included, with only the file dialogs stubbed, and ◀/▶/🎲 still reaching
presets outside the pool. 49 of 49 mutations are caught.
- **Large preset libraries (#574, part 1 of 2: scale)** · done. Importing a
ZIP or a library found on the machine means thousands of presets; the
store could not carry them. Measured in an isolated copy with the corpus
(10,347 presets, 116 MB): `presets:list` took 3.8 s, one save held the main
process for about 2.4 s, the panel used 631 MB, and every web client got
116 MB on every change. The user chose to scale the store before adding
the importer.
- **Store.** Files are read once — in the background at start-up — and
kept; saves and deletes update the cache. `list()` still looks at the
folder's file names on every call, so a file added or removed by hand
shows up; a file edited by hand shows up after a restart. Bulk saves are
written in batches with pauses so the main process keeps serving audio,
lights and IPC, report progress, and keep the pack's own order.
- **Change broadcast.** A save or delete sends only what changed
(`presets-delta`); the whole list is sent only when a page opens. Pages
apply it in the store's order — newest first, ties broken by id, so
presets saved in the same millisecond no longer land in a different
order on each machine.
- **Web clients** get MilkDrop presets without their sources. The overlay
engine asks for a source by id (`/milkdrop/preset`, behind the token)
only when it is about to draw that preset, keeps the current one on
screen until it arrives, and drops the pick if it cannot be fetched
rather than falling back to the default preset.
- **Found on the way:** every preset change rebuilt the visualizer
window's whole layer stack, so importing or deleting a MilkDrop preset
restarted the MilkDrop picture on screen. The stack is now rebuilt only
when a Studio preset changes. The MilkDrop panel no longer keeps a
second copy of the list.
- **Measured** after the change, same corpus: `presets:list` 0.3 s, a
save 29 ms (91 ms with a window open), the panel 273 MB. With 2,000
presets and a web overlay open in a real browser: the connect message
was 271 KB instead of about 30 MB; the overlay followed the window's
auto advance preset for preset and fetched the sources of the seven it
showed; a delete took 68 ms while the window's MilkDrop kept drawing
(same preset, 97 frames in 1.2 s), and the window, overlay and panel
lists all dropped to 1,999.
- **Not done here:** visualizer windows still hold every source (141 MB
with 10,347 presets), since they draw from them directly; the importer
itself is part 2.
- **Tests.** 20 tests: the store against a temporary folder (one read,
cache updates, hand-made files, background load with a save and a
delete in between — the delete made deterministic, since a load that
had already read the file brought it back — and batched saves in the
pack's order), the change broadcast on the page, the stream server
stripping sources and serving them behind the token, the web bridge,
the visualizer's rebuild rule and the engine waiting for a source (and
saying so once if a page ever gets a sourceless preset with no way to
fetch it). 26 of 26 mutations are caught.

## v3.1.6 — Comprehensive video export

Expand Down
8 changes: 8 additions & 0 deletions src/admin/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4496,6 +4496,14 @@
render();
if (window.SVPreview) window.SVPreview.setConfig(cfg);
});
// Değişiklik yayını (#574): bütün liste yalnız açılışta geliyor
if (window.api.onPresetsDelta) {
window.api.onPresetsDelta((d) => {
window.SVPresets.applyDelta(d);
render();
if (window.SVPreview) window.SVPreview.setConfig(cfg);
});
}

// Uzaktan kumandadan (telefon / OBS sayfası) gelen değişiklik: panelin
// kendi kopyası tazelenir ve geri gönderilmez — yoksa sonsuz döngü olur.
Expand Down
40 changes: 35 additions & 5 deletions src/admin/milkdrop-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,31 @@
çizildi. */
let staleRender = false;

/* TEK LİSTE (#574). Panel eskiden kendi kopyasını istiyordu
(`listPresets`); admin.js'in tuttuğu `SVPresets` listesi değişiklik
yayınıyla zaten güncel. İkinci kopya 10.347 presette yüzlerce MB
demekti (ölçülen: panel 631 MB). Ortak liste hazır değilse (açılışın
ilk anı, testler) eski yol. */
function fromStore() {
const S = window.SVPresets;
if (!S || typeof S.ready !== 'function' || !S.ready() || typeof S.user !== 'function') return false;
presets = builtins().concat(S.user().filter((p) => p && p.kind === 'milkdrop'));
loaded = true;
return true;
}

// Kaydedilen/silinen hemen ortak listeye: yayın zaten geliyor, ikisi aynı sonucu veriyor
function adoptDelta(delta) {
const S = window.SVPresets;
if (S && typeof S.applyDelta === 'function' && typeof S.ready === 'function' && S.ready()) S.applyDelta(delta);
}

function refresh(cb) {
if (fromStore()) {
if (cb) cb();
else if (staleRender) { staleRender = false; P().rerender(); }
return;
}
if (!window.api || !window.api.listPresets || loading) return;
loading = true;
const done = () => {
Expand Down Expand Up @@ -148,6 +172,7 @@
}
const res = await window.api.savePresets(read.presets);
const saved = (res && res.saved) || [];
adoptDelta({ upsert: saved });
if (L) L.adopt(library(P().cfg()), read.library, saved);
refresh(() => {
P().apply();
Expand Down Expand Up @@ -601,10 +626,13 @@
const rerender = () => P().apply();
const nodes = [];

if (!loaded && !loading) {
refresh(() => P().rerender());
} else if (!loaded) {
staleRender = true;
// Ortak liste değişiklik yayınıyla güncel (#574): her çizimde ondan
if (!fromStore()) {
if (!loaded && !loading) {
refresh(() => P().rerender());
} else if (!loaded) {
staleRender = true;
}
}

// Durum
Expand Down Expand Up @@ -1004,7 +1032,8 @@
});
}
if (items.length && window.api.savePresets) {
await window.api.savePresets(items);
const res = await window.api.savePresets(items);
adoptDelta({ upsert: (res && res.saved) || [] });
}
busy = '';
refresh(() => {
Expand Down Expand Up @@ -1152,6 +1181,7 @@
onclick: async () => {
if (!(await P().confirm('"' + (p.name || p.id) + '" silinsin mi?'))) return;
if (window.api.deletePreset) await window.api.deletePreset(p.id);
adoptDelta({ remove: [p.id] });
if (md.presetId === p.id) load(cfg, null);
// Puanı, favorisi ve etiketleri de gidiyor (#576): kimlik bir daha gelmiyor
if (LBn) Object.assign(library(cfg), LBn.forget(library(cfg), p.id));
Expand Down
Binary file modified src/admin/studio.js
Binary file not shown.
47 changes: 36 additions & 11 deletions src/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1632,27 +1632,42 @@ function notifyAll(channel, payload) {
sendToVisualizers(channel, payload);
}

function broadcastPresets() {
const list = presetsStore.list();
notifyAll('presets', list);
streamServer.broadcast({ type: 'presets', presets: list });
return list;
/* PRESET YAYINI (#574). Önceden her kayıt bütün listeyi — kaynaklarıyla —
panele, her pencereye, Spout/Syphon'a ve web istemcilerine yeniden
gönderiyordu; 10.347 presette her değişim 116 MB ve ~2,4 sn ana süreç
kilidi. Şimdi yalnız değişenler gidiyor (`presets-delta`); bütün liste
yalnız sayfa açılırken isteniyor (`presets:list`). Web istemcilerine
MilkDrop kaynakları hiç gitmiyor (stream-server.js `publicPresets`). */
function broadcastPresetDelta(upsert, remove) {
const delta = { upsert: upsert || [], remove: remove || [] };
if (!delta.upsert.length && !delta.remove.length) return;
notifyAll('presets-delta', delta);
streamServer.broadcast({ type: 'presets-delta', delta });
}

ipcMain.handle('presets:list', () => presetsStore.list());
// Açılışta arka planda okunmuş olabilir; değilse okuma burada bitiyor
ipcMain.handle('presets:list', async () => {
await presetsStore.warm();
return presetsStore.list();
});
ipcMain.handle('presets:save', (e, preset) => {
const r = presetsStore.save(preset);
if (r.ok) broadcastPresets();
if (r.ok) broadcastPresetDelta([r.preset], []);
return r;
});
ipcMain.handle('presets:delete', (e, id) => {
const r = presetsStore.remove(id);
if (r.ok) broadcastPresets();
if (r.ok) broadcastPresetDelta([], [String(id)]);
return r;
});
ipcMain.handle('presets:save-many', (e, list) => {
const saved = presetsStore.saveMany(list);
if (saved.length) broadcastPresets();
/* Toplu kayıt parça parça (presets-store.js `saveManyAsync`); kaydeden
sayfaya ilerleme gidiyor, yayın bir kez ve sonunda. */
ipcMain.handle('presets:save-many', async (e, list) => {
const sender = e.sender;
const saved = await presetsStore.saveManyAsync(list, (done, total) => {
if (sender && !sender.isDestroyed()) sender.send('presets-progress', { done, total });
});
if (saved.length) broadcastPresetDelta(saved, []);
return { ok: true, saved };
});
/* MilkDrop preset paketleri yüzlerce .milk dosyasından oluşur; tek tek
Expand Down Expand Up @@ -1936,6 +1951,12 @@ function syncStreamServer() {
mdTextureFile: (name) => textureFile(name),
/* MilkDrop sprite resmi (#577): kimlikle; yol ana süreçte çözülüyor. */
mdSpriteFile: (key) => spriteImageFile(key),
/* MilkDrop preset kaynağı (#574): listede kaynaksız gidiyor, sayfa
çizeceği presetin kaynağını kimliğiyle istiyor. */
mdPresetSource: (id) => {
const p = presetsStore.get(id);
return p && p.kind === 'milkdrop' && typeof p.source === 'string' ? p.source : null;
},
logoFile: (id) => logoLibrary.fileInfo(logoLibDir(), id),
onCommand: (msg, client) => applyRemoteCommand(msg, client),
onClientsChanged: (list) => {
Expand Down Expand Up @@ -2712,6 +2733,10 @@ app.whenReady().then(async () => {
dynamicLighting.setConfig(currentConfig.lighting).catch(() => {});
}
syncNowPlaying();
/* Preset deposu arka planda okunmaya başlıyor (#574): pencereler açılıp
listeyi isteyene kadar binlerce dosyanın okuması büyük ölçüde bitmiş
oluyor ve ana süreç o arada bekletilmiyor. */
presetsStore.warm().catch(() => {});

// Medya katmanının video dosyalarını okuduğu protokol. Yalnızca
// yapılandırmada SEÇİLİ olan dosyayı açar; sayfaya genel dosya sistemi
Expand Down
3 changes: 3 additions & 0 deletions src/main/preload-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ contextBridge.exposeInMainWorld('api', {
openPresetsFolder: () => ipcRenderer.invoke('presets:open-folder'),
importShaderText: () => ipcRenderer.invoke('presets:import-text'),
onPresets: (cb) => ipcRenderer.on('presets', (e, list) => cb(list)),
// Değişiklik yayını ve toplu kaydın ilerlemesi (#574)
onPresetsDelta: (cb) => ipcRenderer.on('presets-delta', (e, d) => cb(d)),
onPresetsProgress: (cb) => ipcRenderer.on('presets-progress', (e, p) => cb(p)),

// Yayın çıkışı (OBS tarayıcı kaynağı + mobil kumanda)
streamStatus: () => ipcRenderer.invoke('stream:status'),
Expand Down
2 changes: 2 additions & 0 deletions src/main/preload-visualizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ contextBridge.exposeInMainWorld('api', {
// Studio presetleri ana süreçte tutulur (settings.json şişmesin diye)
getPresets: () => ipcRenderer.invoke('presets:list'),
onPresets: (cb) => ipcRenderer.on('presets', (e, list) => cb(list)),
// Değişiklik yayını (#574): bütün liste yerine yalnız değişenler
onPresetsDelta: (cb) => ipcRenderer.on('presets-delta', (e, d) => cb(d)),
/* MilkDrop doku paketi: preset kendi görselini ada göre istiyor
(`sampler_worms` -> `worms.jpg`). Yalnızca yapılandırmada seçili
klasörün içi okunuyor; kapsam denetimi ana süreçte. */
Expand Down
Loading
Loading