This commit is contained in:
JMARyA 2024-10-07 15:50:46 +02:00
parent 70d45e42a8
commit d309c5d8c1
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
3 changed files with 59 additions and 2 deletions

View file

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use sqlx::prelude::FromRow; use sqlx::prelude::FromRow;
use std::str::FromStr; use std::{io::Read, str::FromStr};
use crate::{ use crate::{
get_pg, get_pg,
@ -325,6 +325,47 @@ impl Track {
.unwrap() .unwrap()
} }
pub async fn get_lyrics(&self) -> Option<serde_json::Value> {
let base_path = std::path::Path::new(&self.path).with_extension("");
let extensions = vec!["lrc", "txt"];
for ext in &extensions {
let candidate = base_path.with_extension(ext);
if candidate.exists() {
if let Ok(mut file) = std::fs::File::open(&candidate) {
let mut contents = String::new();
if file.read_to_string(&mut contents).is_ok() {
// Determine if it's timed lyrics or plain text
let lyrics_type = if ext == &"lrc" { "timed" } else { "plain" };
return Some(json!({
"lyrics": contents,
"source": "file",
"type": lyrics_type
}));
}
}
}
}
if let Some(lyrics) = self.meta.as_ref()?.get("lyrics").and_then(|l| l.as_str()) {
// Check if lyrics seem to be timed or plain text
let lyrics_type = if lyrics.contains('[') && lyrics.contains(']') {
"timed" // A rough check for LRC-style brackets indicating timing
} else {
"plain"
};
return Some(json!({
"lyrics": lyrics,
"type": lyrics_type
}));
}
// No lyrics found
None
}
/// Finds the first track of a given album. /// Finds the first track of a given album.
pub async fn find_first_of_album(album: &uuid::Uuid) -> Option<Self> { pub async fn find_first_of_album(album: &uuid::Uuid) -> Option<Self> {
sqlx::query_as("SELECT * FROM track WHERE album = $1 LIMIT 1") sqlx::query_as("SELECT * FROM track WHERE album = $1 LIMIT 1")

View file

@ -90,7 +90,8 @@ async fn rocket() -> _ {
route::admin::get_orphans_route, route::admin::get_orphans_route,
route::admin::get_singles_route, route::admin::get_singles_route,
route::event::event_report_route, route::event::event_report_route,
route::search::search_route route::search::search_route,
route::track::track_lyrics_route
], ],
) )
.manage(lib) .manage(lib)

View file

@ -1,6 +1,7 @@
use std::str::FromStr; use std::str::FromStr;
use super::api_error; use super::api_error;
use super::no_uuid_error;
use super::to_uuid; use super::to_uuid;
use super::FallibleApiResponse; use super::FallibleApiResponse;
use super::ToAPI; use super::ToAPI;
@ -60,3 +61,17 @@ pub async fn track_audio_aac128_route(track_id: &str, lib: &State<Libary>) -> Op
.await?; .await?;
NamedFile::open(track.get_aac(128)?).await.ok() NamedFile::open(track.get_aac(128)?).await.ok()
} }
#[get("/track/<track_id>/lyrics")]
pub async fn track_lyrics_route(track_id: &str, lib: &State<Libary>) -> FallibleApiResponse {
let track = lib
.get_track_by_id(&uuid::Uuid::from_str(track_id).map_err(|_| no_uuid_error())?)
.await
.ok_or_else(|| api_error("No such track"))?;
if let Some(lyrics) = track.get_lyrics().await {
return Ok(lyrics);
}
Ok(json!({}))
}