Skip to content

Commit 44494a2

Browse files
committed
Expose metadata api
1 parent 562e293 commit 44494a2

File tree

6 files changed

+229
-7
lines changed

6 files changed

+229
-7
lines changed

examples/play.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
print("Usage: %s USERNAME PASSWORD TRACK" % sys.argv[0])
66
sys.exit(1)
77

8-
[_, username, password, trackid] = sys.argv
8+
username = sys.argv[1]
9+
password = sys.argv[2]
10+
trackid = SpotifyId(sys.argv[3])
911

1012
print("Connecting ...")
1113
session = Session.connect(username, password).wait()
1214
player = session.player()
1315

1416
print("Playing ...")
15-
track = SpotifyId(trackid)
16-
player.load(track).wait()
17+
player.load(trackid).wait()
1718

1819
print("Done")

examples/play_album.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sys
2+
from librespot import Session, SpotifyId
3+
4+
if len(sys.argv) != 4:
5+
print("Usage: %s USERNAME PASSWORD ALBUM" % sys.argv[0])
6+
sys.exit(1)
7+
8+
username = sys.argv[1]
9+
password = sys.argv[2]
10+
albumid = SpotifyId(sys.argv[3])
11+
12+
print("Connecting ...")
13+
session = Session.connect(username, password).wait()
14+
player = session.player()
15+
16+
album = session.get_album(albumid).wait()
17+
tracks = album.tracks().wait()
18+
19+
print("Playing album \"%s\" (%d tracks)..." % (album.name(), len(tracks)))
20+
21+
for track in tracks:
22+
print("Playing track \"%s\" ..." % track.name())
23+
player.load(track.id()).wait()
24+
25+
print("Done")

src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ extern crate futures;
44
extern crate librespot;
55
extern crate tokio_core;
66

7-
use cpython::PyResult;
7+
use cpython::{Python, PyResult};
88

99
mod pyfuture;
1010
mod player;
1111
mod session;
12+
mod metadata;
1213

1314
py_class!(pub class SpotifyId |py| {
1415
data id : librespot::util::SpotifyId;
@@ -19,6 +20,12 @@ py_class!(pub class SpotifyId |py| {
1920
}
2021
});
2122

23+
impl SpotifyId {
24+
pub fn new(py: Python, id: librespot::util::SpotifyId) -> PyResult<SpotifyId> {
25+
SpotifyId::create_instance(py, id)
26+
}
27+
}
28+
2229
py_module_initializer!(librespot, initlibrespot, PyInit_librespot, |py, m| {
2330
m.add_class::<session::Session>(py)?;
2431
m.add_class::<SpotifyId>(py)?;

src/metadata.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
use librespot;
2+
use cpython::{PyResult, Python, PythonObject};
3+
use pyfuture::PyFuture;
4+
use futures;
5+
use SpotifyId;
6+
7+
py_class!(pub class Track |py| {
8+
data session : librespot::session::Session;
9+
data track : librespot::metadata::Track;
10+
11+
def id(&self) -> PyResult<SpotifyId> {
12+
SpotifyId::new(py, self.track(py).id)
13+
}
14+
15+
def name(&self) -> PyResult<String> {
16+
Ok(self.track(py).name.clone())
17+
}
18+
19+
def album(&self) -> PyResult<PyFuture> {
20+
let session = self.session(py).clone();
21+
let album = self.track(py).album;
22+
23+
Album::get(py, session, album)
24+
}
25+
26+
def artists(&self) -> PyResult<PyFuture> {
27+
let session = self.session(py).clone();
28+
let artists = self.track(py).artists.clone();
29+
Artist::get_all(py, session, artists)
30+
}
31+
});
32+
33+
py_class!(pub class Album |py| {
34+
data session : librespot::session::Session;
35+
data album : librespot::metadata::Album;
36+
37+
def id(&self) -> PyResult<SpotifyId> {
38+
SpotifyId::new(py, self.album(py).id)
39+
}
40+
41+
def name(&self) -> PyResult<String> {
42+
Ok(self.album(py).name.clone())
43+
}
44+
45+
def artists(&self) -> PyResult<PyFuture> {
46+
let session = self.session(py).clone();
47+
let artists = self.album(py).artists.clone();
48+
Artist::get_all(py, session, artists)
49+
}
50+
51+
def tracks(&self) -> PyResult<PyFuture> {
52+
let session = self.session(py).clone();
53+
let artists = self.album(py).tracks.clone();
54+
Track::get_all(py, session, artists)
55+
}
56+
});
57+
58+
py_class!(pub class Artist |py| {
59+
data _session : librespot::session::Session;
60+
data artist : librespot::metadata::Artist;
61+
62+
def id(&self) -> PyResult<SpotifyId> {
63+
SpotifyId::new(py, self.artist(py).id)
64+
}
65+
66+
def name(&self) -> PyResult<String> {
67+
Ok(self.artist(py).name.clone())
68+
}
69+
});
70+
71+
fn get<T, F, O>(py: Python,
72+
session: librespot::session::Session,
73+
id: librespot::util::SpotifyId,
74+
create_instance: F) -> PyResult<PyFuture>
75+
where
76+
T: librespot::metadata::MetadataTrait + Send,
77+
F: FnOnce(Python, librespot::session::Session, T) -> PyResult<O> + Send + 'static,
78+
O: PythonObject
79+
{
80+
let future = session.metadata().get::<T>(id);
81+
PyFuture::new(py, future, |py, result| {
82+
create_instance(py, session, result.unwrap())
83+
})
84+
}
85+
86+
fn get_all<T, F, O, I>(py: Python,
87+
session: librespot::session::Session,
88+
ids: I,
89+
create_instance: F) -> PyResult<PyFuture>
90+
where
91+
T: librespot::metadata::MetadataTrait + Send,
92+
F: Fn(Python, librespot::session::Session, T) -> PyResult<O> + Send + 'static,
93+
O: PythonObject,
94+
I: IntoIterator<Item = librespot::util::SpotifyId>,
95+
I::IntoIter: 'static
96+
{
97+
let session_ = session.clone();
98+
let futures = ids.into_iter().map(move |id| {
99+
session_.metadata().get::<T>(id)
100+
});
101+
102+
let future = futures::future::join_all(futures);
103+
104+
PyFuture::new(py, future, move |py, result| {
105+
let objects = result.unwrap();
106+
let objects = objects.into_iter().map(|artist| {
107+
create_instance(py, session.clone(), artist)
108+
}).collect::<PyResult<Vec<_>>>()?;
109+
110+
Ok(objects)
111+
})
112+
}
113+
114+
impl Track {
115+
pub fn get(py: Python,
116+
session: librespot::session::Session,
117+
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
118+
{
119+
get(py, session, id, Track::create_instance)
120+
}
121+
122+
pub fn get_all<I>(py: Python,
123+
session: librespot::session::Session,
124+
ids: I) -> PyResult<PyFuture>
125+
where I: IntoIterator<Item = librespot::util::SpotifyId>,
126+
I::IntoIter: 'static
127+
{
128+
get_all(py, session, ids, Track::create_instance)
129+
}
130+
}
131+
132+
impl Album {
133+
pub fn get(py: Python,
134+
session: librespot::session::Session,
135+
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
136+
{
137+
get(py, session, id, Album::create_instance)
138+
}
139+
140+
pub fn get_all<I>(py: Python,
141+
session: librespot::session::Session,
142+
ids: I) -> PyResult<PyFuture>
143+
where I: IntoIterator<Item = librespot::util::SpotifyId>,
144+
I::IntoIter: 'static
145+
{
146+
get_all(py, session, ids, Album::create_instance)
147+
}
148+
}
149+
150+
impl Artist {
151+
pub fn get(py: Python,
152+
session: librespot::session::Session,
153+
id: librespot::util::SpotifyId) -> PyResult<PyFuture>
154+
{
155+
get(py, session, id, Artist::create_instance)
156+
}
157+
158+
pub fn get_all<I>(py: Python,
159+
session: librespot::session::Session,
160+
ids: I) -> PyResult<PyFuture>
161+
where I: IntoIterator<Item = librespot::util::SpotifyId>,
162+
I::IntoIter: 'static
163+
{
164+
get_all(py, session, ids, Artist::create_instance)
165+
}
166+
}

src/pyfuture.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use futures::Future;
22
use std::cell::RefCell;
3-
use cpython::{PyResult, PyObject, Python, PythonObject};
3+
use cpython::{PyResult, PyObject, Python, PythonObject, ToPyObject};
44

55
// Workaround rust-lang/rust#28796
66
pub trait Callback : Send {
@@ -25,11 +25,11 @@ impl PyFuture {
2525
pub fn new<F, T, U>(py: Python, future: F, then: T) -> PyResult<PyFuture>
2626
where F: Future + Send + 'static,
2727
T: FnOnce(Python, Result<F::Item, F::Error>) -> PyResult<U> + Send + 'static,
28-
U: PythonObject
28+
U: ToPyObject
2929
{
3030
PyFuture::create_instance(py, RefCell::new(Some(Box::new(move |py: Python| {
3131
let result = future.wait();
32-
then(py, result).map(PythonObject::into_object)
32+
then(py, result).map(|o| o.into_py_object(py).into_object())
3333
}))))
3434
}
3535
}

src/session.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use futures;
66

77
use pyfuture::PyFuture;
88
use player::Player;
9+
use metadata::{Track, Album, Artist};
10+
use SpotifyId;
911

1012
py_class!(pub class Session |py| {
1113
data session : librespot::session::Session;
@@ -40,4 +42,25 @@ py_class!(pub class Session |py| {
4042

4143
Player::new(py, session)
4244
}
45+
46+
def get_track(&self, track: SpotifyId) -> PyResult<PyFuture> {
47+
let session = self.session(py).clone();
48+
let track = *track.id(py);
49+
50+
Track::get(py, session, track)
51+
}
52+
53+
def get_album(&self, album: SpotifyId) -> PyResult<PyFuture> {
54+
let session = self.session(py).clone();
55+
let album = *album.id(py);
56+
57+
Album::get(py, session, album)
58+
}
59+
60+
def get_artist(&self, artist: SpotifyId) -> PyResult<PyFuture> {
61+
let session = self.session(py).clone();
62+
let artist = *artist.id(py);
63+
64+
Artist::get(py, session, artist)
65+
}
4366
});

0 commit comments

Comments
 (0)