1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#![warn(missing_docs)]
#![doc(html_root_url = "https://docs.rs/sunk/0.1.2")]

//! # sunk
//!
//! `sunk` provides natural Rust bindings to the [Subsonic] music server API.
//! Many other popular music servers, such as Libresonic and Airsonic, also use
//! the Subsonic API, so this crate can stretch far beyond just Subsonic.
//!
//! [Subsonic]: http://www.subsonic.org/pages/index.jsp
//!
//! # Basic usage
//!
//! ```no_run
//! extern crate sunk;
//! use sunk::song::Song;
//! use sunk::{Album, Artist, Client, Streamable};
//!
//! # fn run() -> sunk::Result<()> {
//! let site = "http://subsonic.example.com";
//! let username = "admin";
//! let password = "hunter2";
//!
//! let client = Client::new(site, username, password)?;
//!
//! let random_songs = Song::random(&client, 20)?;
//! for mut song in random_songs {
//!     song.set_max_bit_rate(320);
//!     let bytes = song.stream(&client)?;
//!     // Use another library to stream the `bytes`!
//! }
//! # Ok(())
//! # }
//! # fn main() { }
//! ```
//!
//! # Philosophy
//!
//! The fundamental principle behind the way `sunk` works is to be able to pivot
//! on everything. If you have something returned from a query, you should be
//! able to investigate that object more deeply. This is modelled after what
//! you'd typically expect from mobile or web clients.
//!
//! An example can be seen below:
//!
//! ```no_run
//! # extern crate sunk;
//! # use sunk::{Client, Album, Artist, Streamable};
//! # use sunk::song::Song;
//! # fn run() -> sunk::Result<()> {
//! # let site = "http://subsonic.example.com";
//! # let username = "admin";
//! # let password = "hunter2";
//! let client = Client::new(site, username, password)?;
//!
//! // I want to play some <insert artist here>.
//! let an_artist = Artist::get(&client, 20)?;
//! let artist_info = an_artist.info(&client)?;
//! let artists_albums = an_artist.albums(&client)?;
//!
//! // I love this album. Let's download it.
//! let ref fav_album = artists_albums[0];
//! let album_info_and_similar = fav_album.info(&client)?;
//! let album_songs = fav_album.songs(&client)?;
//!
//! use std::fs::File;
//! use std::io::Write;
//! for song in &album_songs {
//!     let bytes = song.download(&client)?;
//!     let mut file =
//!         File::create(song.title.clone() + "." + song.encoding())?;
//!     file.write(&bytes)?;
//! }
//!
//! // I want to find stuff like this song.
//! let ref this_is_good = album_songs[6];
//! let similar = this_is_good.similar(&client, 10)?;
//! # Ok(())
//! # }
//! # fn main() { }
//! ```
//!
//! This has the result of many methods requiring an active connection to a
//! `Client` to fetch more information.
//!
//! # Debugging
//!
//! The crate uses [`log`] as its debugging backend. If your crate uses log,
//! you'll see output from `sunk` at any information level starting at warning
//! (for critical processes) or info (for most other processes).
//!
//! [`log`]: https://doc.rust-lang.org/log/log/index.html
//!
//! # Development
//!
//! The crate is still under active development. Methods and paths may change,
//! and many have not been tested due to the requirement of having full access
//! to a Subsonic instance. See the repository for any changes and development
//! status.
//!
//! Bug reports and broken features are encouraged to be reported! **If
//! something does not work as reported, it's probably broken.**

#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate md5;
extern crate rand;
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
mod macros;
mod client;
mod error;

mod collections;
mod media;

mod annotate;
mod jukebox;
mod query;
mod response;
pub mod search;
mod user;
mod version;

#[cfg(test)]
mod test_util;

pub use self::client::Client;
pub use self::collections::Playlist;
pub use self::collections::{Album, AlbumInfo, ListType};
pub use self::collections::{Artist, ArtistInfo};
pub use self::collections::{Genre, MusicFolder};
pub use self::error::{ApiError, Error, Result, UrlError};
pub use self::jukebox::{Jukebox, JukeboxPlaylist, JukeboxStatus};
pub use self::media::{podcast, song, video};
pub use self::media::{Hls, HlsPlaylist, Media, NowPlaying, RadioStation, Streamable};
pub use self::user::{User, UserBuilder};
pub use self::version::Version;

use self::song::{Lyrics, RandomSongs, Song};
use self::video::Video;