From aa0f2201e4625b44db0679251ba0ee9aa5f90c51 Mon Sep 17 00:00:00 2001 From: "Reid \"reidlab" Date: Tue, 27 Aug 2024 17:12:01 -0700 Subject: [PATCH 1/2] .env pwd configuration to ini xdg configuration --- .env.example | 5 -- Cargo.lock | 211 ++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 5 +- README.md | 2 +- config.example.ini | 5 ++ flake.nix | 2 +- src/config.rs | 58 ++++++++++--- src/main.rs | 7 +- 8 files changed, 229 insertions(+), 66 deletions(-) delete mode 100644 .env.example create mode 100644 config.example.ini diff --git a/.env.example b/.env.example deleted file mode 100644 index fc88e23..0000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -#PLAYER_BUS="org.mpris.MediaPlayer2.mpv" -USERNAME="ILoveLastDotFm" -PASSWORD="lastfm4lyfe" -API_KEY="t8mb4e0kn9it150amaeezbcfe3iusy8o" -API_SECRET="jd47iz6h1u2kbnbfm8c763lzrj1o89h3" diff --git a/Cargo.lock b/Cargo.lock index 03b5af1..64556b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,10 +136,25 @@ dependencies = [ ] [[package]] -name = "dotenvy" -version = "0.15.7" +name = "dirs" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] [[package]] name = "enum-kinds" @@ -152,26 +167,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "envconfig" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea81cc7e21f55a9d9b1efb6816904978d0bfbe31a50347cb24b2e75564bcac9b" -dependencies = [ - "envconfig_derive", -] - -[[package]] -name = "envconfig_derive" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfca278e5f84b45519acaaff758ebfa01f18e96998bc24b8f1b722dd804b9bf" -dependencies = [ - "proc-macro2", - "quote 1.0.36", - "syn 1.0.109", -] - [[package]] name = "errno" version = "0.3.9" @@ -179,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -249,6 +244,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "heck" version = "0.3.3" @@ -296,10 +302,11 @@ name = "lastfmpris" version = "0.1.0" dependencies = [ "anyhow", - "dotenvy", - "envconfig", + "dirs", "mpris", "rustfm-scrobble-proxy", + "serde", + "serde_ini", "tracing", "tracing-subscriber", ] @@ -325,6 +332,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -448,6 +465,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" @@ -496,6 +519,23 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "result" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560" + [[package]] name = "rustfm-scrobble-proxy" version = "2.0.0" @@ -519,7 +559,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -534,7 +574,7 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -562,24 +602,35 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote 1.0.36", "syn 2.0.72", ] +[[package]] +name = "serde_ini" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb236687e2bb073a7521c021949be944641e671b8505a94069ca37b656c81139" +dependencies = [ + "result", + "serde", + "void", +] + [[package]] name = "serde_json" version = "1.0.122" @@ -677,7 +728,7 @@ dependencies = [ "fastrand", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -838,6 +889,18 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" @@ -860,13 +923,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -875,28 +962,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -909,24 +1014,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index d8ca9f3..02f6db4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,10 @@ edition = "2021" [dependencies] anyhow = "1.0.86" -dotenvy = "0.15.7" -envconfig = "0.10.0" +dirs = "5.0.1" mpris = "2.0.1" rustfm-scrobble-proxy = "2.0.0" +serde = "1.0.209" +serde_ini = "0.2.0" tracing = "0.1.40" tracing-subscriber = "0.3.18" diff --git a/README.md b/README.md index c48b96c..4b36542 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ unfortunately, because of how most mpris players work, the [Track_Id](https://sp ## configuration -copy the values from `.env.example` into a `.env` file and configure your api keys, and the api keys are available [here](https://www.last.fm/login?next=/api/account/create) +either run the program once and navigate to `.config/lastmpris/config.ini` or create the file and copy it from the `config.example.ini` file provided in this directory. once you do that, configure your authentication methods. the api keys are available [here](https://www.last.fm/login?next=/api/account/create) you also have the option to define your mpris bus name, which will instead wait for your specified player instead of waiting for the first active player diff --git a/config.example.ini b/config.example.ini new file mode 100644 index 0000000..d262c6c --- /dev/null +++ b/config.example.ini @@ -0,0 +1,5 @@ +; player_bus = org.mpris.MediaPlayer2.mpv +username = ILoveLastDotFm +password = lastfm4lyfe +api_key = t8mb4e0kn9it150amaeezbcfe3iusy8o +api_secret = jd47iz6h1u2kbnbfm8c763lzrj1o89h3 diff --git a/flake.nix b/flake.nix index d7eaf09..3f14fd1 100644 --- a/flake.nix +++ b/flake.nix @@ -30,7 +30,7 @@ # uncomment this and let the build fail, then get the current hash # very scuffed but endorsed! #cargoSha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; - cargoSha256 = "sha256-2bDHxZc5Zg7jmA8BenSbTF3fBJEB7QDEVBQLkI8qyRc="; + cargoSha256 = "sha256-KOMEvg3iGjmMEFxsrIqD4SaDw63ojiNNNqCfzRlbYLw="; buildInputs = with pkgs; [ pkg-config ]; diff --git a/src/config.rs b/src/config.rs index 1af799b..c056979 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,19 +1,55 @@ -use envconfig::Envconfig; +use anyhow::{Context, Result}; +use serde::Deserialize; +use std::fs; +use std::fs::{create_dir_all, OpenOptions}; +use std::io::Write; +use std::process; +use tracing::info; -#[derive(Envconfig)] +#[derive(Deserialize)] pub struct Config { - #[envconfig(from = "PLAYER_BUS")] pub player_bus: Option, - - #[envconfig(from = "USERNAME")] pub username: String, - - #[envconfig(from = "PASSWORD")] pub password: String, - - #[envconfig(from = "API_KEY")] pub api_key: String, - - #[envconfig(from = "API_SECRET")] pub api_secret: String +} + +pub fn load_config() -> Result { + let path = dirs::config_dir() + .context("failed to get config directory")? + .join("lastfmpris") + .join("config.ini"); + + // create file if it doesnt exist and exit + if !path.exists() { + info!("configuration file doesn't exist, creating boilerplate"); + + // create underline paths and files + if let Some(parent) = path.parent() { + create_dir_all(parent) + .context("failed to create config file folder(s)")?; + } + let mut file = OpenOptions::new() + .write(true) + .create(true) + .open(&path) + .context("failed to create config file")?; + + // write into the config file with the example configuration + // we put inside the base working directory for the project + file.write_all(include_str!("../config.example.ini").as_bytes()) + .context("failed to write boilerplate config")?; + + info!("configuration boilerplate generation completed: see file: {}", path.display()); + // success, exit + process::exit(0) + } + + let content = fs::read_to_string(path) + .context("failed to read config content")?; + let config: Config = serde_ini::from_str(&content) + .context("failed to deserialize ini into a readable format")?; + + Ok(config) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6df96f8..033f331 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,11 @@ mod main_loop; mod player; mod track; -use crate::config::Config; use crate::lastfm::get_scrobbler; use anyhow::{Context, Result}; -use envconfig::Envconfig; use tracing::{debug, Level}; fn main() -> Result<()> { - dotenvy::dotenv()?; tracing_subscriber::fmt() .with_max_level(if cfg!(debug_assertions) { Level::DEBUG } else { Level::INFO }) .init(); @@ -24,8 +21,8 @@ fn main() -> Result<()> { env!("CARGO_PKG_DESCRIPTION") ); - let config = Config::init_from_env() - .context("failed to initiate configuration from .env")?; + let config = config::load_config() + .context("failed to initiate configuration object!")?; let scrobbler = get_scrobbler(&config) .context("failed to create scrobbler")?; From 4d2ee2d53a84a65716309a46a4d6a0659c1bf1da Mon Sep 17 00:00:00 2001 From: "Reid \"reidlab" Date: Tue, 27 Aug 2024 17:52:02 -0700 Subject: [PATCH 2/2] untested home-manager module --- README.md | 52 +++++++++++++++++++++++++++++++++++----------------- flake.nix | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4b36542..da0e424 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ a rust application to scrobble your currently playing song on last.fm with mpris 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. +also you can't configure the program through nix yet because i'm lazy, i'll do that sometime!! + ## configuration either run the program once and navigate to `.config/lastmpris/config.ini` or create the file and copy it from the `config.example.ini` file provided in this directory. once you do that, configure your authentication methods. the api keys are available [here](https://www.last.fm/login?next=/api/account/create) @@ -14,26 +16,42 @@ you also have the option to define your mpris bus name, which will instead wait ## how to install -*if you're on a setup that uses nix, you can just use `nix build` or the provided devshell to build the application.* +you have two methods of installation -first, clone repository: +1. install with cargo + your package manager of choice + + 1. obtain dependencies (this will vary on your package manager) + ```sh + sudo apk add install pkgconf openssl dbus + ``` + 2. run/build + ```sh + cargo build --release + ``` +2. install using nix -```sh -git clone https://git.reidlab.pink/reidlab/lastfmpris && cd lastfmpris -``` + simply run it with nix: -second, obtain dependencies (this will vary on your package manager, here, alpine is used) + ```sh + nix run git+https://git.reidlab.pink/reidlab/lastfmpris + ``` -```sh -sudo apk add install pkgconf openssl dbus -``` + or put it into your flake as such: -finally, run/build + ```nix + # add this into your flake inputs: + lastfmpris.url = "git+https://git.reidlab.pink/reidlab/lastfmpris"; + # add this to your `homeConfiguration`: + imports = [ + inputs.lastfmpris.nixosModules.lastfmpris + ]; + ``` -```sh -cargo run -``` - -```sh -cargo build --release -``` \ No newline at end of file + and then just add this to use it as a home-manager option: + + ```nix + # add this to your home-manager configuration: + services.lastfmpris = { + enable = true; + } + ``` \ No newline at end of file diff --git a/flake.nix b/flake.nix index 3f14fd1..2d8268f 100644 --- a/flake.nix +++ b/flake.nix @@ -54,5 +54,37 @@ RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; }; - }); + }) // { + homeManagerModules = { + lastfmpris = { config, lib, pkgs, ... }: + with lib; + let + cfg = config.services.lastfmpris; + in { + options.services.lastfmpris = { + enable = mkEnableOption "enables the lastmpris scrobbler"; + + package = mkOption { + type = types.package; + default = self.defaultPackage.${pkgs.system}; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + systemd.user.services.lastfmpris = { + Unit = { + Description = "Lastfmpris scrobbling daemon"; + After = [ "graphical-session-pre.target" ]; + }; + Service = { + Type = "Simple"; + ExecStart = "${lib.getExe cfg.package}"; + Restart = "on-failure"; + }; + }; + }; + }; + }; + }; }