Skip to content

Commit f3c46f1

Browse files
committed
Improve scrobble tracking and prevent duplicates
Replace previous_index with current_scrobble_track and a scrobbled_tracks HashSet. Monitor playback progress and spawn a scrobble when elapsed/length >= 40% (and length > 30s). Use cloned track IDs to avoid duplicate scrobbles and reset monitoring on track change or when no track is playing. Clean up ffi import grouping.
1 parent f5dac90 commit f3c46f1

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

crates/server/src/lib.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ use rockbox_sys::events::RockboxCommand;
1313
use rockbox_sys::{self as rb, types::mp3_entry::Mp3Entry};
1414
use sqlx::{Pool, Sqlite};
1515
use std::{
16-
collections::HashMap,
17-
ffi::c_char,
18-
ffi::c_int,
16+
collections::{HashMap, HashSet},
17+
ffi::{c_char, c_int},
1918
sync::{Arc, Mutex},
2019
thread,
2120
};
@@ -260,7 +259,9 @@ pub extern "C" fn start_broker() {
260259
.unwrap();
261260

262261
let mut metadata_cache: HashMap<String, Mp3Entry> = HashMap::new();
263-
let mut previous_index = -10; // Arbitrary value to ensure the first track is scobbled
262+
263+
let mut current_scrobble_track: Option<Track> = None; // The track we are monitoring for scrobble
264+
let mut scrobbled_tracks: HashSet<String> = HashSet::new(); // Simple unique ID to prevent duplicates (use track.id if available)
264265

265266
loop {
266267
let mutex = GLOBAL_MUTEX.lock().unwrap();
@@ -277,36 +278,66 @@ pub extern "C" fn start_broker() {
277278

278279
let playback_status: AudioStatus = rb::playback::status().into();
279280
SimpleBroker::publish(playback_status);
281+
280282
match rb::playback::current_track() {
281283
Some(current_track) => {
282284
let hash = format!("{:x}", md5::compute(current_track.path.as_bytes()));
283285
if let Ok(Some(metadata)) =
284286
rt.block_on(repo::track::find_by_md5(pool.clone(), &hash))
285287
{
286288
let mut track: Track = current_track.into();
287-
track.id = Some(metadata.id);
289+
track.id = Some(metadata.id.clone());
288290
track.album_art = metadata.album_art;
289291
track.album_id = Some(metadata.album_id);
290292
track.artist_id = Some(metadata.artist_id);
291293
SimpleBroker::publish(track.clone());
292294

293-
if previous_index != rb::playlist::index() {
294-
let cloned_pool = pool.clone();
295-
thread::spawn(move || {
296-
let rt = tokio::runtime::Builder::new_current_thread()
297-
.enable_all()
298-
.build()
299-
.unwrap();
300-
match rt.block_on(scrobble(track.clone(), cloned_pool.clone())) {
301-
Ok(_) => {}
302-
Err(e) => eprintln!("{}", e),
295+
let track_changed = if let Some(ref current) = current_scrobble_track {
296+
current.path != track.path
297+
} else {
298+
true
299+
};
300+
301+
if track_changed {
302+
current_scrobble_track = Some(track.clone());
303+
}
304+
305+
// Check progress for scrobbling (only if we have a track to monitor)
306+
if let Some(ref monitored_track) = current_scrobble_track {
307+
if monitored_track.path == track.path {
308+
let elapsed_ms = track.elapsed;
309+
let length_ms = track.length;
310+
311+
if length_ms > 30_000 && // optional: ignore very short tracks per Last.fm rules
312+
elapsed_ms as f64 / length_ms as f64 >= 0.40
313+
{
314+
if !scrobbled_tracks.contains(&metadata.id) {
315+
let cloned_pool = pool.clone();
316+
let cloned_track = monitored_track.clone();
317+
thread::spawn(move || {
318+
let rt = tokio::runtime::Builder::new_current_thread()
319+
.enable_all()
320+
.build()
321+
.unwrap();
322+
match rt
323+
.block_on(scrobble(cloned_track, cloned_pool.clone()))
324+
{
325+
Ok(_) => {}
326+
Err(e) => eprintln!("{}", e),
327+
}
328+
});
329+
scrobbled_tracks.insert(metadata.id.clone());
330+
}
331+
} else {
332+
scrobbled_tracks.clear();
303333
}
304-
});
334+
}
305335
}
306-
previous_index = rb::playlist::index();
307336
}
308337
}
309-
None => {}
338+
None => {
339+
current_scrobble_track = None; // reset on no track
340+
}
310341
};
311342

312343
let mut entries: Vec<Mp3Entry> = vec![];

0 commit comments

Comments
 (0)