normalize queries

This commit is contained in:
Simon
2026-03-16 19:46:00 +00:00
parent 9751c25b95
commit f8a09b0e97

View File

@@ -83,6 +83,53 @@ impl Ord for ClientVersion {
} }
} }
fn normalize_query(raw_query: Option<&str>) -> (Option<String>, Option<String>) {
let Some(raw_query) = raw_query else {
return (None, None);
};
let mut query = raw_query.trim();
if query.is_empty() {
return (None, None);
}
while let Some(stripped) = query.strip_prefix('#') {
query = stripped.trim_start();
}
if query.is_empty() {
return (None, None);
}
let literal_query = if query.len() >= 2
&& ((query.starts_with('"') && query.ends_with('"'))
|| (query.starts_with('\'') && query.ends_with('\'')))
{
let inner = query[1..query.len() - 1].trim();
if inner.is_empty() {
None
} else {
query = inner;
Some(inner.to_ascii_lowercase())
}
} else {
None
};
(Some(query.to_string()), literal_query)
}
fn video_matches_literal_query(video: &VideoItem, literal_query: &str) -> bool {
let contains_literal = |value: &str| value.to_ascii_lowercase().contains(literal_query);
contains_literal(&video.title)
|| video.uploader.as_deref().is_some_and(contains_literal)
|| video
.tags
.as_ref()
.is_some_and(|tags| tags.iter().any(|tag| contains_literal(tag)))
}
pub fn config(cfg: &mut web::ServiceConfig) { pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service( cfg.service(
web::resource("/status") web::resource("/status")
@@ -145,7 +192,7 @@ async fn status(req: HttpRequest) -> Result<impl web::Responder, web::Error> {
} }
async fn videos_post( async fn videos_post(
mut video_request: web::types::Json<VideosRequest>, video_request: web::types::Json<VideosRequest>,
cache: web::types::State<VideoCache>, cache: web::types::State<VideoCache>,
pool: web::types::State<DbPool>, pool: web::types::State<DbPool>,
requester: web::types::State<Requester>, requester: web::types::State<Requester>,
@@ -159,12 +206,6 @@ async fn videos_post(
}, },
_ => ClientVersion::new(999, 0, "Hot%20Tub".to_string()), _ => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
}; };
match video_request.query.as_deref() {
Some(query) if query.starts_with("#") => {
video_request.query = Some(query.trim_start_matches("#").to_string());
}
_ => {}
}
let requester = requester.get_ref().clone(); let requester = requester.get_ref().clone();
// Ensure "videos" table exists with two string columns. // Ensure "videos" table exists with two string columns.
match pool.get() { match pool.get() {
@@ -200,10 +241,7 @@ async fn videos_post(
.unwrap_or("all") .unwrap_or("all")
.to_string(); .to_string();
let sort: String = video_request.sort.as_deref().unwrap_or("date").to_string(); let sort: String = video_request.sort.as_deref().unwrap_or("date").to_string();
let mut query: Option<String> = video_request.query.clone(); let (query, literal_query) = normalize_query(video_request.query.as_deref());
if video_request.query.as_deref() == Some("") {
query = None;
}
let page: u8 = video_request let page: u8 = video_request
.page .page
.as_ref() .as_ref()
@@ -306,6 +344,10 @@ async fn videos_post(
.collect(); .collect();
} }
if let Some(literal_query) = literal_query.as_deref() {
video_items.retain(|video| video_matches_literal_query(video, literal_query));
}
videos.items = video_items.clone(); videos.items = video_items.clone();
if video_items.len() == 0 { if video_items.len() == 0 {
videos.pageInfo = PageInfo { videos.pageInfo = PageInfo {