mirror of
https://github.com/agersant/polaris
synced 2024-12-02 09:39:09 +00:00
Implemented last fm endpoints
This commit is contained in:
parent
4af2c0f09e
commit
c25dc8155f
2 changed files with 98 additions and 20 deletions
|
@ -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);
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue