Replace image pipeline with profile-driven variants
- add image normalization profiles and thumbnail profiles - generate source, full-size variant, and thumbnail image artifacts - rewrite canonical image URLs through the first configured profile - emit explicit image Media RSS groups with named thumbnails - preserve legacy image paths when image conversion is disabled - cover cache-hit source paths, inline image handling, and thumbnail export
This commit is contained in:
parent
7316d4723f
commit
525393272e
13 changed files with 1299 additions and 124 deletions
|
|
@ -43,6 +43,50 @@ def local_audio_path(s: str) -> str:
|
|||
return local_file_path(s)
|
||||
|
||||
|
||||
def image_guid(source_url: str) -> str:
|
||||
return hashlib.sha1(to_bytes(source_url)).hexdigest() # nosec
|
||||
|
||||
|
||||
def image_extension(mimetype_or_extension: str | None, source_url: str = "") -> str:
|
||||
if mimetype_or_extension:
|
||||
if mimetype_or_extension.startswith("."):
|
||||
extension = mimetype_or_extension
|
||||
elif "/" in mimetype_or_extension:
|
||||
extension = mimetypes.guess_extension(mimetype_or_extension) or ""
|
||||
else:
|
||||
extension = f".{mimetype_or_extension.lstrip('.')}"
|
||||
if extension == ".jpe":
|
||||
return ".jpg"
|
||||
return extension
|
||||
guessed = Path(source_url).suffix
|
||||
if guessed == ".jpe":
|
||||
return ".jpg"
|
||||
if guessed:
|
||||
return guessed
|
||||
return ".img"
|
||||
|
||||
|
||||
def source_image_path(source_url: str, mimetype_or_extension: str | None = None) -> str:
|
||||
extension = image_extension(mimetype_or_extension, source_url)
|
||||
return f"source/{image_guid(source_url)}{extension}"
|
||||
|
||||
|
||||
def published_image_path(source_url: str, profile: Mapping[str, Any]) -> str:
|
||||
return variant_media_path(f"full/{image_guid(source_url)}", profile, hashed=True)
|
||||
|
||||
|
||||
def canonical_published_image_path(
|
||||
source_url: str, profiles: Sequence[Mapping[str, Any]]
|
||||
) -> str:
|
||||
if not profiles:
|
||||
raise ValueError("Missing image normalization profiles")
|
||||
return published_image_path(source_url, profiles[0])
|
||||
|
||||
|
||||
def thumbnail_image_path(source_url: str, profile: Mapping[str, Any]) -> str:
|
||||
return variant_media_path(f"thumbs/{image_guid(source_url)}", profile, hashed=True)
|
||||
|
||||
|
||||
def profile_settings_hash(profile: Mapping[str, Any]) -> str:
|
||||
settings = {
|
||||
key: value
|
||||
|
|
@ -65,6 +109,8 @@ def variant_media_path(
|
|||
def published_media_path(
|
||||
file_type: FileType, source_url: str, profile: Mapping[str, Any]
|
||||
) -> str:
|
||||
if file_type == FileType.IMAGE:
|
||||
return published_image_path(source_url, profile)
|
||||
if file_type == FileType.AUDIO:
|
||||
return variant_media_path(local_audio_path(source_url), profile, hashed=True)
|
||||
if file_type == FileType.VIDEO:
|
||||
|
|
@ -79,6 +125,8 @@ def canonical_published_media_path(
|
|||
raise ValueError(f"Missing transcode profiles for {file_type.value}")
|
||||
# The first configured profile is the public URL contract. Reordering profiles
|
||||
# changes published URLs for already-mirrored media.
|
||||
if file_type == FileType.IMAGE:
|
||||
return canonical_published_image_path(source_url, profiles)
|
||||
return published_media_path(file_type, source_url, profiles[0])
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue