mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Enhance Calibre OPDS integration to extract and handle tags, ratings, and publication dates from metadata
This commit is contained in:
@@ -2922,6 +2922,16 @@ def calibre_opds_import() -> ResponseReturnValue:
|
||||
metadata_payload = data.get("metadata") if isinstance(data, Mapping) else None
|
||||
metadata_overrides: Dict[str, Any] = {}
|
||||
if isinstance(metadata_payload, Mapping):
|
||||
def _stringify_metadata_value(value: Any) -> str:
|
||||
if value is None:
|
||||
return ""
|
||||
if isinstance(value, (list, tuple, set)):
|
||||
parts = [str(item).strip() for item in value if item is not None]
|
||||
parts = [part for part in parts if part]
|
||||
return ", ".join(parts)
|
||||
text = str(value).strip()
|
||||
return text
|
||||
|
||||
raw_series = metadata_payload.get("series") or metadata_payload.get("series_name")
|
||||
series_name = str(raw_series or "").strip()
|
||||
if series_name:
|
||||
@@ -2940,6 +2950,48 @@ def calibre_opds_import() -> ResponseReturnValue:
|
||||
metadata_overrides.setdefault("series_position", series_index_text)
|
||||
metadata_overrides.setdefault("series_sequence", series_index_text)
|
||||
metadata_overrides.setdefault("book_number", series_index_text)
|
||||
tags_value = metadata_payload.get("tags") or metadata_payload.get("keywords")
|
||||
if tags_value:
|
||||
tags_text = _stringify_metadata_value(tags_value)
|
||||
if tags_text:
|
||||
metadata_overrides.setdefault("tags", tags_text)
|
||||
metadata_overrides.setdefault("keywords", tags_text)
|
||||
metadata_overrides.setdefault("genre", tags_text)
|
||||
description_value = metadata_payload.get("description") or metadata_payload.get("summary")
|
||||
if description_value:
|
||||
description_text = _stringify_metadata_value(description_value)
|
||||
if description_text:
|
||||
metadata_overrides.setdefault("description", description_text)
|
||||
metadata_overrides.setdefault("summary", description_text)
|
||||
published_value = metadata_payload.get("published") or metadata_payload.get("publication_date")
|
||||
if published_value:
|
||||
published_text = _stringify_metadata_value(published_value)
|
||||
if published_text:
|
||||
metadata_overrides.setdefault("published", published_text)
|
||||
metadata_overrides.setdefault("publication_date", published_text)
|
||||
publication_year = metadata_payload.get("publication_year") or metadata_payload.get("year")
|
||||
if publication_year:
|
||||
year_text = _stringify_metadata_value(publication_year)
|
||||
if year_text:
|
||||
metadata_overrides.setdefault("publication_year", year_text)
|
||||
metadata_overrides.setdefault("year", year_text)
|
||||
rating_value = metadata_payload.get("rating")
|
||||
if rating_value is not None:
|
||||
rating_text = _stringify_metadata_value(rating_value)
|
||||
if rating_text:
|
||||
metadata_overrides.setdefault("rating", rating_text)
|
||||
rating_max = metadata_payload.get("rating_max")
|
||||
if rating_max is not None:
|
||||
rating_max_text = _stringify_metadata_value(rating_max)
|
||||
if rating_max_text:
|
||||
metadata_overrides.setdefault("rating_max", rating_max_text)
|
||||
for key, value in metadata_payload.items():
|
||||
if value is None:
|
||||
continue
|
||||
text_value = _stringify_metadata_value(value)
|
||||
if not text_value:
|
||||
continue
|
||||
metadata_overrides.setdefault(str(key), text_value)
|
||||
|
||||
stored_settings = _stored_integration_config("calibre_opds")
|
||||
if not stored_settings or not _coerce_bool(stored_settings.get("enabled"), False):
|
||||
|
||||
@@ -355,6 +355,22 @@ def _build_audiobookshelf_metadata(job: Job) -> Dict[str, Any]:
|
||||
"seriesSequence": series_sequence,
|
||||
"isbn": _first_nonempty(tags.get("isbn"), tags.get("asin")),
|
||||
}
|
||||
published_date = _first_nonempty(tags.get("published"), tags.get("publication_date"), tags.get("date"))
|
||||
if published_date:
|
||||
data["publishedDate"] = published_date
|
||||
|
||||
rating_text = _first_nonempty(tags.get("rating"), tags.get("my_rating"))
|
||||
if rating_text:
|
||||
try:
|
||||
data["rating"] = float(str(rating_text).strip())
|
||||
except ValueError:
|
||||
pass
|
||||
rating_max_text = _first_nonempty(tags.get("rating_max"), tags.get("rating_scale"))
|
||||
if rating_max_text:
|
||||
try:
|
||||
data["ratingMax"] = float(str(rating_max_text).strip())
|
||||
except ValueError:
|
||||
pass
|
||||
# Remove empty values
|
||||
cleaned: Dict[str, Any] = {}
|
||||
for key, value in data.items():
|
||||
|
||||
@@ -314,6 +314,21 @@ if (modal && browser) {
|
||||
header.appendChild(seriesMeta);
|
||||
}
|
||||
|
||||
if (entry.rating !== null && entry.rating !== undefined && entry.rating !== '') {
|
||||
const ratingMeta = document.createElement('p');
|
||||
ratingMeta.className = 'opds-browser__meta';
|
||||
const ratingMax = entry.rating_max ?? entry.ratingMax ?? 5;
|
||||
ratingMeta.textContent = `Rating: ${entry.rating}${ratingMax ? ` / ${ratingMax}` : ''}`;
|
||||
header.appendChild(ratingMeta);
|
||||
}
|
||||
|
||||
if (Array.isArray(entry.tags) && entry.tags.length > 0) {
|
||||
const tagsMeta = document.createElement('p');
|
||||
tagsMeta.className = 'opds-browser__meta';
|
||||
tagsMeta.textContent = `Tags: ${entry.tags.join(', ')}`;
|
||||
header.appendChild(tagsMeta);
|
||||
}
|
||||
|
||||
item.appendChild(header);
|
||||
|
||||
const summarySource = entry.summary || entry?.alternate?.title || entry?.download?.title || '';
|
||||
@@ -436,6 +451,36 @@ if (modal && browser) {
|
||||
metadata.series_position = seriesIndex;
|
||||
metadata.book_number = seriesIndex;
|
||||
}
|
||||
if (Array.isArray(entry.tags) && entry.tags.length > 0) {
|
||||
const tagsText = entry.tags.join(', ');
|
||||
metadata.tags = tagsText;
|
||||
metadata.keywords = tagsText;
|
||||
metadata.genre = tagsText;
|
||||
}
|
||||
if (typeof entry.summary === 'string' && entry.summary.trim()) {
|
||||
metadata.description = entry.summary;
|
||||
metadata.summary = entry.summary;
|
||||
}
|
||||
if (entry.rating !== null && entry.rating !== undefined && entry.rating !== '') {
|
||||
metadata.rating = String(entry.rating);
|
||||
}
|
||||
if (entry.rating_max !== null && entry.rating_max !== undefined && entry.rating_max !== '') {
|
||||
metadata.rating_max = String(entry.rating_max);
|
||||
}
|
||||
if (entry.published) {
|
||||
metadata.published = entry.published;
|
||||
metadata.publication_date = entry.published;
|
||||
try {
|
||||
const publishedDate = new Date(entry.published);
|
||||
if (!Number.isNaN(publishedDate.getTime())) {
|
||||
const year = String(publishedDate.getUTCFullYear());
|
||||
metadata.publication_year = year;
|
||||
metadata.year = year;
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore invalid date parsing issues
|
||||
}
|
||||
}
|
||||
if (Object.keys(metadata).length > 0) {
|
||||
requestPayload.metadata = metadata;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user