Last active
October 17, 2023 14:58
-
-
Save djanatyn/b3cab1d0dfb597fd1461566cd7f1db23 to your computer and use it in GitHub Desktop.
fixing scrobbles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! https://github.com/Rockbox/rockbox/blob/3c89adbdbdd036baf313786b0694632c8e7e2bb3/apps/plugins/lastfm_scrobbler.c#L29 | |
use chrono::{DateTime, TimeZone, Utc}; | |
use nom::{ | |
bytes::complete::take_until, character::complete::char, multi::count, sequence::terminated, | |
IResult, | |
}; | |
fn main() -> std::io::Result<()> { | |
let log = std::fs::read_to_string("scrobbler.log")?; | |
let scrobbles: Vec<Scrobble> = log | |
.lines() | |
.skip(3) | |
.map(|i| { | |
let (_, scrobble) = parse_scrobble(dbg!(i)).unwrap(); | |
scrobble | |
}) | |
.collect(); | |
Ok(println!("{scrobbles:#?}")) | |
} | |
#[derive(Debug)] | |
enum Rating { | |
Listened, | |
Skipped, | |
} | |
#[derive(Debug)] | |
struct Scrobble { | |
artist: String, | |
album: String, | |
track: String, | |
track_position: Option<u32>, // TODO: Option<u32> | |
song_duration: u32, // seconds | |
rating: Rating, | |
timestamp: DateTime<Utc>, | |
} | |
fn parse_scrobble_token(input: &str) -> IResult<&str, &str> { | |
terminated(take_until("\t"), char('\t'))(input) | |
} | |
fn parse_scrobble(input: &str) -> IResult<&str, Scrobble> { | |
let (rest, tokens) = count(parse_scrobble_token, 7)(input)?; | |
Ok(( | |
rest, | |
Scrobble { | |
artist: tokens[0].to_string(), | |
album: tokens[1].to_string(), | |
track: tokens[2].to_string(), | |
track_position: match tokens[3] { | |
"" => None, | |
pos => Some(pos.parse::<u32>().expect("failed to parse track position")), | |
}, | |
song_duration: tokens[4] | |
.parse::<u32>() | |
.expect("failed to parse song duration"), | |
rating: match tokens[5] { | |
"S" => Rating::Skipped, | |
"L" => Rating::Listened, | |
_ => panic!("failed to parse rating"), | |
}, | |
timestamp: chrono::Utc.timestamp( | |
tokens[6].parse::<i64>().expect("failed to parse timestamp"), | |
0, | |
), | |
}, | |
)) | |
} | |
const HEADER: &str = r#" | |
#AUDIOSCROBBLER/1.1 | |
#TZ/UNKNOWN | |
#CLIENT/Rockbox ipodvideo $Revision$ | |
"#; | |
#[test] | |
fn parse_line() -> std::io::Result<()> { | |
let log = std::fs::read_to_string("scrobbler.log")?; | |
let scrobbles: Vec<Scrobble> = log | |
.lines() | |
.skip(3) | |
.map(|i| { | |
let (_, scrobble) = parse_scrobble(dbg!(i)).unwrap(); | |
scrobble | |
}) | |
.collect(); | |
dbg!(scrobbles); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment