mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Follow client setting to filter explicit tracks
- Don't load explicit tracks when the client setting forbids them - When a client switches explicit filtering on *while* playing an explicit track, immediately skip to the next track
This commit is contained in:
parent
2af34fc674
commit
0fdff0d3fd
5 changed files with 63 additions and 0 deletions
|
@ -746,12 +746,17 @@ impl SpircTask {
|
||||||
_ => old_value,
|
_ => old_value,
|
||||||
};
|
};
|
||||||
self.session.set_user_attribute(key, new_value);
|
self.session.set_user_attribute(key, new_value);
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"Received attribute mutation, {} was {} is now {}",
|
"Received attribute mutation, {} was {} is now {}",
|
||||||
key,
|
key,
|
||||||
old_value,
|
old_value,
|
||||||
new_value
|
new_value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if key == "filter-explicit-content" && new_value == "1" {
|
||||||
|
self.player.skip_explicit_content();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!(
|
trace!(
|
||||||
"Received attribute mutation for {} but key was not found!",
|
"Received attribute mutation for {} but key was not found!",
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub struct AudioItem {
|
||||||
pub duration: i32,
|
pub duration: i32,
|
||||||
pub availability: AudioItemAvailability,
|
pub availability: AudioItemAvailability,
|
||||||
pub alternatives: Option<Tracks>,
|
pub alternatives: Option<Tracks>,
|
||||||
|
pub is_explicit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AudioItem {
|
impl AudioItem {
|
||||||
|
|
|
@ -80,6 +80,7 @@ impl InnerAudioItem for Episode {
|
||||||
duration: episode.duration,
|
duration: episode.duration,
|
||||||
availability,
|
availability,
|
||||||
alternatives: None,
|
alternatives: None,
|
||||||
|
is_explicit: episode.is_explicit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ impl InnerAudioItem for Track {
|
||||||
duration: track.duration,
|
duration: track.duration,
|
||||||
availability,
|
availability,
|
||||||
alternatives,
|
alternatives,
|
||||||
|
is_explicit: track.is_explicit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ enum PlayerCommand {
|
||||||
SetSinkEventCallback(Option<SinkEventCallback>),
|
SetSinkEventCallback(Option<SinkEventCallback>),
|
||||||
EmitVolumeSetEvent(u16),
|
EmitVolumeSetEvent(u16),
|
||||||
SetAutoNormaliseAsAlbum(bool),
|
SetAutoNormaliseAsAlbum(bool),
|
||||||
|
SkipExplicitContent(),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -456,6 +457,10 @@ impl Player {
|
||||||
pub fn set_auto_normalise_as_album(&self, setting: bool) {
|
pub fn set_auto_normalise_as_album(&self, setting: bool) {
|
||||||
self.command(PlayerCommand::SetAutoNormaliseAsAlbum(setting));
|
self.command(PlayerCommand::SetAutoNormaliseAsAlbum(setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_explicit_content(&self) {
|
||||||
|
self.command(PlayerCommand::SkipExplicitContent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Player {
|
impl Drop for Player {
|
||||||
|
@ -478,6 +483,7 @@ struct PlayerLoadedTrackData {
|
||||||
bytes_per_second: usize,
|
bytes_per_second: usize,
|
||||||
duration_ms: u32,
|
duration_ms: u32,
|
||||||
stream_position_pcm: u64,
|
stream_position_pcm: u64,
|
||||||
|
is_explicit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PlayerPreload {
|
enum PlayerPreload {
|
||||||
|
@ -513,6 +519,7 @@ enum PlayerState {
|
||||||
duration_ms: u32,
|
duration_ms: u32,
|
||||||
stream_position_pcm: u64,
|
stream_position_pcm: u64,
|
||||||
suggested_to_preload_next_track: bool,
|
suggested_to_preload_next_track: bool,
|
||||||
|
is_explicit: bool,
|
||||||
},
|
},
|
||||||
Playing {
|
Playing {
|
||||||
track_id: SpotifyId,
|
track_id: SpotifyId,
|
||||||
|
@ -526,6 +533,7 @@ enum PlayerState {
|
||||||
stream_position_pcm: u64,
|
stream_position_pcm: u64,
|
||||||
reported_nominal_start_time: Option<Instant>,
|
reported_nominal_start_time: Option<Instant>,
|
||||||
suggested_to_preload_next_track: bool,
|
suggested_to_preload_next_track: bool,
|
||||||
|
is_explicit: bool,
|
||||||
},
|
},
|
||||||
EndOfTrack {
|
EndOfTrack {
|
||||||
track_id: SpotifyId,
|
track_id: SpotifyId,
|
||||||
|
@ -608,6 +616,7 @@ impl PlayerState {
|
||||||
normalisation_data,
|
normalisation_data,
|
||||||
stream_loader_controller,
|
stream_loader_controller,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
|
is_explicit,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*self = EndOfTrack {
|
*self = EndOfTrack {
|
||||||
|
@ -620,6 +629,7 @@ impl PlayerState {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
duration_ms,
|
duration_ms,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
|
is_explicit,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -648,6 +658,7 @@ impl PlayerState {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
suggested_to_preload_next_track,
|
suggested_to_preload_next_track,
|
||||||
|
is_explicit,
|
||||||
} => {
|
} => {
|
||||||
*self = Playing {
|
*self = Playing {
|
||||||
track_id,
|
track_id,
|
||||||
|
@ -661,6 +672,7 @@ impl PlayerState {
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
reported_nominal_start_time: None,
|
reported_nominal_start_time: None,
|
||||||
suggested_to_preload_next_track,
|
suggested_to_preload_next_track,
|
||||||
|
is_explicit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -689,6 +701,7 @@ impl PlayerState {
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
reported_nominal_start_time: _,
|
reported_nominal_start_time: _,
|
||||||
suggested_to_preload_next_track,
|
suggested_to_preload_next_track,
|
||||||
|
is_explicit,
|
||||||
} => {
|
} => {
|
||||||
*self = Paused {
|
*self = Paused {
|
||||||
track_id,
|
track_id,
|
||||||
|
@ -701,6 +714,7 @@ impl PlayerState {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
suggested_to_preload_next_track,
|
suggested_to_preload_next_track,
|
||||||
|
is_explicit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -778,6 +792,16 @@ impl PlayerTrackLoader {
|
||||||
audio.name, audio.spotify_uri
|
audio.name, audio.spotify_uri
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let is_explicit = audio.is_explicit;
|
||||||
|
if is_explicit {
|
||||||
|
if let Some(value) = self.session.get_user_attribute("filter-explicit-content") {
|
||||||
|
if &value == "1" {
|
||||||
|
warn!("Track is marked as explicit, which client setting forbids.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let audio = match self.find_available_alternative(audio).await {
|
let audio = match self.find_available_alternative(audio).await {
|
||||||
Some(audio) => audio,
|
Some(audio) => audio,
|
||||||
None => {
|
None => {
|
||||||
|
@ -951,6 +975,7 @@ impl PlayerTrackLoader {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
duration_ms,
|
duration_ms,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
|
is_explicit,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1518,6 +1543,7 @@ impl PlayerInternal {
|
||||||
Instant::now() - Duration::from_millis(position_ms as u64),
|
Instant::now() - Duration::from_millis(position_ms as u64),
|
||||||
),
|
),
|
||||||
suggested_to_preload_next_track: false,
|
suggested_to_preload_next_track: false,
|
||||||
|
is_explicit: loaded_track.is_explicit,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
self.ensure_sink_stopped(false);
|
self.ensure_sink_stopped(false);
|
||||||
|
@ -1533,6 +1559,7 @@ impl PlayerInternal {
|
||||||
bytes_per_second: loaded_track.bytes_per_second,
|
bytes_per_second: loaded_track.bytes_per_second,
|
||||||
stream_position_pcm: loaded_track.stream_position_pcm,
|
stream_position_pcm: loaded_track.stream_position_pcm,
|
||||||
suggested_to_preload_next_track: false,
|
suggested_to_preload_next_track: false,
|
||||||
|
is_explicit: loaded_track.is_explicit,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.send_event(PlayerEvent::Paused {
|
self.send_event(PlayerEvent::Paused {
|
||||||
|
@ -1674,6 +1701,7 @@ impl PlayerInternal {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
duration_ms,
|
duration_ms,
|
||||||
normalisation_data,
|
normalisation_data,
|
||||||
|
is_explicit,
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
| PlayerState::Paused {
|
| PlayerState::Paused {
|
||||||
|
@ -1683,6 +1711,7 @@ impl PlayerInternal {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
duration_ms,
|
duration_ms,
|
||||||
normalisation_data,
|
normalisation_data,
|
||||||
|
is_explicit,
|
||||||
..
|
..
|
||||||
} = old_state
|
} = old_state
|
||||||
{
|
{
|
||||||
|
@ -1693,6 +1722,7 @@ impl PlayerInternal {
|
||||||
bytes_per_second,
|
bytes_per_second,
|
||||||
duration_ms,
|
duration_ms,
|
||||||
stream_position_pcm,
|
stream_position_pcm,
|
||||||
|
is_explicit,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.preload = PlayerPreload::None;
|
self.preload = PlayerPreload::None;
|
||||||
|
@ -1943,6 +1973,30 @@ impl PlayerInternal {
|
||||||
PlayerCommand::SetAutoNormaliseAsAlbum(setting) => {
|
PlayerCommand::SetAutoNormaliseAsAlbum(setting) => {
|
||||||
self.auto_normalise_as_album = setting
|
self.auto_normalise_as_album = setting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerCommand::SkipExplicitContent() => {
|
||||||
|
if let PlayerState::Playing {
|
||||||
|
track_id,
|
||||||
|
play_request_id,
|
||||||
|
is_explicit,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
| PlayerState::Paused {
|
||||||
|
track_id,
|
||||||
|
play_request_id,
|
||||||
|
is_explicit,
|
||||||
|
..
|
||||||
|
} = self.state
|
||||||
|
{
|
||||||
|
if is_explicit {
|
||||||
|
warn!("Currently loaded track is explicit, which client setting forbids -- skipping to next track.");
|
||||||
|
self.send_event(PlayerEvent::EndOfTrack {
|
||||||
|
track_id,
|
||||||
|
play_request_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -2080,6 +2134,7 @@ impl fmt::Debug for PlayerCommand {
|
||||||
.debug_tuple("SetAutoNormaliseAsAlbum")
|
.debug_tuple("SetAutoNormaliseAsAlbum")
|
||||||
.field(&setting)
|
.field(&setting)
|
||||||
.finish(),
|
.finish(),
|
||||||
|
PlayerCommand::SkipExplicitContent() => f.debug_tuple("SkipExplicitContent").finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue