Implemented last fm endpoints

This commit is contained in:
Antoine Gersant 2018-10-28 17:05:14 -07:00
parent 4af2c0f09e
commit c25dc8155f
2 changed files with 98 additions and 20 deletions

View file

@ -249,7 +249,7 @@ fn get_endpoints(db: &Arc<DB>, index_channel: &Arc<index::CommandSender>) -> Mou
lastfm_router.get(
"/scrobble",
move |request: &mut Request| self::lastfm_scrobble(request, scrobble_db.deref()),
"auth",
"scrobble",
);
auth_api_mount.mount("/lastfm/", lastfm_router);

View file

@ -1,16 +1,19 @@
use rocket::http::{Cookie, Cookies, RawStr, Status};
use rocket::request::{self, FromParam, FromRequest, Request};
use rocket::response::content::Html;
use rocket::{Outcome, State};
use rocket_contrib::json::Json;
use std::fs::File;
use std::path::PathBuf;
use std::ops::Deref;
use std::path::PathBuf;
use std::str;
use std::sync::Arc;
use config::{self, Config, Preferences};
use db::DB;
use errors;
use index;
use lastfm;
use playlist;
use serve;
use thumbnails;
@ -45,6 +48,10 @@ pub fn get_routes() -> Vec<rocket::Route> {
save_playlist,
read_playlist,
delete_playlist,
lastfm_link,
lastfm_unlink,
lastfm_now_playing,
lastfm_scrobble,
]
}
@ -97,18 +104,18 @@ struct VFSPathBuf {
impl<'r> FromParam<'r> for VFSPathBuf {
type Error = &'r RawStr;
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
let decoded_path = param.percent_decode_lossy();
Ok(VFSPathBuf{
path_buf: PathBuf::from(decoded_path.into_owned())
Ok(VFSPathBuf {
path_buf: PathBuf::from(decoded_path.into_owned()),
})
}
}
}
impl From<VFSPathBuf> for PathBuf {
fn from(vfs_path_buf: VFSPathBuf) -> Self {
vfs_path_buf.path_buf.clone()
}
fn from(vfs_path_buf: VFSPathBuf) -> Self {
vfs_path_buf.path_buf.clone()
}
}
#[derive(Serialize)]
@ -198,10 +205,11 @@ fn auth(
mut cookies: Cookies,
) -> Result<Json<AuthOutput>, errors::Error> {
user::auth::<DB>(&db, &credentials.username, &credentials.password)?;
cookies.add_private(Cookie::new(
SESSION_FIELD_USERNAME,
credentials.username.clone(),
));
cookies.add_private(
Cookie::build(SESSION_FIELD_USERNAME, credentials.username.clone())
.same_site(rocket::http::SameSite::Lax)
.finish(),
);
let auth_output = AuthOutput {
admin: user::is_admin::<DB>(&db, &credentials.username)?,
@ -257,19 +265,30 @@ fn recent(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::Directory>>, err
}
#[get("/search")]
fn search_root(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
fn search_root(
db: State<DB>,
_auth: Auth,
) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::search(db.deref(), "")?;
Ok(Json(result))
}
#[get("/search/<query>")]
fn search(db: State<DB>, _auth: Auth, query: String) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
fn search(
db: State<DB>,
_auth: Auth,
query: String,
) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::search(db.deref(), &query)?;
Ok(Json(result))
}
#[get("/serve/<path>")]
fn serve(db: State<DB>, _auth: Auth, path: VFSPathBuf) -> Result<serve::RangeResponder<File>, errors::Error> {
fn serve(
db: State<DB>,
_auth: Auth,
path: VFSPathBuf,
) -> Result<serve::RangeResponder<File>, errors::Error> {
let db: &DB = db.deref();
let vfs = db.get_vfs()?;
let real_path = vfs.virtual_to_real(&path.into() as &PathBuf)?;
@ -290,8 +309,10 @@ struct ListPlaylistsEntry {
}
#[get("/playlists")]
fn list_playlists(db: State<DB>, auth: Auth) -> Result<Json<Vec<ListPlaylistsEntry>>, errors::Error> {
fn list_playlists(
db: State<DB>,
auth: Auth,
) -> Result<Json<Vec<ListPlaylistsEntry>>, errors::Error> {
let playlist_names = playlist::list_playlists(&auth.username, db.deref())?;
let playlists: Vec<ListPlaylistsEntry> = playlist_names
.into_iter()
@ -307,13 +328,22 @@ struct SavePlaylistInput {
}
#[put("/playlist/<name>", data = "<playlist>")]
fn save_playlist(db: State<DB>, auth: Auth, name: String, playlist: Json<SavePlaylistInput>) -> Result<(), errors::Error> {
fn save_playlist(
db: State<DB>,
auth: Auth,
name: String,
playlist: Json<SavePlaylistInput>,
) -> Result<(), errors::Error> {
playlist::save_playlist(&name, &auth.username, &playlist.tracks, db.deref())?;
Ok(())
}
#[get("/playlist/<name>")]
fn read_playlist(db: State<DB>, auth: Auth, name: String) -> Result<Json<Vec<index::Song>>, errors::Error> {
fn read_playlist(
db: State<DB>,
auth: Auth,
name: String,
) -> Result<Json<Vec<index::Song>>, errors::Error> {
let songs = playlist::read_playlist(&name, &auth.username, db.deref())?;
Ok(Json(songs))
}
@ -323,3 +353,51 @@ fn delete_playlist(db: State<DB>, auth: Auth, name: String) -> Result<(), errors
playlist::delete_playlist(&name, &auth.username, db.deref())?;
Ok(())
}
#[put("/lastfm/now_playing/<path>")]
fn lastfm_now_playing(db: State<DB>, auth: Auth, path: VFSPathBuf) -> Result<(), errors::Error> {
lastfm::now_playing(db.deref(), &auth.username, &path.into() as &PathBuf)?;
Ok(())
}
#[post("/lastfm/scrobble/<path>")]
fn lastfm_scrobble(db: State<DB>, auth: Auth, path: VFSPathBuf) -> Result<(), errors::Error> {
lastfm::scrobble(db.deref(), &auth.username, &path.into() as &PathBuf)?;
Ok(())
}
#[get("/lastfm/link?<token>&<content>")]
fn lastfm_link(
db: State<DB>,
auth: Auth,
token: String,
content: String,
) -> Result<Html<String>, errors::Error> {
lastfm::link(db.deref(), &auth.username, &token)?;
// Percent decode
let base64_content = match RawStr::from_str(&content).percent_decode() {
Ok(s) => s,
Err(_) => return Err(errors::Error::from(errors::ErrorKind::EncodingError).into()),
};
// Base64 decode
let popup_content = match base64::decode(base64_content.as_bytes()) {
Ok(c) => c,
Err(_) => return Err(errors::Error::from(errors::ErrorKind::EncodingError).into()),
};
// UTF-8 decode
let popup_content_string = match str::from_utf8(&popup_content) {
Ok(s) => s,
Err(_) => return Err(errors::Error::from(errors::ErrorKind::EncodingError).into()),
};
Ok(Html(popup_content_string.to_string()))
}
#[delete("/lastfm/link")]
fn lastfm_unlink(db: State<DB>, auth: Auth) -> Result<(), errors::Error> {
lastfm::unlink(db.deref(), &auth.username)?;
Ok(())
}