Make SpotifyId understand more URI formats

This commit is contained in:
ashthespy 2019-10-09 19:49:13 +02:00
parent 6786c093ad
commit b96405af82
3 changed files with 42 additions and 19 deletions

View file

@ -13,14 +13,14 @@ use context::StationContext;
use librespot_core::config::ConnectConfig; use librespot_core::config::ConnectConfig;
use librespot_core::mercury::MercuryError; use librespot_core::mercury::MercuryError;
use librespot_core::session::Session; use librespot_core::session::Session;
use librespot_core::spotify_id::SpotifyId; use librespot_core::spotify_id::{SpotifyId, SpotifyIdError};
use librespot_core::util::SeqGenerator; use librespot_core::util::SeqGenerator;
use librespot_core::version; use librespot_core::version;
use librespot_core::volume::Volume; use librespot_core::volume::Volume;
use playback::mixer::Mixer; use playback::mixer::Mixer;
use playback::player::Player; use playback::player::Player;
use protocol; use protocol;
use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State}; use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef};
pub struct SpircTask { pub struct SpircTask {
player: Player, player: Player,
@ -797,7 +797,7 @@ impl SpircTask {
} }
fn update_tracks(&mut self, frame: &protocol::spirc::Frame) { fn update_tracks(&mut self, frame: &protocol::spirc::Frame) {
// debug!("State: {:?}", frame.get_state()); debug!("State: {:?}", frame.get_state());
let index = frame.get_state().get_playing_track_index(); let index = frame.get_state().get_playing_track_index();
let context_uri = frame.get_state().get_context_uri().to_owned(); let context_uri = frame.get_state().get_context_uri().to_owned();
let tracks = frame.get_state().get_track(); let tracks = frame.get_state().get_track();
@ -813,31 +813,43 @@ impl SpircTask {
self.state.set_shuffle(frame.get_state().get_shuffle()); self.state.set_shuffle(frame.get_state().get_shuffle());
} }
// should this be a method of SpotifyId directly?
fn get_spotify_id_for_track(&self, track_ref: &TrackRef) -> Result<SpotifyId, SpotifyIdError> {
SpotifyId::from_raw(track_ref.get_gid()).or_else(|_| {
let uri = track_ref.get_uri();
debug!("Malformed or no gid, attempting to parse URI <{}>", uri);
SpotifyId::from_uri(uri)
})
}
fn load_track(&mut self, play: bool) { fn load_track(&mut self, play: bool) {
let context_uri = self.state.get_context_uri().to_owned(); let context_uri = self.state.get_context_uri().to_owned();
let index = self.state.get_playing_track_index();
info!("context: {}", context_uri);
// Redundant check here
let track = if context_uri.contains(":show:") || context_uri.contains(":episode:") {
let uri = self.state.get_track()[index as usize].get_uri();
SpotifyId::from_uri(uri).expect("Unable to parse uri")
} else {
let mut index = self.state.get_playing_track_index(); let mut index = self.state.get_playing_track_index();
// Check for malformed gid
let tracks_len = self.state.get_track().len() as u32; let tracks_len = self.state.get_track().len() as u32;
debug!(
"Loading context: {} index: [{}] of {}",
context_uri, index, tracks_len
);
// Tracks either have a gid or uri.
// Context based frames sometimes use spotify:meta:page: that needs to be ignored.
let track = {
let mut track_ref = &self.state.get_track()[index as usize]; let mut track_ref = &self.state.get_track()[index as usize];
while track_ref.get_gid().len() != 16 { let mut track_id = self.get_spotify_id_for_track(track_ref);
while track_id.is_err() {
warn!( warn!(
"Skipping track {:?} at position [{}] of {}", "Skipping track {:?} at position [{}] of {}",
track_ref.get_uri(), track_ref.get_uri(),
index, index,
tracks_len tracks_len
); );
// This will keep looping over, instead we should cylce tracks only once
index = if index + 1 < tracks_len { index + 1 } else { 0 }; index = if index + 1 < tracks_len { index + 1 } else { 0 };
track_ref = &self.state.get_track()[index as usize]; track_ref = &self.state.get_track()[index as usize];
track_id = self.get_spotify_id_for_track(track_ref);
} }
SpotifyId::from_raw(track_ref.get_gid()).unwrap() track_id
}; }
.unwrap();
let position = self.state.get_position_ms(); let position = self.state.get_position_ms();
let end_of_track = self.player.load(track, play, position); let end_of_track = self.player.load(track, play, position);

View file

@ -5,6 +5,7 @@ use std::fmt;
pub enum SpotifyAudioType { pub enum SpotifyAudioType {
Track, Track,
Podcast, Podcast,
NonPlayable,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -71,12 +72,18 @@ impl SpotifyId {
pub fn from_uri(uri: &str) -> Result<SpotifyId, SpotifyIdError> { pub fn from_uri(uri: &str) -> Result<SpotifyId, SpotifyIdError> {
let parts = uri.split(":").collect::<Vec<&str>>(); let parts = uri.split(":").collect::<Vec<&str>>();
if uri.contains(":show:") || uri.contains(":episode:") { let gid = parts.last().unwrap();
let mut spotify_id = SpotifyId::from_base62(parts[2]).unwrap(); if uri.contains(":episode:") {
let mut spotify_id = SpotifyId::from_base62(gid).unwrap();
let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::Podcast); let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::Podcast);
Ok(spotify_id) Ok(spotify_id)
} else if uri.contains(":track:") {
SpotifyId::from_base62(gid)
} else { } else {
SpotifyId::from_base62(parts[2]) // show/playlist/artist/album/??
let mut spotify_id = SpotifyId::from_base62(gid).unwrap();
let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::NonPlayable);
Ok(spotify_id)
} }
} }

View file

@ -8,6 +8,7 @@ extern crate librespot_protocol as protocol;
pub mod cover; pub mod cover;
use futures::future;
use futures::Future; use futures::Future;
use linear_map::LinearMap; use linear_map::LinearMap;
@ -71,6 +72,9 @@ impl AudioItem {
match id.audio_type { match id.audio_type {
SpotifyAudioType::Track => Track::get_audio_item(session, id), SpotifyAudioType::Track => Track::get_audio_item(session, id),
SpotifyAudioType::Podcast => Episode::get_audio_item(session, id), SpotifyAudioType::Podcast => Episode::get_audio_item(session, id),
SpotifyAudioType::NonPlayable => {
Box::new(future::err::<AudioItem, MercuryError>(MercuryError))
}
} }
} }
} }