Refactor: extract Spotify Worker to separate file

This commit is contained in:
Henrik Friedrichsen
2021-04-03 21:38:42 +02:00
parent 8b5bc64dc6
commit 8483653cde
8 changed files with 258 additions and 248 deletions

View File

@@ -64,6 +64,7 @@ mod sharing;
mod show;
mod spotify;
mod spotify_url;
mod spotify_worker;
mod theme;
mod track;
mod traits;

View File

@@ -19,7 +19,7 @@ use crate::playable::Playable;
use crate::playlist::Playlist;
use crate::queue::{Queue, RepeatSetting};
use crate::show::Show;
use crate::spotify::{PlayerEvent, Spotify, URIType, VOLUME_PERCENT};
use crate::spotify::{PlayerEvent, Spotify, UriType, VOLUME_PERCENT};
use crate::track::Track;
use crate::traits::ListItem;
use regex::Regex;
@@ -538,9 +538,9 @@ fn run_dbus_server(
None => "".to_string(),
};
let id = &uri[uri.rfind(':').unwrap_or(0) + 1..uri.len()];
let uri_type = URIType::from_uri(&uri);
let uri_type = UriType::from_uri(&uri);
match uri_type {
Some(URIType::Album) => {
Some(UriType::Album) => {
if let Some(a) = spotify.album(&id) {
if let Some(t) = &Album::from(&a).tracks {
queue.clear();
@@ -553,14 +553,14 @@ fn run_dbus_server(
}
}
}
Some(URIType::Track) => {
Some(UriType::Track) => {
if let Some(t) = spotify.track(&id) {
queue.clear();
queue.append(Playable::Track(Track::from(&t)));
queue.play(0, false, false)
}
}
Some(URIType::Playlist) => {
Some(UriType::Playlist) => {
if let Some(p) = spotify.playlist(&id) {
let mut playlist = Playlist::from(&p);
let spotify = spotify.clone();
@@ -576,7 +576,7 @@ fn run_dbus_server(
}
}
}
Some(URIType::Show) => {
Some(UriType::Show) => {
if let Some(s) = spotify.get_show(&id) {
let mut show = Show::from(&s);
let spotify = spotify.clone();
@@ -594,14 +594,14 @@ fn run_dbus_server(
}
}
}
Some(URIType::Episode) => {
Some(UriType::Episode) => {
if let Some(e) = spotify.episode(&id) {
queue.clear();
queue.append(Playable::Episode(Episode::from(&e)));
queue.play(0, false, false)
}
}
Some(URIType::Artist) => {
Some(UriType::Artist) => {
if let Some(a) = spotify.artist_top_tracks(&id) {
queue.clear();
queue.append_next(a.iter().map(|track| Playable::Track(track.clone())).collect());

View File

@@ -4,13 +4,11 @@ use librespot_core::config::SessionConfig;
use librespot_core::keymaster::Token;
use librespot_core::mercury::MercuryError;
use librespot_core::session::Session;
use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId};
use librespot_playback::config::PlayerConfig;
use librespot_playback::audio_backend;
use librespot_playback::config::Bitrate;
use librespot_playback::mixer::Mixer;
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
use librespot_playback::player::Player;
use rspotify::blocking::client::Spotify as SpotifyAPI;
use rspotify::model::album::{FullAlbum, SavedAlbum, SimplifiedAlbum};
@@ -28,23 +26,15 @@ use serde_json::{json, Map};
use failure::Error;
use futures_01::future::Future as v01_Future;
use futures_01::stream::Stream as v01_Stream;
use futures_01::sync::mpsc::UnboundedReceiver;
use futures_01::Async as v01_Async;
use futures::channel::mpsc;
use futures::channel::oneshot;
use futures::compat::Future01CompatExt;
use futures::compat::Stream01CompatExt;
use futures::task::Context;
use futures::Future;
use futures::Stream;
use tokio_core::reactor::Core;
use url::Url;
use core::task::Poll;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
@@ -56,6 +46,7 @@ use crate::artist::Artist;
use crate::config;
use crate::events::{Event, EventManager};
use crate::playable::Playable;
use crate::spotify_worker::{Worker, WorkerCommand};
use crate::track::Track;
use rspotify::model::recommend::Recommendations;
@@ -63,17 +54,6 @@ use rspotify::model::show::{FullEpisode, FullShow, Show, SimplifiedEpisode};
pub const VOLUME_PERCENT: u16 = ((u16::max_value() as f64) * 1.0 / 100.0) as u16;
enum WorkerCommand {
Load(Playable),
Play,
Pause,
Stop,
Seek(u32),
SetVolume(u16),
RequestToken(oneshot::Sender<Token>),
Shutdown,
}
#[derive(Clone, Debug, PartialEq)]
pub enum PlayerEvent {
Playing,
@@ -96,165 +76,6 @@ pub struct Spotify {
country: Option<Country>,
}
struct Worker {
events: EventManager,
player_events: UnboundedReceiver<LibrespotPlayerEvent>,
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
session: Session,
player: Player,
refresh_task: Pin<Box<dyn Stream<Item = Result<(), tokio_timer::Error>>>>,
token_task: Pin<Box<dyn Future<Output = Result<(), MercuryError>>>>,
active: bool,
mixer: Box<dyn Mixer>,
}
impl Worker {
fn new(
events: EventManager,
player_events: UnboundedReceiver<LibrespotPlayerEvent>,
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
session: Session,
player: Player,
mixer: Box<dyn Mixer>,
) -> Worker {
Worker {
events,
player_events,
commands,
player,
session,
refresh_task: Box::pin(futures::stream::empty()),
token_task: Box::pin(futures::future::pending()),
active: false,
mixer,
}
}
}
impl Worker {
fn create_refresh(&self) -> Pin<Box<dyn Stream<Item = Result<(), tokio_timer::Error>>>> {
let ev = self.events.clone();
let future =
tokio_timer::Interval::new_interval(Duration::from_millis(400)).map(move |_| {
ev.trigger();
});
Box::pin(future.compat())
}
}
impl futures::Future for Worker {
type Output = Result<(), ()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> futures::task::Poll<Self::Output> {
loop {
let mut progress = false;
if self.session.is_invalid() {
self.events.send(Event::Player(PlayerEvent::Stopped));
return Poll::Ready(Result::Err(()));
}
if let Poll::Ready(Some(cmd)) = self.commands.as_mut().poll_next(cx) {
progress = true;
debug!("message received!");
match cmd {
WorkerCommand::Load(playable) => match SpotifyId::from_uri(&playable.uri()) {
Ok(id) => {
info!("player loading track: {:?}", id);
if id.audio_type == SpotifyAudioType::NonPlayable {
warn!("track is not playable");
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
} else {
self.player.load(id, true, 0);
}
}
Err(e) => {
error!("error parsing uri: {:?}", e);
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
}
},
WorkerCommand::Play => {
self.player.play();
}
WorkerCommand::Pause => {
self.player.pause();
}
WorkerCommand::Stop => {
self.player.stop();
}
WorkerCommand::Seek(pos) => {
self.player.seek(pos);
}
WorkerCommand::SetVolume(volume) => {
self.mixer.set_volume(volume);
}
WorkerCommand::RequestToken(sender) => {
self.token_task = Spotify::get_token(&self.session, sender);
progress = true;
}
WorkerCommand::Shutdown => {
self.player.stop();
self.session.shutdown();
}
}
}
if let Ok(v01_Async::Ready(Some(event))) = self.player_events.poll() {
debug!("librespot player event: {:?}", event);
match event {
LibrespotPlayerEvent::Started { .. }
| LibrespotPlayerEvent::Loading { .. }
| LibrespotPlayerEvent::Changed { .. } => {
progress = true;
}
LibrespotPlayerEvent::Playing { .. } => {
self.events.send(Event::Player(PlayerEvent::Playing));
self.refresh_task = self.create_refresh();
self.active = true;
}
LibrespotPlayerEvent::Paused { .. } => {
self.events.send(Event::Player(PlayerEvent::Paused));
self.active = false;
}
LibrespotPlayerEvent::Stopped { .. } => {
self.events.send(Event::Player(PlayerEvent::Stopped));
self.active = false;
}
LibrespotPlayerEvent::EndOfTrack { .. } => {
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
progress = true;
}
_ => {}
}
}
if let Poll::Ready(Some(Ok(_))) = self.refresh_task.as_mut().poll_next(cx) {
self.refresh_task = if self.active {
progress = true;
self.create_refresh()
} else {
Box::pin(futures::stream::empty())
};
}
match self.token_task.as_mut().poll(cx) {
Poll::Ready(Ok(_)) => {
info!("token updated!");
self.token_task = Box::pin(futures::future::pending())
}
Poll::Ready(Err(e)) => {
error!("could not generate token: {:?}", e);
}
_ => (),
}
if !progress {
return Poll::Pending;
}
}
}
}
impl Spotify {
pub fn new(
events: EventManager,
@@ -365,7 +186,7 @@ impl Spotify {
.expect("could not open spotify session")
}
fn get_token(
pub(crate) fn get_token(
session: &Session,
sender: oneshot::Sender<Token>,
) -> Pin<Box<dyn Future<Output = Result<(), MercuryError>>>> {
@@ -955,7 +776,7 @@ impl Spotify {
}
#[derive(Debug, PartialEq)]
pub enum URIType {
pub enum UriType {
Album,
Artist,
Track,
@@ -964,20 +785,20 @@ pub enum URIType {
Episode,
}
impl URIType {
pub fn from_uri(s: &str) -> Option<URIType> {
impl UriType {
pub fn from_uri(s: &str) -> Option<UriType> {
if s.starts_with("spotify:album:") {
Some(URIType::Album)
Some(UriType::Album)
} else if s.starts_with("spotify:artist:") {
Some(URIType::Artist)
Some(UriType::Artist)
} else if s.starts_with("spotify:track:") {
Some(URIType::Track)
Some(UriType::Track)
} else if s.starts_with("spotify:") && s.contains(":playlist:") {
Some(URIType::Playlist)
Some(UriType::Playlist)
} else if s.starts_with("spotify:show:") {
Some(URIType::Show)
Some(UriType::Show)
} else if s.starts_with("spotify:episode:") {
Some(URIType::Episode)
Some(UriType::Episode)
} else {
None
}

View File

@@ -1,15 +1,15 @@
use crate::spotify::URIType;
use crate::spotify::UriType;
use url::{Host, Url};
pub struct SpotifyURL {
pub struct SpotifyUrl {
pub id: String,
pub uri_type: URIType,
pub uri_type: UriType,
}
impl SpotifyURL {
fn new(id: &str, uri_type: URIType) -> SpotifyURL {
SpotifyURL {
impl SpotifyUrl {
fn new(id: &str, uri_type: UriType) -> SpotifyUrl {
SpotifyUrl {
id: id.to_string(),
uri_type,
}
@@ -22,7 +22,7 @@ impl SpotifyURL {
/// assert_eq!(result.id, "4uLU6hMCjMI75M1A2tKUQC");
/// assert_eq!(result.uri_type, URIType::Track);
/// ```
pub fn from_url(s: &str) -> Option<SpotifyURL> {
pub fn from_url(s: &str) -> Option<SpotifyUrl> {
let url = Url::parse(s).ok()?;
if url.host() != Some(Host::Domain("open.spotify.com")) {
return None;
@@ -33,12 +33,12 @@ impl SpotifyURL {
let entity = path_segments.next()?;
let uri_type = match entity.to_lowercase().as_str() {
"album" => Some(URIType::Album),
"artist" => Some(URIType::Artist),
"episode" => Some(URIType::Episode),
"playlist" => Some(URIType::Playlist),
"show" => Some(URIType::Show),
"track" => Some(URIType::Track),
"album" => Some(UriType::Album),
"artist" => Some(UriType::Artist),
"episode" => Some(UriType::Episode),
"playlist" => Some(UriType::Playlist),
"show" => Some(UriType::Show),
"track" => Some(UriType::Track),
"user" => {
let _user_id = path_segments.next()?;
let entity = path_segments.next()?;
@@ -47,14 +47,14 @@ impl SpotifyURL {
return None;
}
Some(URIType::Playlist)
Some(UriType::Playlist)
}
_ => None,
}?;
let id = path_segments.next()?;
Some(SpotifyURL::new(id, uri_type))
Some(SpotifyUrl::new(id, uri_type))
}
}
@@ -62,39 +62,39 @@ impl SpotifyURL {
mod tests {
use std::collections::HashMap;
use super::SpotifyURL;
use crate::spotify::URIType;
use super::SpotifyUrl;
use crate::spotify::UriType;
#[test]
fn test_urls() {
let mut test_cases = HashMap::new();
test_cases.insert(
"https://open.spotify.com/playlist/1XFxe8bkTryTODn0lk4CNa?si=FfSpZ6KPQdieClZbwHakOQ",
SpotifyURL::new("1XFxe8bkTryTODn0lk4CNa", URIType::Playlist),
SpotifyUrl::new("1XFxe8bkTryTODn0lk4CNa", UriType::Playlist),
);
test_cases.insert(
"https://open.spotify.com/track/6fRJg3R90w0juYoCJXxj2d",
SpotifyURL::new("6fRJg3R90w0juYoCJXxj2d", URIType::Track),
SpotifyUrl::new("6fRJg3R90w0juYoCJXxj2d", UriType::Track),
);
test_cases.insert(
"https://open.spotify.com/user/~villainy~/playlist/0OgoSs65CLDPn6AF6tsZVg",
SpotifyURL::new("0OgoSs65CLDPn6AF6tsZVg", URIType::Playlist),
SpotifyUrl::new("0OgoSs65CLDPn6AF6tsZVg", UriType::Playlist),
);
test_cases.insert(
"https://open.spotify.com/show/4MZfJbM2MXzZdPbv6gi5lJ",
SpotifyURL::new("4MZfJbM2MXzZdPbv6gi5lJ", URIType::Show),
SpotifyUrl::new("4MZfJbM2MXzZdPbv6gi5lJ", UriType::Show),
);
test_cases.insert(
"https://open.spotify.com/episode/3QE6rfmjRaeqXSqeWcIWF6",
SpotifyURL::new("3QE6rfmjRaeqXSqeWcIWF6", URIType::Episode),
SpotifyUrl::new("3QE6rfmjRaeqXSqeWcIWF6", UriType::Episode),
);
test_cases.insert(
"https://open.spotify.com/artist/6LEeAFiJF8OuPx747e1wxR",
SpotifyURL::new("6LEeAFiJF8OuPx747e1wxR", URIType::Artist),
SpotifyUrl::new("6LEeAFiJF8OuPx747e1wxR", UriType::Artist),
);
for case in test_cases {
let result = SpotifyURL::from_url(case.0).unwrap();
let result = SpotifyUrl::from_url(case.0).unwrap();
assert_eq!(result.id, case.1.id);
assert_eq!(result.uri_type, case.1.uri_type);
}

188
src/spotify_worker.rs Normal file
View File

@@ -0,0 +1,188 @@
use crate::events::{Event, EventManager};
use crate::playable::Playable;
use crate::spotify::{PlayerEvent, Spotify};
use futures::channel::{mpsc, oneshot};
use futures::compat::Stream01CompatExt;
use futures::task::{Context, Poll};
use futures::{Future, Stream};
use futures_01::stream::Stream as v01_Stream;
use futures_01::sync::mpsc::UnboundedReceiver;
use futures_01::Async as v01_Async;
use librespot_core::keymaster::Token;
use librespot_core::mercury::MercuryError;
use librespot_core::session::Session;
use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId};
use librespot_playback::mixer::Mixer;
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
use std::pin::Pin;
use std::time::Duration;
pub(crate) enum WorkerCommand {
Load(Playable),
Play,
Pause,
Stop,
Seek(u32),
SetVolume(u16),
RequestToken(oneshot::Sender<Token>),
Shutdown,
}
pub struct Worker {
events: EventManager,
player_events: UnboundedReceiver<LibrespotPlayerEvent>,
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
session: Session,
player: Player,
refresh_task: Pin<Box<dyn Stream<Item = Result<(), tokio_timer::Error>>>>,
token_task: Pin<Box<dyn Future<Output = Result<(), MercuryError>>>>,
active: bool,
mixer: Box<dyn Mixer>,
}
impl Worker {
pub(crate) fn new(
events: EventManager,
player_events: UnboundedReceiver<LibrespotPlayerEvent>,
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
session: Session,
player: Player,
mixer: Box<dyn Mixer>,
) -> Worker {
Worker {
events,
player_events,
commands,
player,
session,
refresh_task: Box::pin(futures::stream::empty()),
token_task: Box::pin(futures::future::pending()),
active: false,
mixer,
}
}
}
impl Worker {
fn create_refresh(&self) -> Pin<Box<dyn Stream<Item = Result<(), tokio_timer::Error>>>> {
let ev = self.events.clone();
let future =
tokio_timer::Interval::new_interval(Duration::from_millis(400)).map(move |_| {
ev.trigger();
});
Box::pin(future.compat())
}
}
impl futures::Future for Worker {
type Output = Result<(), ()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> futures::task::Poll<Self::Output> {
loop {
let mut progress = false;
if self.session.is_invalid() {
self.events.send(Event::Player(PlayerEvent::Stopped));
return Poll::Ready(Result::Err(()));
}
if let Poll::Ready(Some(cmd)) = self.commands.as_mut().poll_next(cx) {
progress = true;
debug!("message received!");
match cmd {
WorkerCommand::Load(playable) => match SpotifyId::from_uri(&playable.uri()) {
Ok(id) => {
info!("player loading track: {:?}", id);
if id.audio_type == SpotifyAudioType::NonPlayable {
warn!("track is not playable");
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
} else {
self.player.load(id, true, 0);
}
}
Err(e) => {
error!("error parsing uri: {:?}", e);
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
}
},
WorkerCommand::Play => {
self.player.play();
}
WorkerCommand::Pause => {
self.player.pause();
}
WorkerCommand::Stop => {
self.player.stop();
}
WorkerCommand::Seek(pos) => {
self.player.seek(pos);
}
WorkerCommand::SetVolume(volume) => {
self.mixer.set_volume(volume);
}
WorkerCommand::RequestToken(sender) => {
self.token_task = Spotify::get_token(&self.session, sender);
progress = true;
}
WorkerCommand::Shutdown => {
self.player.stop();
self.session.shutdown();
}
}
}
if let Ok(v01_Async::Ready(Some(event))) = self.player_events.poll() {
debug!("librespot player event: {:?}", event);
match event {
LibrespotPlayerEvent::Started { .. }
| LibrespotPlayerEvent::Loading { .. }
| LibrespotPlayerEvent::Changed { .. } => {
progress = true;
}
LibrespotPlayerEvent::Playing { .. } => {
self.events.send(Event::Player(PlayerEvent::Playing));
self.refresh_task = self.create_refresh();
self.active = true;
}
LibrespotPlayerEvent::Paused { .. } => {
self.events.send(Event::Player(PlayerEvent::Paused));
self.active = false;
}
LibrespotPlayerEvent::Stopped { .. } => {
self.events.send(Event::Player(PlayerEvent::Stopped));
self.active = false;
}
LibrespotPlayerEvent::EndOfTrack { .. } => {
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
progress = true;
}
_ => {}
}
}
if let Poll::Ready(Some(Ok(_))) = self.refresh_task.as_mut().poll_next(cx) {
self.refresh_task = if self.active {
progress = true;
self.create_refresh()
} else {
Box::pin(futures::stream::empty())
};
}
match self.token_task.as_mut().poll(cx) {
Poll::Ready(Ok(_)) => {
info!("token updated!");
self.token_task = Box::pin(futures::future::pending())
}
Poll::Ready(Err(e)) => {
error!("could not generate token: {:?}", e);
}
_ => (),
}
if !progress {
return Poll::Pending;
}
}
}
}

View File

@@ -26,7 +26,7 @@ use crate::ui::album::AlbumView;
use crate::ui::artist::ArtistView;
use crate::ui::contextmenu::ContextMenu;
use crate::ui::pagination::Pagination;
use crate::{album::Album, spotify::URIType, spotify_url::SpotifyURL};
use crate::{album::Album, spotify::UriType, spotify_url::SpotifyUrl};
pub struct ListView<I: ListItem> {
content: Arc<RwLock<Vec<I>>>,
@@ -535,26 +535,26 @@ impl<I: ListItem + Clone> ViewExt for ListView<I> {
let spotify = self.queue.get_spotify();
let url = SpotifyURL::from_url(&url);
let url = SpotifyUrl::from_url(&url);
if let Some(url) = url {
let target: Option<Box<dyn ListItem>> = match url.uri_type {
URIType::Track => spotify
UriType::Track => spotify
.track(&url.id)
.map(|track| Track::from(&track).as_listitem()),
URIType::Album => spotify
UriType::Album => spotify
.album(&url.id)
.map(|album| Album::from(&album).as_listitem()),
URIType::Playlist => spotify
UriType::Playlist => spotify
.playlist(&url.id)
.map(|playlist| Playlist::from(&playlist).as_listitem()),
URIType::Artist => spotify
UriType::Artist => spotify
.artist(&url.id)
.map(|artist| Artist::from(&artist).as_listitem()),
URIType::Episode => spotify
UriType::Episode => spotify
.episode(&url.id)
.map(|episode| Episode::from(&episode).as_listitem()),
URIType::Show => spotify
UriType::Show => spotify
.get_show(&url.id)
.map(|show| Show::from(&show).as_listitem()),
};

View File

@@ -19,7 +19,7 @@ use crate::library::Library;
use crate::playlist::Playlist;
use crate::queue::Queue;
use crate::show::Show;
use crate::spotify::{Spotify, URIType};
use crate::spotify::{Spotify, UriType};
use crate::track::Track;
use crate::traits::{ListItem, ViewExt};
use crate::ui::layout::Layout;

View File

@@ -8,8 +8,8 @@ use crate::library::Library;
use crate::playlist::Playlist;
use crate::queue::Queue;
use crate::show::Show;
use crate::spotify::{Spotify, URIType};
use crate::spotify_url::SpotifyURL;
use crate::spotify::{Spotify, UriType};
use crate::spotify_url::SpotifyUrl;
use crate::track::Track;
use crate::traits::{ListItem, ViewExt};
use crate::ui::listview::ListView;
@@ -381,9 +381,9 @@ impl SearchResultsView {
self.spotify.refresh_token();
// is the query a Spotify URI?
if let Some(uritype) = URIType::from_uri(&query) {
if let Some(uritype) = UriType::from_uri(&query) {
match uritype {
URIType::Track => {
UriType::Track => {
self.perform_search(
Box::new(Self::get_track),
&self.results_tracks,
@@ -392,7 +392,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(0);
}
URIType::Album => {
UriType::Album => {
self.perform_search(
Box::new(Self::get_album),
&self.results_albums,
@@ -401,7 +401,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(1);
}
URIType::Artist => {
UriType::Artist => {
self.perform_search(
Box::new(Self::get_artist),
&self.results_artists,
@@ -410,7 +410,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(2);
}
URIType::Playlist => {
UriType::Playlist => {
self.perform_search(
Box::new(Self::get_playlist),
&self.results_playlists,
@@ -419,7 +419,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(3);
}
URIType::Show => {
UriType::Show => {
self.perform_search(
Box::new(Self::get_show),
&self.results_shows,
@@ -428,7 +428,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(4);
}
URIType::Episode => {
UriType::Episode => {
self.perform_search(
Box::new(Self::get_episode),
&self.results_episodes,
@@ -440,9 +440,9 @@ impl SearchResultsView {
}
// Is the query a spotify URL?
// https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC
} else if let Some(url) = SpotifyURL::from_url(&query) {
} else if let Some(url) = SpotifyUrl::from_url(&query) {
match url.uri_type {
URIType::Track => {
UriType::Track => {
self.perform_search(
Box::new(Self::get_track),
&self.results_tracks,
@@ -451,7 +451,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(0);
}
URIType::Album => {
UriType::Album => {
self.perform_search(
Box::new(Self::get_album),
&self.results_albums,
@@ -460,7 +460,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(1);
}
URIType::Artist => {
UriType::Artist => {
self.perform_search(
Box::new(Self::get_artist),
&self.results_artists,
@@ -469,7 +469,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(2);
}
URIType::Playlist => {
UriType::Playlist => {
self.perform_search(
Box::new(Self::get_playlist),
&self.results_playlists,
@@ -478,7 +478,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(3);
}
URIType::Show => {
UriType::Show => {
self.perform_search(
Box::new(Self::get_show),
&self.results_shows,
@@ -487,7 +487,7 @@ impl SearchResultsView {
);
self.tabs.move_focus_to(4);
}
URIType::Episode => {
UriType::Episode => {
self.perform_search(
Box::new(Self::get_episode),
&self.results_episodes,