feat: Windows 11 Taskbar Widget Mini Player#4349
feat: Windows 11 Taskbar Widget Mini Player#4349digitalnomad91 wants to merge 35 commits intopear-devs:masterfrom
Conversation
…oader-plugins ci: add concurrency settings to prevent workflow cancellation
… prefix - Fix incorrect console output when file already exists: replace broken 'find newest mp3' fallback with pre-resolved expected filename from yt-dlp - Detect yt-dlp 'already downloaded' output and show accurate log messages - Namespace all ytdlp IPC channels (download-song-ytdlp, downloader-ytdlp-feedback, downloader-ytdlp-error-toast, download-playlist-request-ytdlp) to prevent conflicts when both downloader and downloader-ytdlp plugins are enabled - Change ytdlp button text to 'Download (ytdlp)' and use distinct element ID so both download buttons work independently - Fix 'NA - ' filename prefix by using yt-dlp conditional template syntax that only includes artist when metadata is available
fix(downloader-ytdlp): fix file-exists logging, IPC conflicts, and NA prefix
Creates a small frameless always-on-top window positioned above the Windows taskbar that displays album art, song title, artist name, and previous/play-pause/next media controls. The widget updates in real-time via IPC as songs change and communicates control commands back to the main player. Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…ove alt text Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Position widget directly ON the taskbar surface using display bounds vs workArea geometry detection - Auto-detect taskbar height (fallback to 48px for Windows 11) - Place widget to the left of the system tray / notification area - Compact UI scaled to fit within taskbar height (~48px): album art, title, artist, prev/play-pause/next controls - Transparent background so widget blends with taskbar - Non-draggable, non-movable, locked to taskbar position - Reposition on display configuration changes - Window is non-focusable to avoid stealing focus from taskbar Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Use setAlwaysOnTop(true, 'screen-saver') z-level so the widget renders above the taskbar instead of underneath it - Set window type to 'toolbar' to prevent third-party window managers like DisplayFusion from attaching overlays (move to next monitor, etc.) - Add monitorIndex config option with menu radio buttons so users can choose which monitor the widget appears on - Update getTaskbarGeometry to use the selected display instead of always the primary display Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Add periodic repositioning (every 2s) that reasserts setAlwaysOnTop to recover from z-index loss when other windows are focused/moved - Periodic recheck also handles auto-hide taskbar state changes by recalculating bounds from the current display workArea - Add offsetX/offsetY config with multiInput prompt dialog so users can fine-tune horizontal and vertical position of the widget - Add i18n strings for position offset menu Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
… blur - Add onConfigChange handler to live-apply offset/blur changes without restart - Export updateConfig() for live offset + blur updates from config changes - Reduce reposition interval from 2000ms to 500ms for faster z-index recovery - Increase SYSTEM_TRAY_ESTIMATED_WIDTH from 300 to 450 to avoid pinned icons - Make layout more compact: reduce gaps, padding, button/icon sizes - Add background blur option with backdrop-filter: blur(20px) - Add blur-bg CSS class toggled via IPC, with menu checkbox toggle - Add i18n string for background blur menu item Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…yout
- Replace fixed 300px width with content-driven dynamic sizing (150-350px)
via ResizeObserver + IPC resize channel from renderer to main
- CSS: inline-flex container, 3px gap, max-width:160px info section
- Add on('hide') handler for instant recovery from external hides
- Add recoverVisibility() helper used by both hide handler and timer
- Reduce reposition interval to 250ms, add moveTop() for z-order
- Add isShowing/intentionalClose flags for proper state management
- Debounce resize reports (50ms) to avoid IPC floods
- Clean up resize IPC handler in cleanup()
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Remove on('hide') handler that fought with OS/shell causing broken
rendering state where window was shown but not rendered
- Add setIgnoreMouseEvents(true, {forward: true}) to make window
click-through until a song is actually displaying
- Only call setBounds when bounds actually change to reduce flickering
- Move getConfig() inside position dialog click handler so it reads
fresh values each time the dialog is opened
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Add moveTop() to repositionWidget so the widget always reasserts z-order above any overlays (fixes Start menu hiding widget permanently) - Add 'hide' event handler with immediate + retry recovery (fixes brief disappearance on taskbar clicks being visible too long) - Add 'always-on-top-changed' event handler to immediately reassert z-order when stolen by external processes - Clean up recovery timers on plugin cleanup Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…, UI tweaks 1. Fix Start menu hiding widget permanently: replace fixed-retry recovery with a persistent 100ms interval that keeps retrying for 3 seconds after any hide event. Handle minimize events. Always reassert z-order in recoverVisibility() even when isVisible() returns true. 2. Reduce reposition polling from 250ms to 100ms for faster recovery from brief disappearances caused by taskbar interactions. 3. Click anywhere on widget (outside control buttons) to show/focus the main YouTube Music window via new taskbar-widget:show-window IPC channel. 4. Increase gap between album art and title/artist text from 3px to 8px. 5. Increase font sizes: title 12→13px, artist 10→11px (at standard taskbar height ≥48px). Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…overy The widget could get stuck behind the taskbar after Start menu interactions because calling setAlwaysOnTop(true) on an already-TOPMOST window is a no-op on Windows — the OS does not re-evaluate z-band position. Fix: toggle setAlwaysOnTop off then on (HWND_NOTOPMOST → HWND_TOPMOST) to force z-order re-evaluation. The toggle happens: - Immediately on hide/minimize events (existing handlers) - Every ~500ms via the periodic reposition timer (new tick counter) - On main window blur/focus events (new handlers for event-driven recovery) Also: always call showInactive() in recoverVisibility() even when isVisible() returns true, since the widget can appear "visible" while rendered behind the taskbar surface. Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…olor blur - Remove all periodic z-order manipulation from repositionWidget() to eliminate constant stutter; timer now only handles bounds checking - Use opacity trick (0 → toggle → 1) in recoverVisibility() to prevent visible flash during z-order recovery - Schedule staggered recovery attempts (300/800/1500/3000ms) after main window blur for reliable Start menu recovery - Increase container padding (top/bottom and left for blur-bg) - Increase blur background border-radius to 8px (semi-rounded corners) - Extract dominant colour from album art via nativeImage in main process and send to widget for dynamic gradient blur background Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…ur padding - Bring back FORCE_ZORDER_EVERY_N_TICKS periodic z-order toggle in repositionWidget() so the widget reliably recovers from being pushed behind the taskbar (Start menu, third-party taskbar tools, etc.) even when the main YTM window is not focused. - The toggle is wrapped in the opacity:0 guard (recoverVisibility()) to prevent the visible stutter that plagued the earlier implementation. - On intermediate ticks, lightweight setAlwaysOnTop + moveTop keeps the widget above without toggling. - Body CSS changed to flex with vertical centering; container no longer fills full taskbar height, giving the blur background a few pixels of outer padding so it doesn't butt up against the taskbar edges. Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
- Album art sized to widgetHeight-20 (was -12) to double the vertical gap between blur background and taskbar edges - Gradient alpha reduced from 0.45/0.55 to 0.25/0.35 - Default fallback alpha reduced from 0.3 to 0.15 Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…d values Album art sized to widgetHeight-16 (was -20, originally -12) to split the difference as requested — more padding than the original but less than the doubled version. Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
…e flicker - Border: 1px solid rgba(255,255,255,0.12) on blur background - Border-radius: 8px → 4px (slightly rounded, not square) - Album art already 4px, now matches blur background - Gradient opacity: 0.25/0.35 → 0.35/0.45; fallback: 0.15 → 0.25 - Flicker: increase z-order toggle interval 1.5s → 3s, skip redundant setAlwaysOnTop on intermediate ticks, guard moveTop behind isVisible() check Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
| { | ||
| label: t('plugins.downloader.menu.yt-dlp-location-nice'), | ||
| click: async () => { | ||
| const ytDlpPathValue = typeof config.advanced?.ytDlpPath === 'string' ? config.advanced.ytDlpPath : ''; |
There was a problem hiding this comment.
🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Replace ·typeof·config.advanced?.ytDlpPath·===·'string'·?·config.advanced.ytDlpPath with ⏎··········typeof·config.advanced?.ytDlpPath·===·'string'⏎············?·config.advanced.ytDlpPath⏎···········
| const ytDlpPathValue = typeof config.advanced?.ytDlpPath === 'string' ? config.advanced.ytDlpPath : ''; | |
| const ytDlpPathValue = | |
| typeof config.advanced?.ytDlpPath === 'string' | |
| ? config.advanced.ytDlpPath | |
| : ''; |
| }; | ||
|
|
||
| ipc.on('downloader-ytdlp-feedback', (feedback: string) => { | ||
| const targetHtml = feedback || t('plugins.downloader.templates.button') + ' (ytdlp)'; |
There was a problem hiding this comment.
🚫 [eslint] <prettier/prettier> reported by reviewdog 🐶
Insert ⏎·····
| const targetHtml = feedback || t('plugins.downloader.templates.button') + ' (ytdlp)'; | |
| const targetHtml = | |
| feedback || t('plugins.downloader.templates.button') + ' (ytdlp)'; |
| <a | ||
| class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer" | ||
| id="navigation-endpoint" | ||
| onClick={props.onClick} |
There was a problem hiding this comment.
The reactive variable 'props.onClick' should be wrapped in a function for reactivity. This includes event handler bindings on native elements, which are not reactive like other JSX props.
| Platform.shim.eval = async ( | ||
| data: Types.BuildScriptResult, | ||
| env: Record<string, Types.VMPrimative>, | ||
| ) => { |
There was a problem hiding this comment.
🚫 [eslint] <@typescript-eslint/require-await> reported by reviewdog 🐶
Async arrow function has no 'await' expression.
There was a problem hiding this comment.
Pull request overview
This PR adds a new Windows-only “taskbar widget” mini player plugin, but it also introduces substantial additional functionality (a new yt-dlp based downloader plugin, an adblocker plugin restoration, dependency/CI tweaks, README fork notes, and many i18n updates).
Changes:
- Add
taskbar-widgetplugin implementing a native Windows 11 taskbar-embedded mini player window (album art, blur background, playback controls, positioning/z-order recovery). - Add a new
downloader-ytdlpplugin (backend + renderer UI + menu + styles + types) and localize its name/description across many locales. - Reintroduce/extend an
adblockerplugin and update repo metadata (README, deps/lockfile, workflow concurrency, gitignore).
Reviewed changes
Copilot reviewed 64 out of 67 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/taskbar-widget/main.ts | Implements taskbar widget window creation, positioning, z-order recovery, IPC, and dynamic blur/color handling. |
| src/plugins/taskbar-widget/index.ts | Registers the Taskbar Widget plugin, config, and menu (monitor/offset/blur). |
| src/plugins/downloader/main/index.ts | Formatting-only adjustments in downloader backend. |
| src/plugins/downloader-ytdlp/index.ts | Registers the yt-dlp downloader plugin (backend/renderer/menu/styles). |
| src/plugins/downloader-ytdlp/main/index.ts | Implements yt-dlp backend download logic, IPC handlers, notifications, and error reporting. |
| src/plugins/downloader-ytdlp/main/utils.ts | Helper functions (download folder, feedback IPC, image crop, badge). |
| src/plugins/downloader-ytdlp/menu.ts | Adds plugin menu entries (download settings, folder selection, yt-dlp path prompt, presets). |
| src/plugins/downloader-ytdlp/renderer.tsx | Injects download menu entry and renders error toast UI in the renderer. |
| src/plugins/downloader-ytdlp/templates/download.tsx | Download menu item template (copied from existing downloader). |
| src/plugins/downloader-ytdlp/style.css | Styling for injected download menu item/icon. |
| src/plugins/downloader-ytdlp/types.ts | Preset definitions and a large YouTube itag/format table. |
| src/plugins/adblocker/index.ts | Adblocker plugin registration + backend engine control + preload injection hooks + AdSpeedup option. |
| src/plugins/adblocker/blocker.ts | Ghostery ElectronBlocker integration, list loading, caching, enable/disable session blocking. |
| src/plugins/adblocker/adSpeedup.ts | Renderer-side ad speedup/mute logic via MutationObserver. |
| src/plugins/adblocker/types/index.ts | Defines available blocker modes as string constants. |
| src/plugins/adblocker/injectors/inject.js | In-player injection logic (JSON pruning + property trapping) derived from external sources. |
| src/plugins/adblocker/injectors/inject.d.ts | Types for injector exports. |
| src/plugins/adblocker/injectors/inject-cliqz-preload.ts | Loads Ghostery preload helper. |
| src/plugins/adblocker/.gitignore | Ignores an adblocker engine artifact name. |
| src/i18n/resources/en.json | Adds strings for taskbar-widget and downloader-ytdlp. |
| src/i18n/resources/ar.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/bg.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/bn.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ca.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/cs.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/de.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/el.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/es.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/fa.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/fi.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/fil.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/fr.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/hi.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/hr.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/hu.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/id.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/is.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/it.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ja.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ko.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/lt.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/lv.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ms.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/nb.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ne.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/nl.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/pl.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/pt.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/pt-BR.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ro.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ru.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/sk.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/sl.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/sr.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/sv.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/ta.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/th.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/tr.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/uk.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/vi.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/zh-CN.json | Adds downloader-ytdlp name/description translation. |
| src/i18n/resources/zh-TW.json | Adds downloader-ytdlp name/description translation. |
| package.json | Adds chalk and @types/chalk dependencies. |
| pnpm-lock.yaml | Locks new chalk / @types/chalk packages and updates transitive chalk version. |
| README.md | Adds fork-specific documentation and workflow instructions at top of README. |
| .gitignore | Ignores package-lock.json. |
| .github/workflows/build.yml | Adds workflow concurrency settings. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ipc.handle('download-song-ytdlp', (url: string) => downloadSong(url)); | ||
| ipc.on('ytmd:video-src-changed', (data: GetPlayerResponse) => { | ||
| playingUrl = data.microformat.microformatDataRenderer.urlCanonical; | ||
| }); |
There was a problem hiding this comment.
The plugin subscribes to ytmd:video-src-changed, but the rest of the app (and the existing downloader plugin) emits peard:video-src-changed. As written, playingUrl will never be updated, which will break playlist downloads and any fallback that relies on the currently-playing URL. Update this listener to use the peard:* channel names used elsewhere in the codebase.
| // Extract dominant color from album art for the dynamic blur background. | ||
| // Only re-extract when the image URL changes. | ||
| if (songInfo.imageSrc && songInfo.imageSrc !== lastColorUrl) { | ||
| lastColorUrl = songInfo.imageSrc; | ||
| extractDominantColor(songInfo.imageSrc).then((color) => { | ||
| if (color && miniPlayerWin && !miniPlayerWin.isDestroyed()) { | ||
| miniPlayerWin.webContents.send( | ||
| 'taskbar-widget:set-background-color', | ||
| color, | ||
| ); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
extractDominantColor() re-fetches the album art over the network even though SongInfo already carries a decoded songInfo.image (Electron.NativeImage) from the song-info provider. This adds an extra HTTP request per track change and can slow down UI updates on poor connections. Consider computing the dominant color from songInfo.image (or reusing getImage() results) so the widget doesn’t duplicate the fetch.
| .ytmd-menu-item > .yt-simple-endpoint:hover { | ||
| background-color: var(--ytmusic-menu-item-hover-background-color); | ||
| } |
There was a problem hiding this comment.
The hover selector .ytmd-menu-item > .yt-simple-endpoint:hover will never match with the current DOM structure (the .yt-simple-endpoint anchor is the parent of the .ytmd-menu-item element in templates/download.tsx). This means the intended hover background style won’t apply. Adjust the selector to target the anchor’s hover state (or the icon inside it) based on the actual markup.
| // converted from https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2#file-youtube_format_code_itag_list-md | ||
| // and https://gist.github.com/MartinEesmaa/2f4b261cb90a47e9c41ba115a011a4aa | ||
| export const YoutubeFormatList: YouTubeFormat[] = [ | ||
| { | ||
| itag: 5, |
There was a problem hiding this comment.
YoutubeFormatList is a ~900-line constant that is not referenced anywhere else in the repository. Keeping this large unused table increases bundle size and makes the plugin harder to maintain. If it’s not needed, remove it; if it’s intended for future use, consider moving it behind a lazy import or generating it on demand to avoid shipping it to all users unnecessarily.
| "@playwright/test": "1.58.2", | ||
| "@stylistic/eslint-plugin": "5.7.1", | ||
| "@total-typescript/ts-reset": "0.6.1", | ||
| "@types/chalk": "^2.2.4", |
There was a problem hiding this comment.
@types/chalk is a deprecated stub package (chalk ships its own types, especially for v5+). Keeping it adds unnecessary dependencies and can cause type/version mismatches. Remove @types/chalk and rely on the types bundled with chalk instead.
| "@types/chalk": "^2.2.4", |
| // Periodically reposition and reassert z-order so the widget adapts to | ||
| // auto-hide taskbar state changes and recovers from z-index loss. | ||
| repositionTimer = setInterval( | ||
| () => repositionWidget(), | ||
| REPOSITION_INTERVAL_MS, | ||
| ); |
There was a problem hiding this comment.
repositionTimer runs every 100ms for the lifetime of the plugin, even before the widget is shown (isShowing === false). This creates a permanent wake-up/CPU cost and can impact battery life. Consider starting the interval only once the widget becomes visible, and/or increasing the interval / using event-driven updates when possible (e.g., display-metrics-changed + resize IPC) and pausing it when the widget is hidden.
| return { | ||
| x: | ||
| screenX + | ||
| screenWidth - | ||
| currentWidgetWidth - | ||
| SYSTEM_TRAY_ESTIMATED_WIDTH + | ||
| positionOffsetX, | ||
| y: taskbarY + positionOffsetY, | ||
| width: currentWidgetWidth, | ||
| height: taskbarHeight, | ||
| }; |
There was a problem hiding this comment.
getWidgetBounds() can compute an x coordinate outside the target display (e.g., small resolutions, large tray area, or default SYSTEM_TRAY_ESTIMATED_WIDTH being too high), which can place the widget partially/fully off-screen. Consider clamping x to [screenX, screenX + screenWidth - currentWidgetWidth] (and likewise ensuring width doesn’t exceed screen width) so the widget always remains reachable.
| // Standart YouTube artwork width with margins from both sides is 280 + 720 + 280 | ||
| if (imageSize.width === 1280 && imageSize.height === 720) { |
There was a problem hiding this comment.
Typo in comment: “Standart” → “Standard”.
| const writePreloadScript = (): string => { | ||
| const preloadPath = path.join(getWidgetDir(), 'preload.js'); | ||
| // Written at runtime because the plugin system doesn't support bundling | ||
| // separate preload scripts for secondary windows | ||
| fs.writeFileSync( | ||
| preloadPath, | ||
| `const { contextBridge, ipcRenderer } = require('electron'); | ||
| const ALLOWED_SEND = ['taskbar-widget:control', 'taskbar-widget:resize', 'taskbar-widget:show-window']; | ||
| const ALLOWED_RECEIVE = ['taskbar-widget:song-info', 'taskbar-widget:set-blur', 'taskbar-widget:set-background-color']; | ||
| contextBridge.exposeInMainWorld('widgetIpc', { | ||
| send: (channel, ...args) => { | ||
| if (ALLOWED_SEND.includes(channel)) { | ||
| ipcRenderer.send(channel, ...args); | ||
| } | ||
| }, | ||
| on: (channel, listener) => { | ||
| if (ALLOWED_RECEIVE.includes(channel)) { | ||
| ipcRenderer.on(channel, (_event, ...args) => listener(...args)); | ||
| } | ||
| }, | ||
| }); | ||
| `, | ||
| ); | ||
| return preloadPath; |
There was a problem hiding this comment.
The widget writes a preload script into app.getPath('userData') and then executes it via webPreferences.preload. Because userData is user-writable, this creates an easy local code-injection vector if that file is modified between runs (or by other processes). Prefer loading a preload script from the application bundle (e.g., a packaged file under __dirname/resources) rather than generating executable JS in a writable directory; if that’s not possible, consider hardening (unique temp filename + strict permissions + integrity check) to reduce risk.
| export const onConfigChange = (newConfig: DownloaderPluginConfig) => { | ||
| config = newConfig; | ||
| // Update cache when config changes | ||
| cachedConfig = newConfig; | ||
|
|
||
| // Reset yt-dlp path cache if custom path changed | ||
| if (cachedConfig?.advanced?.ytDlpPath !== newConfig.advanced?.ytDlpPath) { | ||
| cachedYtDlpPath = undefined; | ||
| } |
There was a problem hiding this comment.
In onConfigChange, cachedConfig is set to newConfig before comparing cachedConfig?.advanced?.ytDlpPath with newConfig.advanced?.ytDlpPath, so the comparison will always be false and cachedYtDlpPath will never be cleared when the custom path changes. Store the previous path before overwriting the cache (or compare against config before reassignment) so the yt-dlp path cache is invalidated correctly.
Windows 11 Taskbar Widget Mini Player
This PR introduces a native Windows 11 taskbar widget that embeds a mini player directly into the taskbar, providing quick access to playback controls and now-playing information without needing to open the main application window.
🎯 Overview
The taskbar widget displays the current track's album artwork with dynamic blur effects, playback controls (play/pause, previous, next), and seamlessly integrates with the Windows 11 taskbar interface.
✨ Key Features
Native Taskbar Integration
Dynamic Visual Design
Playback Controls
Advanced Window Management
Configuration Options
🔧 Technical Implementation
Architecture
taskbar-widget/)BrowserWindowwith appropriate window flagsFiles Added
src/plugins/taskbar-widget/index.ts(151 lines) - Plugin registration and configurationsrc/plugins/taskbar-widget/main.ts(891 lines) - Core widget logic, window management, positioningsrc/i18n/resources/en.json- Translation strings for settingsKey Technical Features
📊 Statistics
🧪 Testing Performed
Window Management
Start11 Compatibility (Stardock)
Visual & UX
Edge Cases
🎨 Design Decisions
Why Embed vs Float?
Initially considered a floating widget, but embedding into the taskbar provides:
Z-Order Strategy
Implemented aggressive z-order management with:
Start11 Optimization
Special attention was paid to Start11 compatibility through:
Performance Considerations
🚀 Usage
Note for Start11 users: The widget automatically detects and adapts to Start11's taskbar customizations. If using custom positioning with Start11, you may need to adjust the X/Y offsets in the plugin settings.
📝 Configuration
Available settings in plugin options:
🔮 Future Enhancements
Potential improvements for future iterations:
🙏 Acknowledgments
Thanks to extensive testing and iteration to achieve smooth Start menu interaction and reliable z-order management. Special testing conducted on systems running Stardock Start11 to ensure seamless compatibility with custom taskbar configurations.
Ready for review and testing on Windows 11 systems (including those running Start11)!