{"id":13674493,"url":"https://github.com/epoupon/lms","last_synced_at":"2026-06-06T15:01:27.862Z","repository":{"id":21295797,"uuid":"24611950","full_name":"epoupon/lms","owner":"epoupon","description":"Lightweight Music Server. Access your self-hosted music using a web interface.","archived":false,"fork":false,"pushed_at":"2026-06-01T14:53:41.000Z","size":14153,"stargazers_count":1596,"open_issues_count":98,"forks_count":81,"subscribers_count":12,"default_branch":"master","last_synced_at":"2026-06-01T16:27:58.638Z","etag":null,"topics":["audio","audio-streaming","listenbrainz","music","music-player","music-server","music-streaming","musicbrainz","opensubsonic","raspberry-pi","self-hosted","subsonic","subsonic-server"],"latest_commit_sha":null,"homepage":"http://lms-demo.poupon.dev","language":"C++","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/epoupon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"COPYING","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},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":"epoupon","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2014-09-29T20:34:53.000Z","updated_at":"2026-06-01T11:05:01.000Z","dependencies_parsed_at":"2023-10-14T19:56:03.117Z","dependency_job_id":"e2744bc0-ef7e-47ee-97fa-4691882971c4","html_url":"https://github.com/epoupon/lms","commit_stats":null,"previous_names":[],"tags_count":119,"template":false,"template_full_name":null,"purl":"pkg:github/epoupon/lms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epoupon%2Flms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epoupon%2Flms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epoupon%2Flms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epoupon%2Flms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epoupon","download_url":"https://codeload.github.com/epoupon/lms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epoupon%2Flms/sbom","scorecard":{"id":379198,"data":{"date":"2025-08-11","repo":{"name":"github.com/epoupon/lms","commit":"8c3ac478066490d146b3deeac70d8684661bf13d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/3 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 25 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:14","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:15","Warn: no topLevel permission defined: .github/workflows/build-alpine.yml:1","Warn: no topLevel permission defined: .github/workflows/build-arch-all.yml:1","Warn: no topLevel permission defined: .github/workflows/build-arch-basic.yml:1","Warn: no topLevel permission defined: .github/workflows/build-freebsd-basic.yml:1","Warn: no topLevel permission defined: .github/workflows/clang-format-check.yml:1","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: COPYING:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: COPYING:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-alpine.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-alpine.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-alpine.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-alpine.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-alpine.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-alpine.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-alpine.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-alpine.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-arch-all.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-all.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-arch-all.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-all.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-arch-all.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-all.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-arch-all.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-all.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-arch-basic.yml:8: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-basic.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-arch-basic.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-basic.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-arch-basic.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-basic.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-arch-basic.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-arch-basic.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-freebsd-basic.yml:7: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-freebsd-basic.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-freebsd-basic.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/build-freebsd-basic.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/clang-format-check.yml:8: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/clang-format-check.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/clang-format-check.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/clang-format-check.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:50: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/epoupon/lms/codeql.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile-build-alpine:1","Warn: containerImage not pinned by hash: Dockerfile-build-alpine:2: pin your Docker image by updating alpine:3.21 to alpine:3.21@sha256:b6a6be0ff92ab6db8acd94f5d1b7a6c2f0f5d10ce3c24af348d333ac6da80685","Warn: containerImage not pinned by hash: Dockerfile-build-arch:1: pin your Docker image by updating archlinux:latest to archlinux:latest@sha256:104d24b4464e89a16566d3e68ce0e2707aa15258c690ee9bef755930e8bc1c2d","Warn: containerImage not pinned by hash: Dockerfile-release:1","Warn: containerImage not pinned by hash: Dockerfile-release:148","Info:   0 out of  12 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   8 third-party GitHubAction dependencies pinned","Info:   0 out of   5 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/build-alpine.yml:4"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (30) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T14:59:25.488Z","repository_id":21295797,"created_at":"2025-08-18T14:59:25.488Z","updated_at":"2025-08-18T14:59:25.488Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33986901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","audio-streaming","listenbrainz","music","music-player","music-server","music-streaming","musicbrainz","opensubsonic","raspberry-pi","self-hosted","subsonic","subsonic-server"],"created_at":"2024-08-02T11:00:51.635Z","updated_at":"2026-06-06T15:01:27.853Z","avatar_url":"https://github.com/epoupon.png","language":"C++","funding_links":["https://ko-fi.com/epoupon"],"categories":["Software","C++","Apps","置顶","Media Streaming"],"sub_categories":["Media Streaming - Audio Streaming","MediaManagement","08、家庭与物联网","Audio Streaming"],"readme":"# LMS - Lightweight Music Server\n\n[![Last Release](https://img.shields.io/github/v/release/epoupon/lms?logo=github\u0026label=latest)](https://github.com/epoupon/lms/releases)\n\n_LMS_ is a self-hosted music streaming software: access your music collection from anywhere using a web interface!\n\nA [demo instance](http://lms-demo.poupon.dev) is available. Note the administration settings are not available.\n\n## Main features\n* [Subsonic/OpenSubsonic API](SUBSONIC.md) support\n* Multi-valued tags: `genre`, `mood`, `artists`, ...\n* Artist relationships: `composer`, `conductor`, `lyricist`, `mixer`, `performer`, `producer`, `remixer`\n* [Release types](https://musicbrainz.org/doc/Release_Group/Type): `album`, `single`, `EP`, `compilation`, `live`, ...\n* [Release groups](https://musicbrainz.org/doc/Release_Group) support to show different versions of albums, such as remasters, reissues, etc.\n* [MusicBrainz Identifier](https://musicbrainz.org/doc/MusicBrainz_Identifier) support to handle duplicated artist and release names\n* [ListenBrainz](https://listenbrainz.org) support for:\n  * Scrobbling and synchronizing listens\n  * Synchronizing 'love' feedbacks\n* Recommendation engine\n* Multi-library support\n* ReplayGain support\n* Audio transcoding for compatibility and reduced bandwidth\n* User management, with several [authentication backends](INSTALL.md#authentication-backend)\n* Podcasts support\n* Playlists support\n* Lyrics support\n* [Jukebox](SUBSONIC.md#jukebox-support) support\n\n## Music discovery\n_LMS_ provides several ways to help you find the music you like:\n* Tag-based filters (ex: \"_Rock_\", \"_Metal_ and _Aggressive_\", \"_Electronic_ and _Relaxed_\", ...)\n* Recommendations for similar artists and albums\n* Radio mode, with endless filling of the play queue with tracks similar to what is there\n* Searches in album, artist and track names (including sort names)\n* Starred Albums/Artists/Tracks\n* Random/Starred/Most played/Recently played/Recently added for Artist/Albums/Tracks, allowing you to search for things like:\n  * Recently added _Electronic_ artists\n  * Random _Metal_ and _Aggressive_ albums\n  * Most played _Relaxed_ tracks\n  * Starred _Jazz_ albums\n  * ...\n\n__Note__: the recommendation engine supports two modes:\n* **Tag-based**: uses metadata tags `genre` and `grouping`.\n* **Audio similarity**: uses MusicNN embeddings. Extraction throughput depends heavily on both the number of scanner threads and the speed of your storage. Typical reported speeds range from ~1k tracks/hour on a Raspberry Pi 4 (3 threads) to ~25k tracks/hour on an Intel Core i5-13500 (10 threads). To speed up extraction, consider tweaking `scanner-thread-count` in `lms.conf` (defaults to half the number of logical CPUs).\n\n## About tags\n_LMS_ primarily relies on tags to organize your music collection but also supports browsing by directory using the [Subsonic/OpenSubsonic API](SUBSONIC.md).\n\n## Artist information folder\n_LMS_ supports an Artist information folder to manage metadata and images for artists. This folder can be placed anywhere within the scanned libraries but is best located in a dedicated `ArtistInfo` directory in the root of a media library for maximum compatibility with other softwares.\n\nThe folder must follow a structure defined by Kodi, as detailed [here](https://kodi.wiki/view/Artist_information_folder). `artist.nfo` files are used to define additional artist information such as biography, sort name, and MusicBrainz ArtistID. See the format [here](https://kodi.wiki/view/NFO_files/Artists).\n\nThe canonical artist name used by _LMS_ is the one specified in the `artist.nfo` file; If an `artist.nfo` exists but does not provide a name, the name of the containing folder is used.\nIf no artist info file is provided, _LMS_ will pick the artist name found on the latest release.\n\n## Excluding files from scan\nPlace a `.lmsignore` file at the root of a media library to exclude files or directories from scanning.\n\nThe file uses a gitignore-inspired reduced syntax:\n* `*.jpg`: ignore all `.jpg` files at any depth\n* `/Unsorted/`: ignore the top-level `Unsorted/` directory only\n* `extras/`: ignore any `extras/` directory at any depth\n* `!cover.jpg`: re-include a file previously matched by a broader rule\n* `?`: matches any single character except `/`\n* `[abc]`: character class\n\nLines starting with `#` are comments. An empty file has no effect.\n\n__Note__: only one `.lmsignore` file per library root is supported; files placed in subdirectories are ignored.\n\n### Filtering\nIt is possible to apply global filters on your collection using `genre`, `mood`, `grouping`, `language`, `codec`, and by music library. More tags, including custom ones, can be added in the database administration settings.\n\n__Note__: You can use the `lms-audioinfo` tool to get an idea of the tags parsed by _LMS_.\n\n### Multiple artists\n_LMS_ works best when using the default [Picard](https://picard.musicbrainz.org/) settings, where the `artist` tag contains a single display-friendly value, and the `artists` tag holds the actual artist names. This ensures a cleaner, more organized representation of artist names, when multiple artists are involved.\n\n### Multiple album artists\nWhile _LMS_ can manage multiple album artists using the `albumartist` tag, it works better when using the custom `albumartists` and `albumartistssort` tags, similar to how it handles regular artist tags.\n\n__Note__: if you use Picard, add this script to set up both artist and album artist tags:\n```\n$setmulti(artistssort,%_artists_sort%)\n$setmulti(albumartists,%_albumartists%)\n$setmulti(albumartistssort,%_albumartists_sort%)\n```\n\n### Extended artist and MusicBrainz ID support\n_LMS_ supports several non-standard tags to allow more accurate artist identification:\n* **MusicBrainz identifiers** for artist relationships: `musicbrainz_composerid`, `musicbrainz_conductorid`, `musicbrainz_lyricistid`, `musicbrainz_mixerid`, `musicbrainz_producerid`, `musicbrainz_remixerid`\n* **Sort order variants**: , `albumartistssort`, `composerssort`, `conductorssort`, `lyricistssort`, `mixerssort`, `producerssort`, `remixerssort`. Singular forms of these tags are also accepted (e.g., `conductorsort`, `lyricistsort`, etc.)\n\n### Album track grouping\nThe recommended way to group tracks within an album is to use the `musicbrainz_albumid` tag.\n\nWhen this tag is not present, _LMS_ will attempt to group them as best as possible: if the analyzed file contains a disc number and the total number of discs is greater than 1, sibling directories are also scanned to find a matching album.\nOtherwise, _LMS_ will only consider albums within the current directory.  \n\nFor an album to be considered a match, the following conditions must be met:\n* Same name\n* Same sort name\n* Same total number of discs\n* Identical 'compilation' flag value\n* Same record labels\n* Same barcode\n\n## Artist image lookup\nThe recommended method is to name the artist image file using the artist's MusicBrainz ArtistID. This file can be placed anywhere within one of the scanned libraries.\n\nIf no file with the MusicBrainz ArtistID is found, _LMS_ will first look for files named `folder` and then `thumb` in the artist information directory, where the corresponding `artist.nfo` file is located.\nIf neither exists, it will then search for a file named `artist` (or another name configured in `lms.conf`) in the artist's directories, using this logic:\n1. Identify the artist's directory: _LMS_ selects all albums by the artist using the \"AlbumArtist\" link and determines the longest common path among them.\n2. Scan for the image: the directory is scanned starting from this common path, moving upwards if needed, until the artist image file is found.\n3. Fallback search: if no image is found, _LMS_ will then search within each individual album folder.\n\n## Disc image lookup\n_LMS_ automatically associates images with each disc in your collection. Name the image file after the disc's subtitle or another identifier configured in `lms.conf` (see the `medium-image-file-names` setting), and place it in the same directory as the disc's tracks. If no suitable image is found, LMS will also look for embedded images within the tracks of the disc.\n\n## Playlist support\n_LMS_ supports playlist files in `m3u` and `m3u8` formats. These playlists are synced during the scan process and are available as public shared playlists.\n\n### Playlist image lookup\n_LMS_ resolves a playlist's cover image in this order:\n1. **`#EXTIMG:` directive**. An explicit path declared inside the playlist file (URLs are ignored).\n2. **Same-name image file**. An image file in the same directory as the playlist that shares the playlist's filename stem.\n3. **First track's artwork** – if neither of the above is found, the artwork of the first track in the playlist is used as a fallback.\n\n## Lyrics support\n_LMS_ supports lyrics in `lrc` files, `txt` files, and embedded track metadata. Both synchronized and unsynchronized lyrics are supported.\n\n## Keyboard shortcuts\n* Play/pause: \u003ckbd\u003eSpace\u003c/kbd\u003e\n* Previous track: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eLeft\u003c/kbd\u003e\n* Next track: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eRight\u003c/kbd\u003e\n* Decrease volume: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eDown\u003c/kbd\u003e\n* Increase volume: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eUp\u003c/kbd\u003e\n* Seek back by 5 seconds: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eLeft\u003c/kbd\u003e\n* Seek forward by 5 seconds: \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eRight\u003c/kbd\u003e\n\n\n## Installation\nSee [INSTALL.md](INSTALL.md) file.\n\n## Contributing\nAny feedback is welcome:\n* feel free to participate in [discussions](https://github.com/epoupon/lms/discussions) if you have questions,\n* report any bug or request for new features in the [issue tracker](https://github.com/epoupon/lms/issues),\n* submit your pull requests based on the [develop](../../tree/develop) branch.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepoupon%2Flms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepoupon%2Flms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepoupon%2Flms/lists"}