implement track search and playback
This commit is contained in:
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
|
||||
|
||||
[dependencies]
|
||||
cursive = "0.9"
|
||||
cursive = "0.10"
|
||||
crossbeam-channel = "0.2"
|
||||
env_logger = "0.5.13"
|
||||
failure = "0.1.3"
|
||||
|
||||
74
src/main.rs
74
src/main.rs
@@ -16,14 +16,13 @@ extern crate log;
|
||||
extern crate env_logger;
|
||||
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use cursive::views::*;
|
||||
use cursive::CbFunc;
|
||||
use cursive::Cursive;
|
||||
|
||||
use librespot::core::spotify_id::SpotifyId;
|
||||
@@ -31,33 +30,38 @@ use librespot::core::spotify_id::SpotifyId;
|
||||
mod config;
|
||||
mod spotify;
|
||||
mod theme;
|
||||
|
||||
pub trait CbSpotify: Send {
|
||||
fn call_box(self: Box<Self>, &mut spotify::Spotify);
|
||||
}
|
||||
|
||||
impl<F: FnOnce(&mut spotify::Spotify) -> () + Send> CbSpotify for F {
|
||||
fn call_box(self: Box<Self>, s: &mut spotify::Spotify) {
|
||||
(*self)(s)
|
||||
}
|
||||
}
|
||||
mod ui;
|
||||
|
||||
fn main() {
|
||||
let loglines = Arc::new(Mutex::new(Vec::new()));
|
||||
let logbuf = TextContent::new("Welcome to ncspot\n");
|
||||
let logview = TextView::new_with_content(logbuf.clone());
|
||||
std::env::set_var("RUST_LOG", "ncspot=trace");
|
||||
std::env::set_var("RUST_BACKTRACE", "full");
|
||||
|
||||
let mut builder = env_logger::Builder::from_default_env();
|
||||
{
|
||||
let mut loglines = loglines.clone();
|
||||
builder.format(move |buf, record| {
|
||||
let mut lines = loglines.lock().unwrap();
|
||||
lines.push(format!("[{}] {}", record.level(), record.args()));
|
||||
Ok(())
|
||||
}).init();
|
||||
builder
|
||||
.format(move |_, record| {
|
||||
let line = format!("[{}] {}\n", record.level(), record.args());
|
||||
logbuf.clone().append(line.clone());
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open("ncspot.log")
|
||||
.unwrap();
|
||||
if let Err(e) = writeln!(file, "{}", line) {
|
||||
eprintln!("Couldn't write to file: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.init();
|
||||
}
|
||||
|
||||
// let mut cursive = Cursive::default();
|
||||
// cursive.add_global_callback('q', |s| s.quit());
|
||||
// cursive.set_theme(theme::default());
|
||||
let mut cursive = Cursive::default();
|
||||
cursive.add_global_callback('q', |s| s.quit());
|
||||
cursive.set_theme(theme::default());
|
||||
|
||||
let path = match env::var_os("HOME") {
|
||||
None => {
|
||||
@@ -69,22 +73,16 @@ fn main() {
|
||||
|
||||
let cfg = config::load(path.to_str().unwrap()).expect("could not load configuration file");
|
||||
|
||||
let spotify = spotify::Spotify::new(cfg.username, cfg.password, cfg.client_id);
|
||||
let spotify = Arc::new(spotify::Spotify::new(
|
||||
cfg.username,
|
||||
cfg.password,
|
||||
cfg.client_id,
|
||||
));
|
||||
|
||||
// let track = SpotifyId::from_base62("24zYR2ozYbnhhwulk2NLD4").expect("could not load track");
|
||||
let logpanel = Panel::new(logview).title("Log");
|
||||
//cursive.add_fullscreen_layer(logpanel);
|
||||
let search = ui::search::SearchView::new(spotify.clone());
|
||||
cursive.add_fullscreen_layer(search.view);
|
||||
|
||||
// spotify.load(track);
|
||||
// thread::sleep(time::Duration::new(3, 0));
|
||||
// spotify.play();
|
||||
// thread::sleep(time::Duration::new(3, 0));
|
||||
// spotify.pause();
|
||||
// thread::sleep(time::Duration::new(3, 0));
|
||||
// spotify.play();
|
||||
|
||||
// thread::sleep(time::Duration::new(8, 0));
|
||||
// spotify.load(track);
|
||||
// spotify.play();
|
||||
|
||||
let _ = io::stdin().read(&mut [0u8]).unwrap();
|
||||
// cursive.run();
|
||||
cursive.run();
|
||||
}
|
||||
|
||||
@@ -156,16 +156,18 @@ impl Spotify {
|
||||
println!("Spotify::run() finished");
|
||||
}
|
||||
|
||||
pub fn search(&mut self, query: &str, limit: u32, offset: u32) -> Result<SearchTracks, Error> {
|
||||
pub fn search(&self, query: &str, limit: u32, offset: u32) -> Result<SearchTracks, Error> {
|
||||
self.api.search_track(query, limit, offset, None)
|
||||
}
|
||||
|
||||
pub fn load(&mut self, track: SpotifyId) {
|
||||
pub fn load(&self, track: SpotifyId) {
|
||||
info!("loading track: {:?}", track);
|
||||
self.channel.unbounded_send(WorkerCommand::Load(track)).unwrap();
|
||||
self.channel
|
||||
.unbounded_send(WorkerCommand::Load(track))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn play(&mut self) {
|
||||
pub fn play(&self) {
|
||||
info!("play()");
|
||||
self.channel.unbounded_send(WorkerCommand::Play).unwrap();
|
||||
}
|
||||
|
||||
1
src/ui/mod.rs
Normal file
1
src/ui/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod search;
|
||||
55
src/ui/search.rs
Normal file
55
src/ui/search.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use cursive::direction::Orientation;
|
||||
use cursive::traits::Boxable;
|
||||
use cursive::traits::Identifiable;
|
||||
use cursive::views::*;
|
||||
use cursive::Cursive;
|
||||
use std::sync::Arc;
|
||||
|
||||
use librespot::core::spotify_id::SpotifyId;
|
||||
|
||||
use spotify::Spotify;
|
||||
|
||||
pub struct SearchView {
|
||||
pub view: Panel<LinearLayout>,
|
||||
}
|
||||
|
||||
impl SearchView {
|
||||
pub fn search_handler(s: &mut Cursive, input: &str, spotify: Arc<Spotify>) {
|
||||
let mut results: ViewRef<ListView> = s.find_id("search_results").unwrap();
|
||||
let tracks = spotify.search(input, 10, 0);
|
||||
|
||||
results.clear();
|
||||
|
||||
if let Ok(tracks) = tracks {
|
||||
for track in tracks.tracks.items {
|
||||
let s = spotify.clone();
|
||||
let trackid = SpotifyId::from_base62(&track.id).expect("could not load track");
|
||||
let button = Button::new(track.name, move |_cursive| {
|
||||
s.load(trackid);
|
||||
s.play();
|
||||
});
|
||||
results.add_child(&track.id, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(spotify: Arc<Spotify>) -> SearchView {
|
||||
let spotify_ref = spotify.clone();
|
||||
let searchfield = EditView::new()
|
||||
.on_submit(move |s, input| {
|
||||
SearchView::search_handler(s, input, spotify_ref.clone());
|
||||
})
|
||||
.with_id("search_edit")
|
||||
.full_width()
|
||||
.fixed_height(1);
|
||||
let results = ListView::new()
|
||||
.with_id("search_results")
|
||||
.full_width()
|
||||
.full_height();
|
||||
let layout = LinearLayout::new(Orientation::Vertical)
|
||||
.child(searchfield)
|
||||
.child(results);
|
||||
let rootpanel = Panel::new(layout).title("Search");
|
||||
return SearchView { view: rootpanel };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user