[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

Select the types of activity you want to include in your feed.

Add "Reveal in File Manager" context menu item

Kasper (Dec 14, 2021, 10:04 PM +0100) a7a616d1 8b28db59

+53 -6
+1
CHANGELOG.md
··· 7 7 - Add `Ctrl+]` and `Ctrl+]` (macOS: `Cmd+]` and `Cmd+]`) for opening the next and previous track in the "Get Info" window 8 8 - Add metadata editing of bpm, track number, total tracks, disc number and total discs 9 9 - Add more items to the Song menu 10 + - Add "Reveal in File Manager" menu item 10 11 - Add `Escape` shortcut for deselecting tracks 11 12 - Add support selecting tracks via `Ctrl+A` (macOS: `Cmd+A`), `Shift+Up/Down`, `Alt+Up/Down`, `Shift+Alt+Up/Down` 12 13 - Expand the titlebar drag region a bit
+7 -2
README.md
··· 20 20 ### ToDo 21 21 22 22 - Playlist covers 23 - - Make removing from playlists work when filter or sorting is used (rn, if you remove the first shown track, it would remove the first track in the playlist) 24 - - iTunes Import overwrites library, but old track/artwork files are still kept. Either move or delete them 23 + - Import m4a files 24 + - Move playlists 25 + - Edit playlists 26 + - Create playlist folder 27 + - Allow removing tracks from playlists when filter or sorting is used 28 + - Move iTunes Import to Rust 29 + - iTunes Import overwrites library, but old track files are still kept 25 30 - Databases 26 31 - https://github.com/TheNeikos/rustbreak 27 32 - https://github.com/spacejam/sled
+15 -2
src/components/TrackList.svelte
··· 8 8 trackLists as trackListsStore, 9 9 addTracksToPlaylist, 10 10 deleteTracksInOpen, 11 + paths, 11 12 } from '../stores/data' 12 13 import { newPlaybackInstance, playingId } from '../stores/player' 13 14 import { ··· 42 43 if ($page.tracklist.type === 'playlist') { 43 44 removeFromOpenPlaylist(indexes) 44 45 } 46 + } else if (clickedId === 'revealTrackFile') { 47 + const track = page.getTrack(indexes[0]) 48 + ipcRenderer.invoke('revealTrackFile', paths.tracks_dir, track.file) 45 49 } else if (clickedId === 'Get Info') { 46 50 trackInfo.visible.open(page.getTrackIds(), indexes[0]) 47 51 } else { ··· 65 69 trackInfo.visible.open(page.getTrackIds(), index) 66 70 } 67 71 } 72 + function revealTrackFile() { 73 + const index = selection.findFirst($selection.list) 74 + if (index !== null) { 75 + let firstIndex = selection.findFirst($selection.list) || 0 76 + const track = page.getTrack(firstIndex) 77 + ipcRenderer.invoke('revealTrackFile', paths.tracks_dir, track.file) 78 + } 79 + } 68 80 function removeFromPlaylist() { 69 81 if ($page.tracklist.type === 'playlist') { 70 82 const indexes = selection.getSelectedIndexes($selection) ··· 76 88 deleteTracksInOpen(indexes) 77 89 } 78 90 onMount(() => { 79 - ipcRenderer.on('Get Info', getInfo) 80 91 ipcRenderer.on('Play Next', playNext) 81 92 ipcRenderer.on('Add to Queue', addToQueue) 93 + ipcRenderer.on('revealTrackFile', revealTrackFile) 82 94 ipcRenderer.on('Remove from Playlist', removeFromPlaylist) 83 95 ipcRenderer.on('Delete from Library', deleteFromLibrary) 84 96 }) 85 97 onDestroy(() => { 86 - ipcRenderer.off('Get Info', getInfo) 87 98 ipcRenderer.off('Play Next', playNext) 88 99 ipcRenderer.off('Add to Queue', addToQueue) 100 + ipcRenderer.off('Get Info', getInfo) 101 + ipcRenderer.off('revealTrackFile', revealTrackFile) 89 102 ipcRenderer.off('Remove from Playlist', removeFromPlaylist) 90 103 ipcRenderer.off('Delete from Library', deleteFromLibrary) 91 104 })
+16 -1
src/electron/ipc.js
··· 1 - const { ipcMain, dialog, Menu } = require('electron') 1 + const { ipcMain, dialog, Menu, shell } = require('electron') 2 + const path = require('path') 3 + const is = require('./is.js') 2 4 3 5 ipcMain.handle('showMessageBox', async (e, options) => { 4 6 return await dialog.showMessageBox(options) ··· 18 20 } 19 21 }) 20 22 23 + ipcMain.handle('revealTrackFile', async (e, ...paths) => { 24 + shell.showItemInFolder(path.join(...paths)) 25 + }) 26 + 21 27 ipcMain.handle('showTrackMenu', (e, list) => { 22 28 return new Promise((resolve, reject) => { 23 29 for (const item of list) { ··· 40 46 { 41 47 label: 'Get Info', 42 48 click: () => resolve('Get Info'), 49 + }, 50 + { type: 'separator' }, 51 + { 52 + label: (() => { 53 + if (is.mac) return 'Reveal in Finder' 54 + else if (is.windows) return 'Reveal in File Explorer' 55 + else return 'Reveal in File Manager' 56 + })(), 57 + click: () => resolve('revealTrackFile'), 43 58 }, 44 59 { type: 'separator' }, 45 60 {
+2 -1
src/electron/is.js
··· 1 1 module.exports = { 2 + dev: process.env.NODE_ENV === 'development', 2 3 mac: process.platform === 'darwin', 3 - dev: process.env.NODE_ENV === 'development', 4 + windows: process.platform === 'win32', 4 5 }
+12
src/electron/menubar.js
··· 97 97 }, 98 98 { type: 'separator' }, 99 99 { 100 + label: (() => { 101 + if (is.mac) return 'Reveal in Finder' 102 + else if (is.windows) return 'Reveal in File Explorer' 103 + else return 'Reveal in File Manager' 104 + })(), 105 + accelerator: 'Alt+CmdOrCtrl+R', 106 + click: () => { 107 + mainWindow.webContents.send('revealTrackFile') 108 + }, 109 + }, 110 + { type: 'separator' }, 111 + { 100 112 label: 'Remove from Playlist', 101 113 accelerator: '', 102 114 click: () => {