{"id":34418424,"url":"https://github.com/llehouerou/waves","last_synced_at":"2026-02-11T11:13:10.084Z","repository":{"id":327013967,"uuid":"1105798876","full_name":"llehouerou/waves","owner":"llehouerou","description":"Terminal music player with library browser, Soulseek downloads, MusicBrainz tagging, Last.Fm integration. Built with Go and Bubble Tea.","archived":false,"fork":false,"pushed_at":"2026-01-22T17:39:46.000Z","size":1690,"stargazers_count":91,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-23T00:28:35.891Z","etag":null,"topics":["audio","bubbletea","cli","flac","go","golang","lastfm","linux","mp3","music-player","musicbrainz","radio","slskd","soulseek","terminal","tui"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/llehouerou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-28T07:12:43.000Z","updated_at":"2026-01-22T17:40:04.000Z","dependencies_parsed_at":"2025-12-18T14:06:01.328Z","dependency_job_id":null,"html_url":"https://github.com/llehouerou/waves","commit_stats":null,"previous_names":["llehouerou/waves"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/llehouerou/waves","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llehouerou%2Fwaves","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llehouerou%2Fwaves/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llehouerou%2Fwaves/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llehouerou%2Fwaves/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/llehouerou","download_url":"https://codeload.github.com/llehouerou/waves/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llehouerou%2Fwaves/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28736601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T19:23:36.361Z","status":"ssl_error","status_checked_at":"2026-01-24T19:23:28.966Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","bubbletea","cli","flac","go","golang","lastfm","linux","mp3","music-player","musicbrainz","radio","slskd","soulseek","terminal","tui"],"created_at":"2025-12-21T03:00:21.407Z","updated_at":"2026-02-11T11:13:10.078Z","avatar_url":"https://github.com/llehouerou.png","language":"Go","funding_links":[],"categories":["Applications","Table of Contents"],"sub_categories":["Media"],"readme":"\u003ch1 align=\"center\"\u003eWaves\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  A keyboard-driven terminal music player for Linux with Soulseek downloads, MusicBrainz tagging, Last.fm scrobbling, and radio mode.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/llehouerou/waves/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/llehouerou/waves\" alt=\"Release\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://aur.archlinux.org/packages/waves-bin\"\u003e\u003cimg src=\"https://img.shields.io/aur/version/waves-bin\" alt=\"AUR\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/llehouerou/waves/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/llehouerou/waves\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/llehouerou/waves\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/llehouerou/waves\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/demo.gif\" alt=\"Waves terminal music player demo\" width=\"800\"\u003e\n\u003c/p\u003e\n\n\u003e **Note:** This project is in active development. Some features may be incomplete.\n\n## Features\n\n- **Library Browser**: Browse music by Artist \u003e Album \u003e Track hierarchy\n- **File Browser**: Navigate filesystem with file/folder deletion\n- **Playlists**: Create, organize, and manage playlists with folder hierarchy\n- **Favorites**: Quick-access playlist with heart icon display\n- **Playing Queue**: Persistent queue with multi-selection, reordering, and undo/redo\n- **Audio Playback**: MP3, FLAC, OPUS/OGG, and M4A/AAC support with seeking\n- **Album Art**: Display album art in expanded player bar, auto-fetch during import\n- **Full-Text Search**: SQLite FTS5 search across library, files, and playlists\n- **Download Manager**: Search and download from Soulseek via slskd integration\n- **Import System**: MusicBrainz tagging, file renaming, and library integration\n- **Last.fm Scrobbling**: Track your listening history with offline queue support\n- **Radio Mode**: Endless playback with Last.fm similar artists and intelligent track selection\n- **Desktop Notifications**: Optional notifications for track changes and downloads (Linux)\n- **Mouse Support**: Click to navigate, select tracks, and control playback\n- **State Persistence**: Queue and navigation saved between sessions\n\n## Installation\n\n### Arch Linux (AUR)\n\n```bash\nyay -S waves-bin\n```\n\n### Nix\n\n```bash\nnix run github:llehouerou/waves\n```\n\nOr add to your flake inputs for a persistent installation.\n\n### From Source\n\n```bash\ngo install github.com/llehouerou/waves@latest\n```\n\nRequires Go 1.25+ and ALSA development libraries (`libasound2-dev` on Debian/Ubuntu, `alsa-lib` on Arch).\n\n## Development\n\n```bash\ngit clone https://github.com/llehouerou/waves.git\ncd waves\nmake install-hooks  # Install git pre-commit hook\nmake run            # Run the app\n```\n\n## Controls\n\nPress `?` at any time to show the keybinding help popup.\n\n### Global\n\n| Key | Action |\n|-----|--------|\n| `q` / `ctrl+c` | Quit |\n| `Tab` | Switch focus (navigator / queue) |\n| `p` | Toggle queue panel |\n| `/` | Search current items |\n| `?` | Show help |\n| `ctrl+z` | Undo |\n| `ctrl+shift+z` | Redo |\n\n### View Switching\n\n| Key | Action |\n|-----|--------|\n| `F1` | Library view |\n| `F2` | File browser view |\n| `F3` | Playlists view |\n| `F4` | Downloads view |\n\n### F-Sequence Commands\n\n| Key | Action |\n|-----|--------|\n| `f` `f` | Deep search |\n| `f` `r` | Refresh library (incremental) |\n| `f` `R` | Full rescan library |\n| `f` `p` | Library sources manager |\n| `f` `d` | Download from Soulseek |\n| `f` `l` | Last.fm settings |\n\n### Playback\n\n| Key | Action |\n|-----|--------|\n| `Space` | Play/pause |\n| `s` | Stop |\n| `v` | Toggle player display |\n| `R` | Cycle repeat mode (off/all/one/radio) |\n| `S` | Toggle shuffle |\n| `+` / `-` | Volume +/-10% |\n| `M` | Toggle mute |\n| `Shift+Left/Right` | Seek -/+5 seconds |\n| `Alt+Shift+Left/Right` | Seek -/+15 seconds |\n| `PgDown` / `PgUp` | Next/previous track |\n| `Home` / `End` | First/last track |\n\n### Navigator\n\n| Key | Action |\n|-----|--------|\n| `h` `j` `k` `l` / Arrows | Navigate |\n| `Enter` | Play (replace queue) |\n| `a` | Add to queue |\n| `ctrl+a` | Add to playlist |\n| `g` / `G` | First/last item |\n| `ctrl+d` / `ctrl+u` | Half page down/up |\n\n### Library (F1 view)\n\n| Key | Action |\n|-----|--------|\n| `d` | Delete track |\n| `F` | Toggle favorite |\n| `V` | Toggle album view |\n| `t` | Retag album |\n\n### Album View Options\n\n| Key | Action |\n|-----|--------|\n| `o` `g` | Album grouping |\n| `o` `s` | Album sorting |\n| `o` `p` | Album presets |\n\n### File Browser (F2 view)\n\n| Key | Action |\n|-----|--------|\n| `d` | Delete file/folder |\n\n### Playlists (F3 view)\n\n| Key | Action |\n|-----|--------|\n| `n` | Create new playlist |\n| `N` | Create new folder |\n| `ctrl+r` | Rename playlist/folder |\n| `ctrl+d` | Delete playlist/folder |\n\n### Playlist Track Editing\n\n| Key | Action |\n|-----|--------|\n| `d` | Remove track |\n| `J` / `K` | Move track down/up |\n\n### Queue Panel\n\n| Key | Action |\n|-----|--------|\n| `x` | Toggle selection |\n| `d` / `Delete` | Delete selected |\n| `c` | Clear except playing |\n| `Shift+J` / `Shift+K` | Move selected down/up |\n| `Enter` | Play track |\n| `Esc` | Clear selection |\n| `L` | Locate in navigator |\n| `g` / `G` | First/last item |\n| `ctrl+d` / `ctrl+u` | Half page down/up |\n\n## Configuration\n\nCopy `config.example.toml` to `~/.config/waves/config.toml` or `./config.toml`.\n\n```toml\n# Default folder to open on startup (supports ~)\ndefault_folder = \"~/Music\"\n\n# Icon style: \"nerd\" (Nerd Font), \"unicode\" (emoji), \"none\" (text)\nicons = \"nerd\"\n\n# slskd integration for downloading music from Soulseek\n[slskd]\nurl = \"http://localhost:5030\"\napikey = \"your-api-key-here\"\ncompleted_path = \"~/downloads/complete\"  # For disk verification and importing\n\n[slskd.filters]\nformat = \"both\"       # \"both\", \"lossless\", or \"lossy\"\nno_slot = true        # Filter out users with no free upload slot\ntrack_count = true    # Filter results with fewer tracks than expected\n\n[musicbrainz]\nalbums_only = true    # Filter to show only albums (not singles/EPs)\n\n# Last.fm scrobbling (get API key at https://www.last.fm/api/account/create)\n[lastfm]\napi_key = \"your-api-key\"\napi_secret = \"your-api-secret\"\n```\n\n### Library Sources\n\nLibrary sources are managed in-app using `f p` in the library view (F1). This opens a popup where you can add, remove, and view source paths. Sources are persisted in the database, not the config file.\n\n### Download Manager\n\nThe download manager requires a running [slskd](https://github.com/slskd/slskd) instance. Configure the URL and API key in `config.toml`, then use `f d` to open the download popup. Search for artists/albums, select a release from MusicBrainz, and download matching results from Soulseek. Downloaded files can be imported with MusicBrainz tagging and Picard-compatible file renaming.\n\n**Completed downloads path:**\n\nTo enable disk verification and importing, set `completed_path` to match your slskd completed downloads folder:\n\n```toml\n[slskd]\nurl = \"http://localhost:5030\"\napikey = \"your-api-key\"\ncompleted_path = \"~/downloads/complete\"  # Path to slskd's completed folder\n```\n\nThe app matches files by extracting the folder name from slskd's directory path. For example, if slskd reports a download in `@@username\\Music\\Pink Floyd - The Wall`, the app looks for files in `completed_path/Pink Floyd - The Wall/`. This means:\n\n- The final folder name from slskd must match the folder on disk\n- Files are verified by checking existence and size\n- Once verified, downloads can be imported into your library\n\n### Last.fm Scrobbling\n\nScrobble your listening history to [Last.fm](https://www.last.fm). Create an API account at [last.fm/api/account/create](https://www.last.fm/api/account/create), add the credentials to `config.toml`, then link your account with `f l`. Tracks are scrobbled after 50% of playback or 4 minutes, whichever comes first. Failed scrobbles are queued and retried automatically.\n\n### Radio Mode\n\nRadio mode provides endless playback by automatically adding tracks from similar artists to your queue. It uses the Last.fm API to find artists similar to what you're currently playing, then selects tracks from your local library.\n\n**Requirements:**\n- Last.fm API credentials configured in `config.toml` (same as scrobbling)\n- A populated music library with indexed artists\n\n**Usage:**\n1. Start playing any track from your library\n2. Press `R` to cycle repeat modes until you see the radio icon (📻)\n3. The queue will automatically fill with related tracks as you listen\n\n**How it works:**\n- Finds similar artists via Last.fm API based on the currently playing artist\n- Matches similar artists to your local library using fuzzy matching\n- Scores tracks based on popularity, your listening history, and artist similarity\n- Enforces variety by limiting artist repetition and preventing oscillation patterns\n- Caches API responses locally to reduce network requests\n\n**Configuration options:**\n\n```toml\n[radio]\n# Queue behavior\nbuffer_size = 1              # Tracks to queue ahead (1-20)\n\n# Artist selection\nsimilar_artists_limit = 50   # Similar artists to fetch from API\nshuffle_pool_size = 10       # Top N artists to shuffle from\nartists_per_fill = 5         # Artists to use per fill after shuffle\nartist_match_threshold = 0.8 # Fuzzy match threshold (0.0-1.0)\n\n# Variety enforcement\nmax_artist_repeat = 2        # Max times same artist in window\nartist_repeat_window = 20    # Window size for repeat check\nrecent_seeds_window = 3      # Seeds to remember for A→B→A prevention\n\n# Scoring weights\ntop_track_boost = 3.0        # Boost multiplier for top tracks\nuser_boost = 1.3             # Multiplier for user-scrobbled tracks\ndecay_factor = 0.1           # Penalty for recently played\nmin_similarity_weight = 0.1  # Floor for similarity score\n\n# Cache\ncache_ttl_days = 7           # Cache TTL in days\n```\n\n### Desktop Notifications\n\nDesktop notifications are available on Linux via D-Bus. They are disabled by default and must be enabled in `config.toml`:\n\n```toml\n[notifications]\nenabled = true           # Master toggle (required)\nnow_playing = true       # Notify on track change\ndownloads = true         # Notify when downloads complete\nshow_album_art = true    # Include album art in notifications\ntimeout = 5000           # Notification timeout in ms\n```\n\nNotifications use the system notification daemon and support album art display when available.\n\n### File Renaming (Import)\n\nWhen importing downloaded files, the rename pattern determines the folder structure and filename. Configure it with templates and smart features:\n\n```toml\n[rename]\n# Templates (defaults shown)\nfolder = \"{albumartist}/{year} • {album}\"\nfilename = \"{artist} • {album} • {tracknumber} · {title}\"\n\n# Smart features (all default to true)\nreissue_notation = true      # Add [YYYY reissue] suffix for reissues\nva_brackets = true           # Wrap \"Various Artists\" in brackets\nsingles_handling = true      # Special handling for singles\nrelease_type_notes = true    # Add [soundtrack], [live], etc.\nand_to_ampersand = true      # Convert \"and\" to \"\u0026\"\nremove_feat = true           # Remove \"feat.\" patterns from titles\nellipsis_normalize = true    # Convert \"...\" to \"…\"\n```\n\n**Available placeholders:**\n\n| Placeholder | Description |\n|-------------|-------------|\n| `{artist}` | Track artist (falls back to album artist) |\n| `{albumartist}` | Album artist |\n| `{album}` | Album title (includes reissue/release type notes when enabled) |\n| `{title}` | Track title |\n| `{year}` | Release year (prefers original release year) |\n| `{tracknumber}` | Track number (zero-padded, multi-disc aware: `01` or `01.05`) |\n| `{discnumber}` | Disc number |\n| `{date}` | Full release date |\n| `{originalyear}` | Original release year |\n\n**Examples:**\n\nSimple structure:\n```toml\nfolder = \"{albumartist}/{album}\"\nfilename = \"{tracknumber} - {title}\"\n# Result: Pink Floyd/The Dark Side of the Moon/04 - Time.flac\n```\n\nFlat structure:\n```toml\nfolder = \"{albumartist}\"\nfilename = \"{album} - {tracknumber} - {title}\"\n# Result: Pink Floyd/The Dark Side of the Moon - 04 - Time.flac\n```\n\n## License\n\nGPL-3.0 - See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllehouerou%2Fwaves","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllehouerou%2Fwaves","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllehouerou%2Fwaves/lists"}