Ozellikler: - Playlist toplu indirme (onizle-ve-sec): YouTube playlist URL'si yapistir -> tum parcalar arama sonucu gibi listelenir (SearchThread playlist modu, noplaylist=False + extract_flat), checkbox'la sec, toplu indir. Yeni bridge slotu importPlaylist(url). Indirme pill'i "X/Y" sayaci gosterir (download_total). - Geri/Ileri gezinme: ust bardaki oklar artik gercek gorunum-gecmisi yiginiyla calisir (recordHistory/navBack/navFwd, wireEvents'te baglandi). Duzeltmeler (alt-ajan taramasindan): - Komut paletinden karaoke menusu flash-kapaniyordu -> palet ogesi onclick'i stopPropagation (global tikla-kapat menuyu silmesin). - Arama/akilli-liste gorunumunde surukle-sirala gercek listeyi bozup kaydediyordu -> trackRow(reorderable): yalniz gercek tam-liste suruklenebilir. - dl-pill/sep-pill/mini-klip ayni sag-alt kosede biniyordu -> pill'ler sol-alta, sepPill dl'nin ustune; ayrica sepPill .show sinifi eksikti (gorunmuyordu) -> fix. - trackChanged JSON.parse guard'siz -> try/catch. - repeat_mode trackChanged payload'inda yoktu -> eklendi + okundu (3 durumlu tekrar dugmesi parca degisince dogru). - Eski YouTube sonuclari sorgu degisince temizleniyor. Altyapi: - Dependabot (.github/dependabot.yml): pip + github-actions haftalik. - docs/: ARCHITECTURE, BRIDGE-SIGNALS, KNOWN-ISSUES, DEV (+ TR->EN sozluk) — proje kendini belgeliyor. graphify grafigi guncellendi. - README + GitHub about + Pages: banner (OpenRouter/Nano Banana Pro ile uretildi), rozetler, v1.0.4 notlari.
6.1 KiB
Just Music Premium — Known Issues & Gotchas
A defect + gotcha log so future work doesn't re-discover the same traps. Line numbers are approximate — grep the symbol, don't trust the number after edits.
Files that matter most: justmusic/web/app.js, justmusic/web/app.css, justmusic/bridge.py, justmusic/config.py.
Part 1 — Fixed in v1.0.4
-
1. Top-bar Back/Forward arrows were dead (never wired). ✅ FIXED — real view-history stack:
recordHistory/navBack/navFwd(app.js ~223–246), wired inwireEvents($('#navBack').onclick=navBack; $('#navFwd').onclick=navFwd;, ~app.js:755).recordHistoryskips clip mode and de-dupes the current location;navLockguards replays. -
2. Karaoke menu from the Ctrl+K command palette flash-closed. Root cause: the global
document.addEventListener('click', … remove .ctx-menu)(app.js ~39) removes any left-click-opened menu on the same click's bubble. ✅ FIXED — the palette itemonclicknow callse.stopPropagation()before running the command (app.js ~1240). The direct#pKaraokebutton already had this guard (app.js ~780). -
3. Drag-to-reorder from Search / Smart-list views corrupted the real playlist (filtered index applied to the real array, then persisted). ✅ FIXED —
trackRow(s, i, pl, reorderable)(app.js ~340) makes rowsdraggableonly whenreorderableis true. Only the real full-listrenderPlaylistpassestrue(~app.js:336); Search (~410) and Smart (~1219) pass nothing → drag off. Drop also requiresplaylistSort==='default'(~app.js:367). -
4. Download pill, separation pill and mini-clip player all pinned bottom-right and overlapped. ✅ FIXED — pills moved to bottom-LEFT;
#sepPillstacks above#dlPill(.dl-pill{left:20px; bottom:calc(var(--player-h)+18px)},#sepPill{bottom:calc(var(--player-h)+78px)}, app.css ~396–398). Mini-clip stays bottom-right (.clip-mini{right:20px}, app.css ~480). Also the separation pill never appeared becauseupdateSepPilldidn't add.show— ✅ FIXED (app.js ~1058). -
5.
trackChangedhandler had no try/catch aroundJSON.parse(every other signal did). ✅ FIXED —bridge.trackChanged.connect(j=>{try{track=JSON.parse(j);}catch(e){return;}onTrackChanged();})(app.js ~712). -
6.
repeat_modewas missing from thetrackChangedpayload, so the 3-state repeat glyph could drift. ✅ FIXED — added to_track_json()(bridge.py ~369) and read inonTrackChanged(if(track.repeat_mode!=null)active.repeat_mode=track.repeat_mode;, app.js ~644). -
7. Stale YouTube results lingered when the search box was narrowed/cleared. ✅ FIXED —
searchRows=[]on every#topSearchinput change (app.js ~758).
Part 2 — Known / open (not yet fixed)
-
showView('playlist')with a nullviewPlaylistleavesviewlying.view=vis set at the top ofshowView(app.js ~208) before thev==='playlist' && viewPlaylistguard fails and falls through torenderHome()(~217). Result: globalviewsays'playlist'while Home is on screen. app.js ~207–217. -
Heart "burst" like-animation never triggers.
.icon-btn.fav.burst+@keyframes burstexist in CSS (app.css ~428–429) but no JS ever adds.burst—updatePlayeronly toggles.onon#pFav(app.js ~619). The animation is dead until something adds/removes the class on like. -
Visualizer hot path forces a style recalc every frame.
vizLoop(app.js ~657) runsdrawPlayerViz+drawWaveforms+updateAmbienton everyrequestAnimationFramewith no early-out when paused, and each ofvizLoop/drawPlayerViz/drawWaveformscallsgetComputedStyle(document.documentElement)per frame (app.js ~663, ~674, ~940, ~994) to read--accent-rgb. That's a forced synchronous style/layout read in the hot path. Suggested: cache the accent color, refresh only on accent/cover change; and bail early when!active.playing. -
Dead code.
confirmBox(app.js ~66) is an unused wrapper aroundmodalConfirm. The seek handler computes an unuseddurlocal (const dur=parseFloat($('#pDur')…), app.js ~793) and then useslastDurinstead — remove it. -
yt-dlp goes stale every few weeks (YouTube changes its player). Symptom: downloads start returning HTTP 403 while search still works. Fix: bump the pinned
yt-dlpand rebuild (see the v1.0.3 commit). Future idea: a runtime yt-dlp self-updater would avoid shipping a full ~490 MB app update each time.
Traps / invariants
Read these before touching menus, drag-reorder, the clip player, or playlist names.
-
(a) ctx-menu + global click-closer. Any
.ctx-menuopened by a left-click MUST calle.stopPropagation()in that click's handler, or the globaldocument-level click listener (app.js ~39) removes it on the same bubble. Right-click (contextmenu) opens are safe. See#pKaraoke(~780) and the palette item (~1240) for the pattern. -
(b)
trackRowdrag index is only valid in the default full-list view. Theidxstored on dragstart indexes the displayed array. It is only equal to the real playlist index inrenderPlaylistwithplaylistSort==='default'. Never enable reorder drag from filtered/sorted/smart/search views — passreorderable=false(the default) and the drop guard also checksplaylistSort==='default'. -
(c) The clip
<video>MUST be removed from the DOM on stop. Pausing alone keeps network traffic alive AND a live<video>left in the DOM crashes QtWebEngine on app close.stopClip(app.js ~1120) doesv.pause(); v.removeAttribute('src'); v.load();thenhost.remove(). Keep all three steps. The audio engine is separate — don't touch it here. -
(d) Protected playlist names are stored dict keys, not display labels.
"Kütüphanem","Beğenilen Şarkılar","İndirilenler"areconfig.PROTECTED_PLAYLISTS(config.py ~88–91) and used as literal keys in the library/state dicts and download routing (bridge.py ~1343). Do not rename, translate, or "prettify" them — renaming a key silently orphans its songs. The UI already hides rename/delete forS.protected(app.js ~198).