feat: add configurable status mappings for metadata providers
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6s
Add a status_mappings table to replace hardcoded provider status normalization. Users can now configure how provider statuses (e.g. "releasing", "finie") map to target statuses (e.g. "ongoing", "ended") via the Settings > Integrations page. - Migration 0038: status_mappings table with pre-seeded mappings - Migration 0039: re-normalize existing series_metadata.status values - API: CRUD endpoints for status mappings, DB-based normalize function - API: new GET /series/provider-statuses endpoint - Backoffice: StatusMappingsCard component with create target, assign, and delete capabilities - Fix all clippy warnings across the API crate - Fix missing OpenAPI schema refs (MetadataStats, ProviderCount) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -497,6 +497,13 @@ async fn get_series_books_impl(
|
||||
}))
|
||||
.collect();
|
||||
|
||||
static RE_TOME: std::sync::LazyLock<regex::Regex> =
|
||||
std::sync::LazyLock::new(|| regex::Regex::new(r"(?i)-Tome-\d+-").unwrap());
|
||||
static RE_BOOK_ID: std::sync::LazyLock<regex::Regex> =
|
||||
std::sync::LazyLock::new(|| regex::Regex::new(r"-(\d+)\.html").unwrap());
|
||||
static RE_VOLUME: std::sync::LazyLock<regex::Regex> =
|
||||
std::sync::LazyLock::new(|| regex::Regex::new(r"(?i)Tome-(\d+)-").unwrap());
|
||||
|
||||
for (idx, album_el) in doc.select(&album_sel).enumerate() {
|
||||
// Title from <a class="titre" title="..."> — the title attribute is clean
|
||||
let title_sel = Selector::parse("a.titre").ok();
|
||||
@@ -516,22 +523,18 @@ async fn get_series_books_impl(
|
||||
|
||||
// Only keep main tomes — their URLs contain "Tome-{N}-"
|
||||
// Skip hors-série (HS), intégrales (INT/INTFL), romans, coffrets, etc.
|
||||
if let Ok(re) = regex::Regex::new(r"(?i)-Tome-\d+-") {
|
||||
if !re.is_match(album_url) {
|
||||
continue;
|
||||
}
|
||||
if !RE_TOME.is_match(album_url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let external_book_id = regex::Regex::new(r"-(\d+)\.html")
|
||||
.ok()
|
||||
.and_then(|re| re.captures(album_url))
|
||||
let external_book_id = RE_BOOK_ID
|
||||
.captures(album_url)
|
||||
.map(|c| c[1].to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Volume number from URL pattern "Tome-{N}-" or from itemprop name
|
||||
let volume_number = regex::Regex::new(r"(?i)Tome-(\d+)-")
|
||||
.ok()
|
||||
.and_then(|re| re.captures(album_url))
|
||||
let volume_number = RE_VOLUME
|
||||
.captures(album_url)
|
||||
.and_then(|c| c[1].parse::<i32>().ok())
|
||||
.or_else(|| extract_volume_from_title(&title));
|
||||
|
||||
@@ -649,13 +652,13 @@ fn compute_confidence(title: &str, query: &str) -> f32 {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
if title_lower.starts_with(&query_lower) || query_lower.starts_with(&title_lower) {
|
||||
if title_lower.starts_with(&query_lower) || query_lower.starts_with(&title_lower)
|
||||
|| title_norm.starts_with(&query_norm) || query_norm.starts_with(&title_norm)
|
||||
{
|
||||
0.85
|
||||
} else if title_norm.starts_with(&query_norm) || query_norm.starts_with(&title_norm) {
|
||||
0.85
|
||||
} else if title_lower.contains(&query_lower) || query_lower.contains(&title_lower) {
|
||||
0.7
|
||||
} else if title_norm.contains(&query_norm) || query_norm.contains(&title_norm) {
|
||||
} else if title_lower.contains(&query_lower) || query_lower.contains(&title_lower)
|
||||
|| title_norm.contains(&query_norm) || query_norm.contains(&title_norm)
|
||||
{
|
||||
0.7
|
||||
} else {
|
||||
let common: usize = query_lower
|
||||
|
||||
Reference in New Issue
Block a user