Skip to content

Commit

Permalink
Add command scrobble_url for scrobbling from Last.fm album URL
Browse files Browse the repository at this point in the history
  • Loading branch information
theirix committed Sep 13, 2023
1 parent 41f04be commit c556828
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ structopt = { version = "0.3.26", features = ["color"] }
thiserror = "1.0.43"
time = { version = "0.3.23", features = ["macros", "formatting", "local-offset"] }
toml = "0.7.6"
urlencoding = "2.1.2"
url = "2.4.1"
urlencoding = "2.1.3"
xmltree = "0.10.3"

[target.'cfg(all(unix, target_env = "musl"))'.dependencies]
Expand Down
19 changes: 18 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod scrobbler;
mod utils;

use crate::auth::authenticate;
use crate::scrobbler::{scrobble_album, scrobble_track};
use crate::scrobbler::{scrobble_album, scrobble_track, scrobble_url};
use anyhow::Context;
use env_logger::Env;
use log::{error, info};
Expand Down Expand Up @@ -35,6 +35,20 @@ enum CliArgs {
start: Option<String>,
},

ScrobbleUrl {
/// Last.fm album page URL
#[structopt(long)]
url: String,

/// Dry run mode (no writes done)
#[structopt(short, long)]
dryrun: bool,

/// Start time
#[structopt(long)]
start: Option<String>,
},

Auth {
/// API key
#[structopt(long)]
Expand Down Expand Up @@ -85,6 +99,9 @@ fn run(cli_args: CliArgs) -> anyhow::Result<()> {
CliArgs::Scrobble { .. } => {
anyhow::bail!("Wrong arguments");
}
CliArgs::ScrobbleUrl { url, dryrun, start } => {
scrobble_url(url, dryrun, start_to_duration(start)?)
}
}
}

Expand Down
33 changes: 32 additions & 1 deletion src/scrobbler.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::auth::load_auth_config;
use crate::lastfmapi::{Album, ApiError, LastfmApi, LastfmApiBuilder};
use crate::utils::now_local;
use anyhow::anyhow;
use anyhow::{anyhow, Context};
use log::{debug, info, warn};
use time::ext::NumericalDuration;
use time::macros::format_description;
use time::Duration;
use url::Url;

/// Scrobble all tracks in an album with proper timestamps
fn scrobble_timeline(
Expand Down Expand Up @@ -105,3 +106,33 @@ pub fn scrobble_track(
Err(e) => Err(e.into()),
}
}

/// Scrobble a whole album identified by Last.fm webpage URL
pub fn scrobble_url(
url: String,
dryrun: bool,
start: Option<Duration>,
) -> Result<(), anyhow::Error> {
let expected_format = "https://www.last.fm/music/Artist/Album+Name";

let parsed_url = Url::parse(&url)?;
debug!("Parsed url to: {:?}", &parsed_url);

let path = &parsed_url
.path_segments()
.context("Cannot parse path")?
.collect::<Vec<&str>>();
if !(parsed_url.host_str() == Some("last.fm") || parsed_url.host_str() == Some("www.last.fm")) {
anyhow::bail!("URL is not from last.fm");
}
if path.len() < 3 || path[0] != "music" {
anyhow::bail!("URL must be in format {}", expected_format);
}
// Additionally replace plus (not %20) with space
let artist = urlencoding::decode(path[1])?.replace('+', " ");
let album = urlencoding::decode(path[2])?.replace('+', " ");

info!("Extracted artist {} and album {}", &artist, &album);

scrobble_album(artist, album, dryrun, start)
}

0 comments on commit c556828

Please sign in to comment.