Skip to content

Commit

Permalink
feat: A shallow integration of the scrobbling API
Browse files Browse the repository at this point in the history
  • Loading branch information
Losses committed Dec 19, 2024
1 parent c6bcd4d commit d8b0db2
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions native/hub/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ lyric = { path = "../../lyric" }
database = { path = "../../database" }
analysis = { path = "../../analysis" }
playback = { path = "../../playback" }
scrobbling = { path = "../../scrobbling" }
lazy_static = "1.5.0"
dunce = "1.0.4"
log = "0.4.22"
Expand Down
11 changes: 10 additions & 1 deletion native/hub/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod system;
mod utils;

use std::sync::Arc;
use std::time::Duration;

use anyhow::Context;
use license::validate_license_request;
Expand All @@ -35,6 +36,7 @@ pub use tokio;

use ::playback::player::Player;
use ::playback::sfx_player::SfxPlayer;
use ::scrobbling::manager::ScrobblingManager;

use crate::analyze::*;
use crate::collection::*;
Expand Down Expand Up @@ -121,13 +123,20 @@ async fn player_loop(path: String, db_connections: DatabaseConnections) {
let player = Player::new(Some(main_cancel_token.clone()));
let player = Arc::new(Mutex::new(player));

let scrobbler = ScrobblingManager::new(10, Duration::new(5, 0));
let scrobbler = Arc::new(Mutex::new(scrobbler));

let sfx_player = SfxPlayer::new(Some(main_cancel_token.clone()));
let sfx_player = Arc::new(Mutex::new(sfx_player));

let main_cancel_token = Arc::new(main_cancel_token);

info!("Initializing Player events");
tokio::spawn(initialize_player(main_db.clone(), player.clone()));
tokio::spawn(initialize_player(
main_db.clone(),
player.clone(),
scrobbler.clone(),
));

info!("Initializing UI events");
select_signal!(
Expand Down
57 changes: 54 additions & 3 deletions native/hub/src/player.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

use anyhow::{bail, Error};
use anyhow::{Context, Result};
Expand All @@ -22,12 +23,33 @@ use playback::player::{Player, PlayingItem};
use playback::MediaMetadata;
use playback::MediaPlayback;
use playback::MediaPosition;
use scrobbling::manager::ScrobblingManager;
use scrobbling::ScrobblingTrack;

use crate::{CrashResponse, PlaybackStatus, PlaylistItem, PlaylistUpdate, RealtimeFft};

pub fn metadata_summary_to_scrobbling_track(
metadata: PlayingItemMetadataSummary,
) -> ScrobblingTrack {
ScrobblingTrack {
artist: metadata.artist,
album: Some(metadata.album),
track: metadata.title,
duration: Some(metadata.duration.clamp(0.0, u32::MAX as f64) as u32),
album_artist: None,
timestamp: Some(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
),
}
}

pub async fn initialize_player(
main_db: Arc<MainDbConnection>,
player: Arc<Mutex<Player>>,
scrobbler: Arc<Mutex<ScrobblingManager>>,
) -> Result<()> {
let status_receiver = player.lock().await.subscribe_status();
let played_through_receiver = player.lock().await.subscribe_played_through();
Expand All @@ -43,7 +65,8 @@ pub async fn initialize_player(
let manager = Arc::new(Mutex::new(MediaControlManager::new()?));

let os_controller_receiver = manager.lock().await.subscribe_controller_events();
let dispatcher = PlayingItemActionDispatcher::new();
let dispatcher = Arc::new(Mutex::new(PlayingItemActionDispatcher::new()));
let dispatcher_for_played_through = Arc::clone(&dispatcher);

manager.lock().await.initialize()?;

Expand All @@ -68,7 +91,12 @@ pub async fn initialize_player(
let item_vec = &[item_clone].to_vec();

// Update the cached metadata if the index has changed
let cover_art = match dispatcher.bake_cover_art(&main_db, item_vec).await {
let cover_art = match dispatcher
.lock()
.await
.bake_cover_art(&main_db, item_vec)
.await
{
Ok(data) => {
let parsed_data = data.values().collect::<Vec<_>>();
cached_cover_art = if parsed_data.is_empty() {
Expand All @@ -82,7 +110,12 @@ pub async fn initialize_player(
Err(_) => None,
};

match dispatcher.get_metadata_summary(&main_db, item_vec).await {
match dispatcher
.lock()
.await
.get_metadata_summary(&main_db, item_vec)
.await
{
Ok(metadata) => match metadata.first() {
Some(metadata) => {
cached_meta = Some(metadata.clone());
Expand Down Expand Up @@ -181,6 +214,7 @@ pub async fn initialize_player(

task::spawn(async move {
let main_db = Arc::clone(&main_db_for_played_throudh);
let dispatcher = Arc::clone(&dispatcher_for_played_through);

while let Ok(item) = played_through_receiver.recv().await {
match item {
Expand All @@ -195,6 +229,23 @@ pub async fn initialize_player(
PlayingItem::IndependentFile(_) => {}
PlayingItem::Unknown => {}
}

let metadata = dispatcher
.lock()
.await
.get_metadata_summary(&main_db, [item].as_ref())
.await;

if let Ok(metadata) = metadata {
if metadata.is_empty() {
continue;
}

let metadata: PlayingItemMetadataSummary = metadata[0].clone();
let track: ScrobblingTrack = metadata_summary_to_scrobbling_track(metadata);

scrobbler.lock().await.scrobble_all(&track).await;
}
}
});

Expand Down

0 comments on commit d8b0db2

Please sign in to comment.