···11-# Pipris 
11+# Pipris 
2233-Pipris is an extensible MPRIS scrobbler written in Deno. It was originally created for
33+Pipris is an extensible MPRIS scrobbler written with Deno. It was originally created for
44[teal.fm](https://teal.fm), but can be extended to support a wide variety of
55services (e.g. Last.fm or Discord rich presence).
6677The name is derived from [piper](https://tangled.org/teal.fm/piper) +
88[MPRIS](https://specifications.freedesktop.org/mpris/latest).
991010-## Usage
1010+## Development
1111+1212+The following modules are built in:
11131212-There is an example module in `src/modules/example.js.disabled`, and a teal.fm module in `src/modules/teal.js`.
1414+- <code>src/modules/<ins>**discord**</ins>.js</code>
1515+1616+ Discord rich presence
1717+1818+- <code>src/modules/<ins>**teal**</ins>.js</code>
1919+2020+ teal.fm scrobbler
2121+2222+- <code>src/modules/<ins>**example**</ins>.js.disabled</code>
2323+2424+ Example module stub
2525+2626+## Configuration
2727+2828+For every module, there is a matching *.json file in the `config` folder. Most options should be self-explanatory, though some will be listed below for clarity.
2929+3030+### global.json
3131+3232+`global.json` currently has 1 option: `"playerListMode"`. This can be set to one of three options:
3333+3434+- `"on"`
3535+3636+ Will only capture MPRIS events from whitelisted players (defined in `src/mpris.js`).
3737+3838+- `"priority"`
3939+4040+ All MPRIS events will be captured, but ones coming from players in the player list will be prioritised.
4141+4242+- `"off"`
4343+4444+ The player list will be completely disabled.
···55const PROPS_IFACE = "org.freedesktop.DBus.Properties";
6677// Lowercase substrings matched against the bus name suffix.
88-// These are local/offline music players that should be preferred.
99-const PREFERRED_PLAYERS = [
88+// Only players matching this whitelist will be used.
99+const ALLOWED_PLAYERS = [
1010+ // local players
1011 "gapless",
1112 "elisa",
1213 "rhythmbox",
···1920 "audacious",
2021 "quodlibet",
2122 "deadbeef",
2222- "celluloid",
2323 "cmus",
2424 "musikcube",
2525 "aimp",
2626+ "spotify",
2727+ "tidal",
2828+ "deezer",
2929+ "youtube-music",
3030+ "youtubemusic",
3131+ "nuclear",
3232+ "cider",
3333+ "feishin",
3434+ "sonixd",
3535+ "navidrome",
3636+ "plexamp",
2637];
27382839/**
···4657}
47584859/**
4949- * Pick the best player from a list of bus names.
5050- * Prefers local music players; falls back to the first in the list.
6060+ * Pick the best player from a list of bus names based on the list mode.
6161+ * "off" – return the first player found (ignore the list)
6262+ * "priority" – prefer listed players, fall back to any player
6363+ * "on" – only allow listed players (strict whitelist)
5164 */
5252-export function selectPlayer(players) {
5353- if (players.length === 0) return null;
6565+export function selectPlayer(players, mode = "on") {
6666+ if (mode === "off") {
6767+ return players[0] ?? null;
6868+ }
54697070+ // Find the first player that matches the list
5571 for (const name of players) {
5672 const suffix = name.slice(MPRIS_PREFIX.length).toLowerCase();
5757- if (PREFERRED_PLAYERS.some((p) => suffix.includes(p))) {
7373+ if (ALLOWED_PLAYERS.some((p) => suffix.includes(p))) {
5874 return name;
5975 }
6076 }
6161- return players[0];
7777+7878+ // In priority mode, fall back to any player
7979+ if (mode === "priority") {
8080+ return players[0] ?? null;
8181+ }
8282+8383+ return null;
6284}
63856486/**