Skip to content

Commit 47a4a0d

Browse files
committed
Foo
1 parent f123a55 commit 47a4a0d

6 files changed

Lines changed: 102 additions & 31 deletions

File tree

examples/play.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
from librespot import Session, SpotifyId
3+
import threading
34

45
if len(sys.argv) != 4:
56
print("Usage: %s USERNAME PASSWORD TRACK" % sys.argv[0])
@@ -13,7 +14,15 @@
1314
session = Session.connect(username, password).wait()
1415
player = session.player()
1516

17+
print(threading.get_ident())
18+
def print_track(track):
19+
print(threading.get_ident())
20+
print("Playing track \"%s\"..." % (track.name(),))
21+
22+
session.get_track(trackid).spawn(print_track)
23+
1624
print("Playing ...")
1725
player.load(trackid).wait()
1826

27+
1928
print("Done")

src/metadata.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use librespot;
21
use cpython::{PyResult, Python, PythonObject};
3-
use pyfuture::PyFuture;
42
use futures;
3+
use librespot;
4+
use pyfuture::PyFuture;
5+
use tokio_core::reactor::Remote;
56
use SpotifyId;
67

78
py_class!(pub class Track |py| {
89
data session : librespot::session::Session;
10+
data handle : Remote;
911
data track : librespot::metadata::Track;
1012

1113
def id(&self) -> PyResult<SpotifyId> {
@@ -18,20 +20,23 @@ py_class!(pub class Track |py| {
1820

1921
def album(&self) -> PyResult<PyFuture> {
2022
let session = self.session(py).clone();
23+
let handle = self.handle(py).clone();
2124
let album = self.track(py).album;
2225

23-
Album::get(py, session, album)
26+
Album::get(py, session, handle, album)
2427
}
2528

2629
def artists(&self) -> PyResult<PyFuture> {
2730
let session = self.session(py).clone();
31+
let handle = self.handle(py).clone();
2832
let artists = self.track(py).artists.clone();
29-
Artist::get_all(py, session, artists)
33+
Artist::get_all(py, session, handle, artists)
3034
}
3135
});
3236

3337
py_class!(pub class Album |py| {
3438
data session : librespot::session::Session;
39+
data handle : Remote;
3540
data album : librespot::metadata::Album;
3641

3742
def id(&self) -> PyResult<SpotifyId> {
@@ -44,19 +49,22 @@ py_class!(pub class Album |py| {
4449

4550
def artists(&self) -> PyResult<PyFuture> {
4651
let session = self.session(py).clone();
52+
let handle = self.handle(py).clone();
4753
let artists = self.album(py).artists.clone();
48-
Artist::get_all(py, session, artists)
54+
Artist::get_all(py, session, handle, artists)
4955
}
5056

5157
def tracks(&self) -> PyResult<PyFuture> {
5258
let session = self.session(py).clone();
59+
let handle = self.handle(py).clone();
5360
let artists = self.album(py).tracks.clone();
54-
Track::get_all(py, session, artists)
61+
Track::get_all(py, session, handle, artists)
5562
}
5663
});
5764

5865
py_class!(pub class Artist |py| {
5966
data _session : librespot::session::Session;
67+
data _handle : Remote;
6068
data artist : librespot::metadata::Artist;
6169

6270
def id(&self) -> PyResult<SpotifyId> {
@@ -70,6 +78,7 @@ py_class!(pub class Artist |py| {
7078

7179
fn get<T, F, O>(py: Python,
7280
session: librespot::session::Session,
81+
handle : Remote,
7382
id: librespot::util::SpotifyId,
7483
create_instance: F) -> PyResult<PyFuture>
7584
where
@@ -78,13 +87,14 @@ fn get<T, F, O>(py: Python,
7887
O: PythonObject
7988
{
8089
let future = session.metadata().get::<T>(id);
81-
PyFuture::new(py, future, |py, result| {
82-
create_instance(py, session, result.unwrap())
90+
PyFuture::new(py, handle.clone(), future, |py, result| {
91+
create_instance(py, session, handle, result.unwrap())
8392
})
8493
}
8594

8695
fn get_all<T, F, O, I>(py: Python,
8796
session: librespot::session::Session,
97+
handle : Remote,
8898
ids: I,
8999
create_instance: F) -> PyResult<PyFuture>
90100
where
@@ -101,10 +111,10 @@ fn get_all<T, F, O, I>(py: Python,
101111

102112
let future = futures::future::join_all(futures);
103113

104-
PyFuture::new(py, future, move |py, result| {
114+
PyFuture::new(py, handle.clone(), future, move |py, result| {
105115
let objects = result.unwrap();
106116
let objects = objects.into_iter().map(|artist| {
107-
create_instance(py, session.clone(), artist)
117+
create_instance(py, session.clone(), handle.clone(), artist)
108118
}).collect::<PyResult<Vec<_>>>()?;
109119

110120
Ok(objects)
@@ -114,53 +124,59 @@ fn get_all<T, F, O, I>(py: Python,
114124
impl Track {
115125
pub fn get(py: Python,
116126
session: librespot::session::Session,
127+
handle : Remote,
117128
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
118129
{
119130
get(py, session, id, Track::create_instance)
120131
}
121132

122133
pub fn get_all<I>(py: Python,
123134
session: librespot::session::Session,
135+
handle : Remote,
124136
ids: I) -> PyResult<PyFuture>
125137
where I: IntoIterator<Item = librespot::util::SpotifyId>,
126138
I::IntoIter: 'static
127139
{
128-
get_all(py, session, ids, Track::create_instance)
140+
get_all(py, session, handle, ids, Track::create_instance)
129141
}
130142
}
131143

132144
impl Album {
133145
pub fn get(py: Python,
134146
session: librespot::session::Session,
147+
handle : Remote,
135148
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
136149
{
137150
get(py, session, id, Album::create_instance)
138151
}
139152

140153
pub fn get_all<I>(py: Python,
141154
session: librespot::session::Session,
155+
handle : Remote,
142156
ids: I) -> PyResult<PyFuture>
143157
where I: IntoIterator<Item = librespot::util::SpotifyId>,
144158
I::IntoIter: 'static
145159
{
146-
get_all(py, session, ids, Album::create_instance)
160+
get_all(py, session, handle, ids, Album::create_instance)
147161
}
148162
}
149163

150164
impl Artist {
151165
pub fn get(py: Python,
152166
session: librespot::session::Session,
167+
handle : Remote,
153168
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
154169
{
155-
get(py, session, id, Artist::create_instance)
170+
get(py, session, handle, id, Artist::create_instance)
156171
}
157172

158173
pub fn get_all<I>(py: Python,
159174
session: librespot::session::Session,
175+
handle : Remote,
160176
ids: I) -> PyResult<PyFuture>
161177
where I: IntoIterator<Item = librespot::util::SpotifyId>,
162178
I::IntoIter: 'static
163179
{
164-
get_all(py, session, ids, Artist::create_instance)
180+
get_all(py, session, handle, ids, Artist::create_instance)
165181
}
166182
}

src/player.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ use librespot;
22
use SpotifyId;
33
use cpython::{PyResult, PyObject, Python};
44
use pyfuture::PyFuture;
5+
use tokio_core::reactor::Remote;
56

67
py_class!(pub class Player |py| {
78
data player : librespot::player::Player;
9+
data handle: Remote;
810

911
def load(&self, track: SpotifyId, play: bool = true, position_ms: u32 = 0) -> PyResult<PyFuture> {
1012
let player = self.player(py);
13+
let handle = self.handle(py).clone();
1114
let track = *track.id(py);
1215

1316
let end_of_track = player.load(track, play, position_ms);
14-
PyFuture::new(py, end_of_track, |_py, _result| {
17+
PyFuture::new(py, handle, end_of_track, |_py, _result| {
1518
Ok(true)
1619
})
1720
}
@@ -30,10 +33,10 @@ py_class!(pub class Player |py| {
3033
});
3134

3235
impl Player {
33-
pub fn new(py: Python, session: librespot::session::Session) -> PyResult<Player> {
36+
pub fn new(py: Python, session: librespot::session::Session, handle: Remote) -> PyResult<Player> {
3437
let backend = librespot::audio_backend::find(None).unwrap();
3538
let player = librespot::player::Player::new(session, None, move || (backend)(None));
36-
Player::create_instance(py, player)
39+
Player::create_instance(py, player, handle)
3740
}
3841
}
3942

src/pyfuture.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
use cpython::{PyResult, PyObject, Python, PythonObject, ToPyObject};
1+
use cpython::{PyResult, PyObject, Python, PythonObject, ToPyObject, ObjectProtocol};
22
use futures::executor;
33
use futures::{Future, Async};
44
use std::cell::RefCell;
55
use std::sync::Arc;
6+
use tokio_core::reactor::Remote;
67

78
pub trait Callback : Send {
89
fn poll(&mut self, py: Python) -> PyResult<Option<PyObject>>;
910
fn wait(&mut self, py: Python) -> PyResult<PyObject>;
11+
fn spawn(&mut self, py: Python, cb: PyObject) -> PyResult<PyObject>;
1012
}
1113

1214
struct FutureData<F, T> {
15+
handle: Remote,
1316
future: Option<executor::Spawn<F>>,
1417
then: Option<T>,
1518
}
@@ -26,7 +29,7 @@ impl <F, T, U> Callback for FutureData<F, T>
2629
{
2730
fn poll(&mut self, py: Python) -> PyResult<Option<PyObject>> {
2831
let result = {
29-
let future = self.future.as_mut().expect("Future already completed");
32+
let future = self.future.as_mut().expect("Future already consumed");
3033
match future.poll_future(Arc::new(NoopUnpark)) {
3134
Ok(Async::Ready(v)) => Ok(v),
3235
Err(e) => Err(e),
@@ -40,12 +43,31 @@ impl <F, T, U> Callback for FutureData<F, T>
4043
}
4144

4245
fn wait(&mut self, py: Python) -> PyResult<PyObject> {
43-
let mut future = self.future.take().expect("Future already completed");
46+
let mut future = self.future.take().expect("Future already consumed");
4447
let result = py.allow_threads(|| future.wait_future());
4548

4649
let then = self.then.take().unwrap();
4750
then(py, result).map(|o| o.into_py_object(py).into_object())
4851
}
52+
53+
fn spawn(&mut self, py: Python, cb: PyObject) -> PyResult<PyObject> {
54+
let future = self.future.take().expect("Future already consumed").into_inner();
55+
let then = self.then.take().unwrap();
56+
57+
self.handle.spawn(move |_handle| {
58+
future.then(move |result| {
59+
let gil = Python::acquire_gil();
60+
let py = gil.python();
61+
62+
let arg = then(py, result).unwrap().into_py_object(py).into_object();
63+
cb.call(py, (arg,) , None).unwrap();
64+
65+
Ok(())
66+
})
67+
});
68+
69+
Ok(py.None())
70+
}
4971
}
5072

5173
py_class!(pub class PyFuture |py| {
@@ -58,15 +80,20 @@ py_class!(pub class PyFuture |py| {
5880
def wait(&self) -> PyResult<PyObject> {
5981
self.callback(py).borrow_mut().wait(py)
6082
}
83+
84+
def spawn(&self, cb: PyObject) -> PyResult<PyObject> {
85+
self.callback(py).borrow_mut().spawn(py, cb)
86+
}
6187
});
6288

6389
impl PyFuture {
64-
pub fn new<F, T, U>(py: Python, future: F, then: T) -> PyResult<PyFuture>
90+
pub fn new<F, T, U>(py: Python, handle: Remote, future: F, then: T) -> PyResult<PyFuture>
6591
where F: Future + Send + 'static,
6692
T: FnOnce(Python, Result<F::Item, F::Error>) -> PyResult<U> + Send + 'static,
6793
U: ToPyObject
6894
{
6995
PyFuture::create_instance(py, RefCell::new(Box::new(FutureData {
96+
handle: handle,
7097
future: Some(executor::spawn(future)),
7198
then: Some(then),
7299
})))

0 commit comments

Comments
 (0)