Skip to content

Update dependencies and refactor validation logic#426

Open
Sandakan wants to merge 44 commits intomasterfrom
release/4.0.0-alpha.3
Open

Update dependencies and refactor validation logic#426
Sandakan wants to merge 44 commits intomasterfrom
release/4.0.0-alpha.3

Conversation

@Sandakan
Copy link
Copy Markdown
Owner

@Sandakan Sandakan commented Nov 24, 2025

This pull request introduces two new migration guides for modern JavaScript/TypeScript projects and adds an example environment variable file. The guides provide step-by-step instructions for migrating from ESLint to Oxlint and from Prettier/Biome to Oxfmt, including manual steps, option mappings, and troubleshooting tips. Additionally, a template .env.example file is included to help developers configure environment variables for local development. Minor formatting improvements are also made to the main process documentation.

New Migration Documentation:

  • Added .agents/skills/migrate-oxlint/SKILL.md, a comprehensive guide for migrating a project from ESLint to Oxlint, covering automated migration, plugin and rule mapping, handling unsupported features, CI/script updates, and best practices.
  • Added .agents/skills/migrate-oxfmt/SKILL.md, a detailed guide for migrating from Prettier or Biome to Oxfmt, including option mapping, config review, handling unsupported features, and updating CI/scripts.

Development Environment Setup:

  • Added .env.example file providing a template for required environment variables, including Musixmatch, Last.fm, Genius, Sentry, Discord, database, and log path configuration.

Documentation Improvements:

  • Improved formatting and clarity in .github/copilot-instructions.md for the main process description, window management, system integration, database structure, and code patterns. [1] [2] [3] [4] [5] [6] [7] [8] [9]This pull request introduces a variety of improvements and updates across the codebase, focusing on dependency upgrades, environment configuration, playlist management, and documentation. The most significant changes are grouped below by theme.

Dependency and Build System Updates:

  • Upgraded several dependencies in package.json, including drizzle-orm, electron-vite, material-symbols, and zod, and added new dependencies such as node-taglib-sharp and yoctocolors. [1] [2] [3] [4] [5]
  • Updated electron.vite.config.ts to remove the use of externalizeDepsPlugin and ensure compatibility with the new electron-vite version. [1] [2]

Environment and Configuration:

  • Added a comprehensive .env.example file with placeholders for all required environment variables, improving developer onboarding and configuration clarity.

Playlist Management Improvements:

  • Refactored playlist-related functions to consistently use number types for playlistId and songIds instead of string, enhancing type safety and reliability in functions like addSongsToPlaylist, addArtworkToAPlaylist, and blacklistSongs. [1] [2] [3] [4]
  • Introduced a new SpecialPlaylists enum in src/common/playlists.enum.ts to better handle special playlist IDs such as History and Favorites.

Documentation and Developer Experience:

  • Completely overhauled the README.md for improved clarity, structure, and user engagement, including new feature lists, gallery, feedback/contribution sections, and clearer build instructions. [1] [2]
  • Added a new logs script in package.json for easier log colorization and access.

Path and Import Fixes:

  • Fixed and standardized import paths for utility and update functions in playlist-related modules, ensuring correct module resolution and maintainability. [1] [2] [3]

These changes collectively improve the robustness, maintainability, and usability of the project.Upgrade zod and material-symbols dependencies. Refactor validation logic to directly utilize zod schemas across various routes, removing reliance on zod-adapter. This change streamlines validation processes and enhances code maintainability.

- Updated `zod` from version 3.25.76 to 4.1.13 in `package.json`.
- Updated `material-symbols` from version 0.39.1 to 0.40.0 in `package.json`.
- Refactored validation logic in various routes to directly use `zod` schemas instead of `zodValidator` from `@tanstack/zod-adapter`.
- Updated routes in `albums`, `artists`, `folders`, `genres`, `lyrics`, `playlists`, `queue`, and `search` to reflect the new validation approach.
@Sandakan Sandakan added this to the Nora v4.0.0 milestone Nov 24, 2025
Sandakan and others added 26 commits November 24, 2025 23:27
…tadata and update related imports

- Renamed `sendSongId3Tags` to `sendSongMetadata` across multiple files for clarity.
- Updated the function signature in `songs.ts` to reflect the new naming convention.
- Removed the old `sendSongId3Tags` implementation and replaced it with the new `sendSongMetadata` logic.
- Adjusted all relevant imports and usages to ensure consistency throughout the codebase.
- Introduced a new script `colorize-logs.ts` for colorizing and tailing NDJSON log files.
- The script supports various features including log level filtering, file selection, and pretty-printing of log data.
- Added a new npm command `logs` to execute the log viewer script with an optional environment log path.
- Implemented `testUtils.ts` to provide mock data and utility functions for testing song metadata, file stats, and database transactions.
- Created comprehensive tests in `tryToParseSong.test.ts` to cover various scenarios including duplicate prevention, success cases, retry logic, renderer messages, and edge cases.
- Mocked dependencies such as file system operations, database queries, and external libraries to isolate tests and ensure reliability.
- Enhanced test coverage for song parsing logic, ensuring robust handling of different paths and error scenarios.
…nres, and artists; enhance song metadata update process
- Updated function signatures and variable types in various modules to use number for songId instead of string.
- Adjusted related database queries and IPC handlers to accommodate the new type.
- Modified local storage migration to convert songId from string to number.
- Updated type definitions in app.d.ts to reflect changes in songId type.
- Ensured consistency in handling songId throughout the application, including in event data and song-related operations.
Updated the README to enhance clarity and structure, including a new introduction and improved feature descriptions.
…and queries

- Updated toggleSongIsFavorite to accept songId as a number.
- Modified updateQueueOnSongPlay to handle songId as a number and adjusted queue structure accordingly.
- Changed album, artist, genre, listen, playlist, and song queries to use number for songId and related identifiers.
- Adjusted route parameters in main-player routes to convert string params to numbers for songId, albumId, artistId, genreId, and playlistId.
- Updated local storage utility functions to handle number arrays instead of string arrays for ignored artists and songs.
- Refined metadata management functions to ensure consistent handling of artist and genre data.
- Adjusted types in app.d.ts to reflect changes in songId and related identifiers.
- Fixed various instances in the UI where songId was treated as a string instead of a number.
…s to use enums

- Changed import paths for conversion functions in multiple files to use '../utils/convert' instead of '../../common/convert'.
- Updated playlist IDs in the filesystem and related components to use the SpecialPlaylists enum for better maintainability.
- Adjusted types for song and album data structures to use numbers instead of strings where applicable.
- Modified API calls to handle data responses correctly in various components.
- Cleaned up unused parameters and improved code readability across several files.
- Implement tests for hasDataChanged to verify data comparison logic across various object structures, including basic and complex cases.
- Introduce tests for isLatestVersion to validate version comparison, covering scenarios with different release phases and build metadata.
…type safety and state handling

- Introduced type definitions for queue and store subscription states to improve type safety.
- Refactored queue singleton initialization and synchronization logic for clarity and maintainability.
- Updated store subscription logic to ensure proper state retrieval and local storage synchronization.
- Improved logging for state changes during development.
@Sandakan Sandakan marked this pull request as ready for review April 4, 2026 06:54
Copilot AI review requested due to automatic review settings April 4, 2026 06:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the codebase by updating tooling/configuration, shifting many IDs from string to number across renderer + main, introducing DB-backed user-preferences storage (with migration + export), and refactoring some metadata/audio handling (including adoption of node-taglib-sharp and new file-handle utilities).

Changes:

  • Refactored many song/artist/album/playlist/genre IDs from stringnumber and updated route param handling (stringifying where needed).
  • Added new user-preferences persistence (Drizzle migration + seed + queries) and included export/import support.
  • Tooling/config updates: Oxfmt config, removal of Prettier/ESLint configs, and electron-vite config updates.

Reviewed changes

Copilot reviewed 294 out of 419 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/renderer/src/components/SongsPage/DeleteSongsFromSystemConfrimPrompt.tsx Switch songIds prop type to number[]; import ordering
src/renderer/src/components/SongsPage/BlacklistSongConfirmPrompt.tsx Switch songIds prop type to number[]; import ordering
src/renderer/src/components/SongsControlsContainer/UpNextSongPopup.tsx Route param stringification; songId type number
src/renderer/src/components/SongsControlsContainer/SongControlsContainer.tsx Import ordering
src/renderer/src/components/SongsControlsContainer/SongControlsAndSeekbarContainer.tsx Formatting only
src/renderer/src/components/SongsControlsContainer/SeekBarContainer.tsx Import ordering
src/renderer/src/components/SongsControlsContainer/OtherSongControlsContainer.tsx Import ordering
src/renderer/src/components/SongsControlsContainer/CurrentlyPlayingSongInfoContainer.tsx Route param stringification; album/songId types
src/renderer/src/components/SongUnplayableErrorPrompt.tsx Import ordering
src/renderer/src/components/SongTagsEditingPage/input_containers/SongLyricsEditorInput.tsx songId/artistId types; TODO stubbed navigation
src/renderer/src/components/SongTagsEditingPage/input_containers/SongGenresInput.tsx genreId types; Tailwind class tweaks
src/renderer/src/components/SongTagsEditingPage/input_containers/SongArtistsInput.tsx artistId types; Tailwind class tweaks
src/renderer/src/components/SongTagsEditingPage/input_containers/SongArtistInputResult.tsx artistId type; import ordering
src/renderer/src/components/SongTagsEditingPage/input_containers/SongAlbumInputResult.tsx Typed album data; Tailwind class tweak
src/renderer/src/components/SongTagsEditingPage/input_containers/SongAlbumInput.tsx Typed album data arrays; Tailwind class tweak
src/renderer/src/components/SongTagsEditingPage/input_containers/SongAlbumArtistInput.tsx albumId/artistId types
src/renderer/src/components/SongTagsEditingPage/SongMetadataResult.tsx API response .data handling; migrate album→albums
src/renderer/src/components/SongTagsEditingPage/SongArtwork.tsx Migrate album→albums (first item) when artwork changes
src/renderer/src/components/SongTagsEditingPage/ResetTagsToDefaultPrompt.tsx Formatting only
src/renderer/src/components/SongTagsEditingPage/CustomizeSelectedMetadataPrompt.tsx API response .data; migrate album→albums
src/renderer/src/components/SongInfoPage/UnAvailableTrack.tsx Import ordering
src/renderer/src/components/SongInfoPage/SongsWithFeaturingArtistSuggestion.tsx Move ignore handling to user preferences hook; songId type
src/renderer/src/components/SongInfoPage/SongAdditionalInfoContainer.tsx Import ordering
src/renderer/src/components/SongInfoPage/SimilarTracksContainer.tsx songId type; queue fields rename usage (songIds/position)
src/renderer/src/components/SongInfoPage/ListeningActivityBarGraph.tsx Formatting only
src/renderer/src/components/Sidebar/Sidebar.tsx Import ordering
src/renderer/src/components/SettingsPage/SettingsPage.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/StorageSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/StartupSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/PreferencesSettings.tsx Remove userData gating for preference checkbox
src/renderer/src/components/SettingsPage/Settings/PerformanceSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/LyricsSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/LanguageSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/DefaultPageSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AudioPlaybackSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AppearanceSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AppStats.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AdvancedSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AccountsSettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AccessibilitySettings.tsx Import ordering
src/renderer/src/components/SettingsPage/Settings/AboutSettings.tsx Use settingsQuery suspense instead of store for dark mode
src/renderer/src/components/SettingsPage/ResetAppConfirmationPrompt.tsx Formatting only
src/renderer/src/components/SettingsPage/ClearLocalStoragePrompt.tsx Formatting only
src/renderer/src/components/SettingsPage/BlacklistedSong.tsx songId type number
src/renderer/src/components/SettingsPage/AppShortcutsPrompt.tsx Import ordering
src/renderer/src/components/SensitiveActionConfirmPrompt.tsx Import ordering
src/renderer/src/components/SeekBarSlider.tsx Import ordering
src/renderer/src/components/SecondaryContainer.tsx Formatting only
src/renderer/src/components/SearchPage/SearchStartPlaceholder.tsx Import ordering
src/renderer/src/components/SearchPage/SearchResultsFilter.tsx Formatting only
src/renderer/src/components/SearchPage/SearchOptions.tsx Formatting only
src/renderer/src/components/SearchPage/Result_Containers/SongSearchResultsContainer.tsx songId type number
src/renderer/src/components/SearchPage/Result_Containers/PlaylistSearchResultsContainer.tsx Import ordering
src/renderer/src/components/SearchPage/Result_Containers/MostRelevantSearchResultsContainer.tsx Queue field rename usage; route param stringification
src/renderer/src/components/SearchPage/Result_Containers/GenreSearchResultsContainer.tsx Import ordering
src/renderer/src/components/SearchPage/Result_Containers/ArtistsSearchResultsContainer.tsx Import ordering
src/renderer/src/components/SearchPage/Result_Containers/AlbumSearchResultsContainer.tsx Import ordering
src/renderer/src/components/SearchPage/RecentSearchResult.tsx Formatting only
src/renderer/src/components/SearchPage/NoSearchResultsContainer.tsx Import ordering
src/renderer/src/components/SearchPage/MostRelevantResult.tsx id type number; route param stringification
src/renderer/src/components/SearchPage/All_Search_Result_Containers/AllSongResults.tsx songId type number
src/renderer/src/components/SearchPage/All_Search_Result_Containers/AllPlaylistResults.tsx Import ordering
src/renderer/src/components/SearchPage/All_Search_Result_Containers/AllGenreResults.tsx Import ordering
src/renderer/src/components/SearchPage/All_Search_Result_Containers/AllArtistResults.tsx Import ordering
src/renderer/src/components/SearchPage/All_Search_Result_Containers/AllAlbumResults.tsx Import ordering
src/renderer/src/components/ReleaseNotesPrompt/VersionNote.tsx Formatting only
src/renderer/src/components/ReleaseNotesPrompt/Version.tsx Import ordering
src/renderer/src/components/ReleaseNotesPrompt/ReleaseNotesPrompt.tsx Import ordering
src/renderer/src/components/ReleaseNotesPrompt/ReleaseNotesAppUpdateInfo.tsx Formatting only
src/renderer/src/components/PromptMenu/PromptMenuNavigationControlsContainer.tsx Import ordering
src/renderer/src/components/PromptMenu/PromptMenu.tsx Formatting + Tailwind class changes
src/renderer/src/components/Preloader/Preloader.tsx Import ordering
src/renderer/src/components/PlaylistsPage/RenamePlaylistPrompt.tsx Tailwind class changes
src/renderer/src/components/PlaylistsPage/PlaylistOptions.tsx Import ordering
src/renderer/src/components/PlaylistsPage/NewPlaylistPrompt.tsx Import ordering
src/renderer/src/components/PlaylistsPage/MultipleArtworksCover.tsx songIds type number[]; query import ordering
src/renderer/src/components/PlaylistsPage/ConfirmDeletePlaylistsPrompt.tsx playlistIds type number[]; SpecialPlaylists usage
src/renderer/src/components/PlaylistsInfoPage/PlaylistInfoAndImgContainer.tsx Import ordering
src/renderer/src/components/OpenLinkConfirmPrompt.tsx Import ordering
src/renderer/src/components/NotificationPanel/NotificationPanel.tsx Import ordering
src/renderer/src/components/NotificationPanel/NotificationClearAllButton.tsx Formatting only
src/renderer/src/components/NotificationPanel/Notification.tsx Import ordering
src/renderer/src/components/NavLink.tsx Doc comment formatting
src/renderer/src/components/MusicFoldersPage/folderOptions.tsx Formatting only
src/renderer/src/components/MusicFoldersPage/SelectableFolder.tsx Import ordering
src/renderer/src/components/MusicFoldersPage/RemoveFolderConfirmationPrompt.tsx Formatting only
src/renderer/src/components/MusicFoldersPage/BlacklistFolderConfirmPrompt.tsx Formatting only
src/renderer/src/components/MusicFoldersPage/AddMusicFoldersPrompt.tsx Import ordering
src/renderer/src/components/MultipleSelectionCheckbox.tsx id type number; stringified for Checkbox id
src/renderer/src/components/MiniPlayer/containers/TitleBarContainer.tsx Import ordering
src/renderer/src/components/MiniPlayer/containers/LyricsContainer.tsx Import ordering
src/renderer/src/components/MiniPlayer/MiniPlayer.tsx Import ordering
src/renderer/src/components/MainContainer.tsx Formatting only
src/renderer/src/components/LyricsPage/NoLyrics.tsx Formatting only
src/renderer/src/components/LyricsPage/LyricsMetadata.tsx Formatting only
src/renderer/src/components/LyricsPage/LyricLine.tsx Formatting only
src/renderer/src/components/LyricsEditingPage/LyricsEditorSettingsPrompt.tsx Import ordering
src/renderer/src/components/LyricsEditingPage/LyricsEditorSavePrompt.tsx Import ordering
src/renderer/src/components/LyricsEditingPage/LyricsEditorHelpPrompt.tsx Import ordering
src/renderer/src/components/LyricsEditingPage/LyricsEditingPageDurationCounter.tsx Formatting only
src/renderer/src/components/LyricsEditingPage/EnhancedSyncedLyricWord.tsx Formatting only
src/renderer/src/components/LyricsEditingPage/EditingLyricsLine.tsx Import ordering
src/renderer/src/components/Img.tsx Import ordering
src/renderer/src/components/Hyperlink.tsx Import ordering
src/renderer/src/components/HomePage/RecentlyPlayedSongs.tsx Import ordering
src/renderer/src/components/HomePage/RecentlyPlayedArtists.tsx Import ordering
src/renderer/src/components/HomePage/RecentlyAddedSongs.tsx Import ordering
src/renderer/src/components/HomePage/MostLovedSongs.tsx Import ordering
src/renderer/src/components/HomePage/MostLovedArtists.tsx Import ordering
src/renderer/src/components/GenresPage/genreOptions.tsx Formatting only
src/renderer/src/components/GenreInfoPage/GenreImgAndInfoContainer.tsx Import ordering
src/renderer/src/components/FullScreenPlayer/containers/SongInfoContainer.tsx Import ordering
src/renderer/src/components/FullScreenPlayer/containers/LyricsContainer.tsx Import ordering
src/renderer/src/components/FullScreenPlayer/FullScreenPlayer.tsx Formatting + import ordering
src/renderer/src/components/ErrorPrompt.tsx Import ordering
src/renderer/src/components/ErrorBoundary.tsx Import ordering
src/renderer/src/components/ContextMenu/ContextMenuItem.tsx Formatting only
src/renderer/src/components/ContextMenu/ContextMenu.tsx Import ordering
src/renderer/src/components/Checkbox.tsx Tailwind class tweaks
src/renderer/src/components/BodyAndSidebarContainer.tsx Import ordering
src/renderer/src/components/Biography/HashTag.tsx Formatting only
src/renderer/src/components/Biography/Biography.tsx Import ordering
src/renderer/src/components/ArtistPage/ArtistOptions.tsx Formatting only
src/renderer/src/components/ArtistPage/Artist.tsx artistId/songIds types; route param stringification; queue field rename
src/renderer/src/components/ArtistInfoPage/SimilarArtistsContainer.tsx Import ordering
src/renderer/src/components/ArtistInfoPage/SeparateArtistsSuggestion.tsx Switch ignore handling to user preferences hook
src/renderer/src/components/AlbumsPage/AlbumOptions.tsx Formatting only
src/renderer/src/components/AlbumsPage/Album.tsx selectAllHandler type; route param stringification; queue field rename
src/renderer/src/components/AlbumInfoPage/OnlineAlbumInfoContainer.tsx Import ordering
src/renderer/src/components/AlbumInfoPage/AlbumImgAndInfoContainer.tsx Formatting only
src/renderer/src/assets/locales/en/en.json Fix English strings
src/main/utils/withFileHandle.ts New utility for safe node-taglib-sharp file disposal
src/main/utils/safeStorage.ts Formatting only
src/main/utils/romanizeLyrics.ts Import ordering
src/main/utils/parseSongMetadataFromMusixmatchApiData.ts Import ordering
src/main/utils/makeDir.ts Formatting only
src/main/utils/isPathADir.ts Import ordering
src/main/utils/isBlacklisted.ts songId type number
src/main/utils/getTranslatedLyrics.ts Formatting only
src/main/utils/getRootSize.ts Regex tweak + import ordering
src/main/utils/getFileSize.ts Formatting only
src/main/utils/getDirSize.ts Change catch to catch {}; import ordering
src/main/utils/filterSongs.ts Use song.isBlacklisted instead of song.blacklist
src/main/utils/fetchSongMetadataFromInternet.ts Import ordering
src/main/utils/fetchSongArtworksFromSpotify.ts Import ordering
src/main/utils/fetchLyricsFromMusixmatch.ts Import ordering
src/main/utils/dirExists.ts Formatting only
src/main/utils/copyDir.ts Import ordering
src/main/utils/convertToRomaja.ts Import ordering
src/main/utils/convertToPinyin.ts Import ordering
src/main/update.ts Import ordering / formatting
src/main/search.ts Convert import path switch to main utils/convert
src/main/saveLyricsToSong.ts Import ordering
src/main/resetAppData.ts Import ordering
src/main/removeSongsFromLibrary.ts Convert import path; const flags
src/main/parseSong/manageAlbumsOfParsedSong.ts Import ordering
src/main/parseSong/manageAlbumArtistOfParsedSong.ts Import ordering
src/main/parseSong/generateCoverBuffer.ts Modify API to accept a string path only
src/main/other/lastFm/sendNowPlayingSongDataToLastFM.ts songId type number; convert import path
src/main/other/lastFm/sendFavoritesDataToLastFM.ts Import ordering
src/main/other/lastFm/scrobbleSong.ts songId type number; convert import path
src/main/other/lastFm/getSimilarTracks.ts songId type number; convert import path
src/main/other/lastFm/getLastFMAuthData.ts Import ordering
src/main/other/lastFm/getAlbumInfoFromLastFM.ts albumId type number; id comparisons updated
src/main/other/lastFm/generateApiRequestBodyForLastFMPostRequests.ts Import ordering
src/main/other/generatePalette.ts Import ordering; updated generateCoverBuffer call
src/main/other/discordRPC.ts Formatting only
src/main/other/discord.ts Formatting only
src/main/other/artworks.ts Import ordering; change catch to catch {}; doc formatting
src/main/migrations.ts Formatting only
src/main/logger.ts Formatting only
src/main/handleFileProtocol.ts Import ordering; change catch to catch {}
src/main/fs/resolveFilePaths.ts playlist/song id types; import ordering
src/main/fs/parseFolderStructuresForSongPaths.ts Import ordering
src/main/fs/checkForFolderModifications.ts Import ordering
src/main/fs/checkFolderForUnknownContentModifications.ts Import ordering
src/main/fs/checkFolderForContentModifications.ts Import ordering
src/main/fs/addWatchersToParentFolders.ts Import ordering
src/main/fs/addWatchersToFolders.ts Import ordering
src/main/filesystem.ts SpecialPlaylists numeric IDs; playlistIds type number[]
src/main/db/seed.ts Seed keyboard shortcuts + equalizer preset tables
src/main/db/queries/userPreferences.ts New queries for keyboard shortcuts + equalizer preset
src/main/db/queries/songs.ts Add updateSongBasicFields; rename metadata getter
src/main/db/queries/playlists.ts Import ordering
src/main/db/queries/palettes.ts Import ordering
src/main/db/queries/listens.ts Formatting only
src/main/db/queries/history.ts Import ordering
src/main/db/queries/genres.ts Add helpers + delete function + docs
src/main/db/queries/folders.ts songIds now numeric
src/main/db/queries/artworks.ts Formatting only
src/main/db/queries/artists.ts Add deleteArtist + docs; keep unlink docs
src/main/db/queries/albums.ts Add deleteAlbum + docs; add getAlbumSongIds
src/main/db/db.ts Reorder imports; lower PGlite debug; formatting
src/main/core/userPreferencesExportImport.ts New export/import for DB-backed user preferences
src/main/core/updateSongListeningData.ts songId type number
src/main/core/toggleLikeSongs.ts songIds type number[]; remove Number conversions
src/main/core/toggleLikeArtists.ts artistIds type number[]; remove Number conversions
src/main/core/toggleBlacklistFolders.ts dataUpdateEvent payload removed
src/main/core/sendPlaylistData.ts convert import path; signature tweak
src/main/core/sendAudioDataFromPath.ts Switch to node-taglib-sharp; id/duration handling changes
src/main/core/sendAudioData.ts songId type number; artist/album id types
src/main/core/saveLyricsToLrcFile.ts Import ordering
src/main/core/saveArtworkToSystem.ts Update import paths for updateSong/updateSongId3Tags
src/main/core/restoreBlacklistedSongs.ts blacklistedSongIds type number[]
src/main/core/restoreBlacklistedFolder.ts Import ordering
src/main/core/resolveSeparateArtists.ts separateArtistId type number; updateSong import path
src/main/core/resolveFeaturingArtists.ts songId type number; updateSong import path
src/main/core/resolveDuplicates.ts selectedArtistId/duplicateIds types number[]
src/main/core/renameAPlaylist.ts playlistId type number
src/main/core/removeSongFromPlaylist.ts playlistId/songId types number
src/main/core/removePlaylists.ts playlistIds type number[]
src/main/core/removeMusicFolder.ts Import ordering
src/main/core/removeFromFavorites.ts songId type number
src/main/core/manageTaskbarPlaybackButtonControls.ts Import ordering
src/main/core/importPlaylist.ts Import ordering
src/main/core/getStorageUsage.ts Import ordering
src/main/core/getSongLyrics.ts Import ordering; change catch to catch {}
src/main/core/getSongInfo.ts songIds type number[]; convert import path
src/main/core/getMusicFolderData.ts Import ordering
src/main/core/getListeningData.ts songIds type number[]
src/main/core/getGenresInfo.ts convert import path
src/main/core/getFolderStructures.ts Import ordering
src/main/core/getDuplicates.ts Import ordering
src/main/core/getArtworksForMultipleArtworksCover.ts songIds type number[]
src/main/core/getArtistInfoFromNet.ts artistId type number; convert import path
src/main/core/getAllSongs.ts convert import path
src/main/core/getAllHistorySongs.ts convert import path
src/main/core/getAllFavoriteSongs.ts convert import path
src/main/core/fetchSongInfoFromLastFM.ts Import ordering
src/main/core/fetchArtistData.ts convert import path
src/main/core/fetchAlbumData.ts convert import path
src/main/core/exportPlaylist.ts playlistId type number
src/main/core/exportAppData.ts Include user_preferences.json export
src/main/core/deleteSongsFromSystem.ts Import ordering
src/main/core/convertParsedLyricsToNodeID3Format.ts Formatting only
src/main/core/clearSongHistory.ts Formatting only
src/main/core/clearSeachHistoryResults.ts Formatting only
src/main/core/checkForStartUpSongs.ts Import ordering
src/main/core/checkForNewSongs.ts Import ordering
src/main/core/changeAppTheme.ts dataUpdateEvent payload removed
src/main/core/blacklistSongs.ts songIds type number[]
src/main/core/blacklistFolders.ts Import ordering
src/main/core/addSongsToPlaylist.ts playlistId/songIds types number; remove Number conversions
src/main/core/addNewPlaylist.ts Update import paths; convert import path
src/main/core/addMusicFolder.ts Import ordering
src/main/core/addArtworkToAPlaylist.ts playlistId type number
src/main/auth/manageLastFmAuth.ts Import ordering
src/common/playlists.enum.ts New SpecialPlaylists constants + helper
src/common/parseLyrics.ts Regex tweak + catch to catch {}
src/common/isLyricsSynced.ts Regex tweak for extended synced lyrics
skills-lock.json New skills lockfile
scripts/dropDatabase.ts Import ordering
resources/drizzle/meta/_journal.json Add migration journal entry
resources/drizzle/0001_add_user_preferences.sql New schema for user preferences tables
prettier.config.cjs Removed Prettier config
flatpak/app.netlify.noramusic.Nora.json Formatting only
eslint.config.mjs Removed ESLint flat config
electron.vite.config.ts Remove externalizeDepsPlugin; update TanStack Router plugin paths
.vscode/launch.json JSON formatting fix
.prettierignore Removed (replaced by .oxfmtrc ignorePatterns)
.oxfmtrc.json New Oxfmt config (format, import sort, ignore patterns)
.env.example Add env var template for local development

Comment on lines 144 to 148
const ignoreSuggestion = useCallback(() => {
storage.ignoredSongsWithFeatArtists.setIgnoredSongsWithFeatArtists([songId]);
if (!songId) return;
addIgnoredFeaturingArtistMutation.mutate({ songIds: [songId] });

setIsIgnored(true);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignoredFeaturingArtists (as implied by the hook name and the DB migration/table naming) appears to store artist IDs, but this UI is passing songIds. This will either fail at runtime (type mismatch) or silently persist incorrect data. Consider either (mandatory) changing the mutation payload to persist an artist ID (and rename any UI variables that call these "ignoredSongs"), or (alternative) introduce a separate preference/table specifically for “ignored songs with featuring-artist suggestions” and wire this component to that store.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +43
ignoredArtists: ignored.map((item) => item.artistId),
ignoredFeaturingArtists: ignoredFeating.map((item) => item.artistId),
ignoredDuplicateMetadata: ignoredDuplicate.map((item) => ({
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export/import model treats ignoredFeaturingArtists as an array of artistIds, but the renderer uses that preference list as “ignored songs” (see SongsWithFeaturingArtistsSuggestion). The preference semantics need to be made consistent (mandatory): either rename and use it as artist IDs everywhere, or create a separate persisted preference keyed by song ID and export/import that instead.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
const file = File.createFromPath(songPath);
const metadata = file.tag;
if (metadata) {
const artworkData = metadata.common?.picture?.at(0)?.data;
const artworkData = metadata.pictures?.at(0)?.data?.toByteArray();
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File.createFromPath() allocates a native handle in node-taglib-sharp, but the handle is never disposed here (risking leaked file handles / memory, especially when scanning or previewing many files). Additionally, generating songId with Math.random() can collide with real DB IDs or other temp IDs, leading to incorrect lookups and UI behavior. Use the new withFileHandle() wrapper (or an explicit try/finally calling file.dispose()) and generate a collision-resistant temp ID (e.g., a negative range based on -Date.now() or a UUID mapped to a safe numeric namespace if you must keep number).

Copilot uses AI. Check for mistakes.
artworkPath: tempArtworkPath,
path: path.join(DEFAULT_FILE_URL, songPath),
songId: generateRandomId(),
songId: Math.floor(Math.random() * 1000000),
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File.createFromPath() allocates a native handle in node-taglib-sharp, but the handle is never disposed here (risking leaked file handles / memory, especially when scanning or previewing many files). Additionally, generating songId with Math.random() can collide with real DB IDs or other temp IDs, leading to incorrect lookups and UI behavior. Use the new withFileHandle() wrapper (or an explicit try/finally calling file.dispose()) and generate a collision-resistant temp ID (e.g., a negative range based on -Date.now() or a UUID mapped to a safe numeric namespace if you must keep number).

Copilot uses AI. Check for mistakes.
<DialogPanel
ref={promptMenuRef}
transition
className="bg-background-color-1 dark:bg-dark-background-color-1 relative h-fit max-h-[80%] min-h-75 w-[80%] max-w-[90%] min-w-[800px] transform overflow-hidden overflow-y-auto rounded-2xl text-left shadow-xl transition-all data-closed:scale-95 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-lg">
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

min-h-75 is not part of Tailwind’s default spacing scale (unless this project has custom spacing values configured). If it’s not configured, this class will be dropped and the dialog may become too short/tall unexpectedly. Prefer bracket notation for non-standard values (e.g., min-h-[300px]) or ensure the spacing scale explicitly includes 75.

Suggested change
className="bg-background-color-1 dark:bg-dark-background-color-1 relative h-fit max-h-[80%] min-h-75 w-[80%] max-w-[90%] min-w-[800px] transform overflow-hidden overflow-y-auto rounded-2xl text-left shadow-xl transition-all data-closed:scale-95 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-lg">
className="bg-background-color-1 dark:bg-dark-background-color-1 relative h-fit max-h-[80%] min-h-[300px] w-[80%] max-w-[90%] min-w-[800px] transform overflow-hidden overflow-y-auto rounded-2xl text-left shadow-xl transition-all data-closed:scale-95 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-lg">

Copilot uses AI. Check for mistakes.
type="text"
name="playlistName"
className="playlist-name-input bg-background-color-2! text-font-color-black dark:bg-dark-background-color-2! dark:text-font-color-white w-fit max-w-[75%] min-w-[400px] rounded-2xl border-[transparent] px-6 py-3 text-lg outline-hidden"
className="playlist-name-input bg-background-color-2! text-font-color-black dark:bg-dark-background-color-2! dark:text-font-color-white w-fit max-w-[75%] min-w-100 rounded-2xl border-transparent px-6 py-3 text-lg outline-hidden"
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

min-w-100 is also not part of Tailwind’s default spacing scale (unless customized). If not configured, this will be ignored and layout may regress. Prefer min-w-[400px] (as before) or another known Tailwind token (e.g., min-w-96) / project-defined spacing token.

Suggested change
className="playlist-name-input bg-background-color-2! text-font-color-black dark:bg-dark-background-color-2! dark:text-font-color-white w-fit max-w-[75%] min-w-100 rounded-2xl border-transparent px-6 py-3 text-lg outline-hidden"
className="playlist-name-input bg-background-color-2! text-font-color-black dark:bg-dark-background-color-2! dark:text-font-color-white w-fit max-w-[75%] min-w-[400px] rounded-2xl border-transparent px-6 py-3 text-lg outline-hidden"

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +27
year: data.year || null,
trackNumber: data.trackNumber || null
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using || null will coerce valid falsy values to null (e.g., year: 0 becomes null). For numeric fields, prefer nullish coalescing (?? null) so that only undefined/null become null. This is particularly important if 0 is a meaningful value in any of these fields now or in future migrations.

Suggested change
year: data.year || null,
trackNumber: data.trackNumber || null
year: data.year ?? null,
trackNumber: data.trackNumber ?? null

Copilot uses AI. Check for mistakes.
Comment on lines 20 to 23
}
} catch (error) {
} catch {
logger.error('Failed to calculate dir size of a directory.');
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch {} drops the underlying error details, which makes diagnosing filesystem issues (permissions, broken symlinks, transient IO failures) much harder in production logs. Consider capturing the error and logging it (e.g., include { error, filepath }), while still returning 0 to keep behavior stable.

Copilot uses AI. Check for mistakes.
import storage from '../../utils/localStorage';

const BlacklistSongConfrimPrompt = (props: { songIds: string[]; title?: string }) => {
const BlacklistSongConfrimPrompt = (props: { songIds: number[]; title?: string }) => {
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confrim appears to be a typo in the component name (and there are similar occurrences elsewhere). Since this component is being edited anyway, consider renaming to BlacklistSongConfirmPrompt for clarity and to reduce future import/name churn.

Copilot uses AI. Check for mistakes.
Sandakan added 2 commits April 4, 2026 15:51
…tCard component

- Updated FavoritesPlaylistInfoPage to include an importSongsToFavorites feature, allowing users to import songs directly into the favorites playlist.
- Improved the layout and functionality of the favorites playlist, including better handling of song actions and notifications.
- Introduced a new SpecialPlaylistCard component for displaying special playlists with context menu options for exporting playlists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants