implement track search and playback
This commit is contained in:
@@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
|
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cursive = "0.9"
|
cursive = "0.10"
|
||||||
crossbeam-channel = "0.2"
|
crossbeam-channel = "0.2"
|
||||||
env_logger = "0.5.13"
|
env_logger = "0.5.13"
|
||||||
failure = "0.1.3"
|
failure = "0.1.3"
|
||||||
|
|||||||
74
src/main.rs
74
src/main.rs
@@ -16,14 +16,13 @@ extern crate log;
|
|||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::fs::OpenOptions;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use cursive::views::*;
|
use cursive::views::*;
|
||||||
use cursive::CbFunc;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
use librespot::core::spotify_id::SpotifyId;
|
use librespot::core::spotify_id::SpotifyId;
|
||||||
@@ -31,33 +30,38 @@ use librespot::core::spotify_id::SpotifyId;
|
|||||||
mod config;
|
mod config;
|
||||||
mod spotify;
|
mod spotify;
|
||||||
mod theme;
|
mod theme;
|
||||||
|
mod ui;
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
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_LOG", "ncspot=trace");
|
||||||
|
std::env::set_var("RUST_BACKTRACE", "full");
|
||||||
|
|
||||||
let mut builder = env_logger::Builder::from_default_env();
|
let mut builder = env_logger::Builder::from_default_env();
|
||||||
{
|
{
|
||||||
let mut loglines = loglines.clone();
|
builder
|
||||||
builder.format(move |buf, record| {
|
.format(move |_, record| {
|
||||||
let mut lines = loglines.lock().unwrap();
|
let line = format!("[{}] {}\n", record.level(), record.args());
|
||||||
lines.push(format!("[{}] {}", record.level(), record.args()));
|
logbuf.clone().append(line.clone());
|
||||||
Ok(())
|
|
||||||
}).init();
|
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();
|
let mut cursive = Cursive::default();
|
||||||
// cursive.add_global_callback('q', |s| s.quit());
|
cursive.add_global_callback('q', |s| s.quit());
|
||||||
// cursive.set_theme(theme::default());
|
cursive.set_theme(theme::default());
|
||||||
|
|
||||||
let path = match env::var_os("HOME") {
|
let path = match env::var_os("HOME") {
|
||||||
None => {
|
None => {
|
||||||
@@ -69,22 +73,16 @@ fn main() {
|
|||||||
|
|
||||||
let cfg = config::load(path.to_str().unwrap()).expect("could not load configuration file");
|
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);
|
cursive.run();
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,16 +156,18 @@ impl Spotify {
|
|||||||
println!("Spotify::run() finished");
|
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)
|
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);
|
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()");
|
info!("play()");
|
||||||
self.channel.unbounded_send(WorkerCommand::Play).unwrap();
|
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