diff --git a/README.md b/README.md index a123a85..ff10b86 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ a rust application to scrobble your currently playing song on last.fm with mpris -upd 2024-08-27: i'm adding a home-manager module, eventually! - ## limitations unfortunately, because of how most mpris players work, the [Track_Id](https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html#Simple-Type:Track_Id) (unique identifier for every song in the tracklist) object is very rarely supported, or, if supported, implemented incorrectly (looking at you, [Cider](https://cider.sh/)) meaning it is impossible to tell if the track has been played twice in a row. this means you cannot have succssive scrobbles of the same song, sorry! besides this, i'd say the program is feature complete. @@ -20,10 +18,39 @@ you also have the option to define your mpris bus name, which will instead wait 1. the nix way + simply just run it: + ```sh nix run git+https://git.reidlab.pink/reidlab/lastfmpris.git ``` + or import it into your flake like so: + + ```nix + lastfmpris.url = "git+https://git.reidlab.pink/reidlab/lastfmpris.git"; + # in your `homeManagerConfiguration`: + imports = [ + inputs.lastfmpris.homeManagerModules.lastfmpris; + ]; + ``` + + and then use it as a service in your `homeManagerConfiguration`: + + ```nix + services.lastfmpris = { + enable = true; + settings = { + global = { + # player_bus = "org.mpris.MediaPlayer2.mpv"; + username = "ILoveLastDotFm"; + password = builtins.readFile /etc/lastfm-password; + api_key = builtins.readFile /etc/lastfm-api-key; + api_secret = builtins.readFile /etc/lastfm-api-secret; + } + }; + }; + ``` + 2. the normal way first, clone repository: diff --git a/config.example.ini b/config.example.ini index d262c6c..1a7f69c 100644 --- a/config.example.ini +++ b/config.example.ini @@ -1,3 +1,4 @@ +[global] ; player_bus = org.mpris.MediaPlayer2.mpv username = ILoveLastDotFm password = lastfm4lyfe diff --git a/flake.nix b/flake.nix index 3f14fd1..dec2c35 100644 --- a/flake.nix +++ b/flake.nix @@ -15,14 +15,15 @@ overlays = [rust-overlay.overlays.default]; }; package = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package; - rustPlatform = pkgs.makeRustPlatform { - cargo = pkgs.cargo; - rustc = pkgs.rustc; - }; toolchain = pkgs.rust-bin.fromRustupToolchainFile ./toolchain.toml; + rustPlatform = pkgs.makeRustPlatform { + cargo = toolchain; + rustc = toolchain; + }; in rec { - packages = flake-utils.lib.flattenTree { + packages = flake-utils.lib.flattenTree rec { + default = lastfmpris; lastfmpris = rustPlatform.buildRustPackage { pname = package.name; inherit (package) version; @@ -31,21 +32,21 @@ # very scuffed but endorsed! #cargoSha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; cargoSha256 = "sha256-KOMEvg3iGjmMEFxsrIqD4SaDw63ojiNNNqCfzRlbYLw="; + + nativeBuildInputs = with pkgs; [ pkg-config ]; - buildInputs = with pkgs; [ pkg-config ]; - - nativeBuildInputs = with pkgs; [ openssl dbus ]; + buildInputs = with pkgs; [ openssl dbus ]; src = ./.; + + meta.mainProgram = package.name; }; }; - defaultPackage = packages.lastfmpris; - devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ pkg-config ]; + nativeBuildInputs = with pkgs; [ pkg-config ]; - nativeBuildInputs = with pkgs; [ openssl dbus ]; + buildInputs = with pkgs; [ openssl dbus ]; packages = with pkgs; [ toolchain @@ -54,5 +55,53 @@ RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; }; - }); + }) // { + homeManagerModules = rec { + default = lastfmpris; + lastfmpris = { config, lib, pkgs, ... }: + with lib; + let + cfg = config.services.lastfmpris; + + iniFmt = pkgs.formats.ini {}; + in { + options.services.lastfmpris = { + enable = mkEnableOption "Enables the lastfmpris mpris scrobbling daemon"; + package = mkOption { + type = types.package; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; + }; + settings = mkOption { + type = iniFmt.type; + description = "Configuration (https://git.reidlab.pink/reidlab/lastfmpris/src/branch/main/config.example.ini)"; + example = literalExpression '' + { + global = { + username = "ILoveLastDotFm"; + password = "lastfm4lyfe"; + api_key = "t8mb4e0kn9it150amaeezbcfe3iusy8o"; + api_secret = "jd47iz6h1u2kbnbfm8c763lzrj1o89h3"; + }; + } + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.lastfmpris = { + Unit = { + Description = "a rust application to scrobble your currently playing song on last.fm with mpris"; + Requires = ["graphical-session.target"]; + }; + Service = { + Type = "simple"; + ExecStart = "${lib.getExe cfg.package}"; + }; + }; + + xdg.configFile."lastfmpris/config.ini".source = (iniFmt.generate "config.ini" cfg.settings); + }; + }; + }; + }; } diff --git a/src/config.rs b/src/config.rs index c056979..db7bed6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,8 +6,15 @@ use std::io::Write; use std::process; use tracing::info; +// okay i don't like this. +// we have to please the ini parser though!! #[derive(Deserialize)] pub struct Config { + pub global: GlobalConfig +} + +#[derive(Deserialize)] +pub struct GlobalConfig { pub player_bus: Option, pub username: String, pub password: String, diff --git a/src/lastfm.rs b/src/lastfm.rs index 3361d43..0e009ad 100644 --- a/src/lastfm.rs +++ b/src/lastfm.rs @@ -4,9 +4,9 @@ use rustfm_scrobble_proxy::Scrobbler; use tracing::info; pub fn get_scrobbler(config: &Config) -> Result { - let mut scrobbler = Scrobbler::new(&config.api_key, &config.api_secret); + let mut scrobbler = Scrobbler::new(&config.global.api_key, &config.global.api_secret); scrobbler - .authenticate_with_password(&config.username, &config.password) + .authenticate_with_password(&config.global.username, &config.global.password) .context("failed to authenticate")?; info!(" successfully authenticated"); diff --git a/src/player.rs b/src/player.rs index 7cff068..4ee1f6b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -15,9 +15,9 @@ pub fn is_active(player: &Player) -> bool { } pub fn is_whitelisted(config: &Config, player: &Player) -> bool { - if Some(player.bus_name()) == config.player_bus.as_deref() { + if Some(player.bus_name()) == config.global.player_bus.as_deref() { return true - } else if config.player_bus.is_none() { + } else if config.global.player_bus.is_none() { return player.bus_name().starts_with(MPRIS_BUS_PREFIX) } else { return false