main image selections

This commit is contained in:
nvrl committed 2026-04-26 22:38:07 +02:00
1 parent caf3830d72
commit 466d0a0f9f
7 files changed
+153 -80

No files matched your search

@@ -1,5 +1,7 @@
import hashlib
import json
import os
from urllib.parse import urlparse
import requests
from django.conf import settings
@@ -13,29 +15,26 @@ class Command(BaseCommand):
help = "Adds legacy flavors from JSON files in the legacy/ folder"
def download_image(self, url, flavor_name):
"""Download legacy image into flavors/legacy_<slug>/00_<hash>.<ext>. Returns rel path."""
if not url:
return None
try:
safe_name = slugify(flavor_name)
ext = url.split(".")[-1].split("?")[0].lower()
if ext not in ["jpg", "jpeg", "png", "webp", "gif"]:
path = urlparse(url).path
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
if ext not in ("jpg", "jpeg", "png", "webp", "gif"):
ext = "png"
filename = f"legacy_{safe_name}.{ext}"
filepath = os.path.join(settings.MEDIA_ROOT, "flavors", filename)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
url_hash = hashlib.sha1(path.encode("utf-8")).hexdigest()[:10]
rel_path = os.path.join("flavors", f"legacy_{safe_name}", f"00_{url_hash}.{ext}")
abs_path = os.path.join(settings.MEDIA_ROOT, rel_path)
if os.path.exists(abs_path) and os.path.getsize(abs_path) > 0:
return rel_path
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
response.raise_for_status()
if os.path.exists(filepath):
os.remove(filepath)
with open(filepath, "wb") as f:
with open(abs_path, "wb") as f:
f.write(response.content)
return f"flavors/{filename}"
return rel_path
except Exception as e:
self.stdout.write(
self.style.WARNING(f"Failed to download image for {flavor_name}: {e}")
@@ -146,21 +145,18 @@ class Command(BaseCommand):
flavor.is_available = False # Legacy is always unavailable via API
if image_url:
# Check if local file exists
file_exists = False
if flavor.image:
abs_path = os.path.join(settings.MEDIA_ROOT, flavor.image.name)
if os.path.exists(abs_path):
file_exists = True
# Download if missing OR if image_url changed
if not file_exists or flavor.image_url != image_url:
rel_path = self.download_image(image_url, name)
if rel_path:
flavor.image = rel_path
self.stdout.write(f" -> Updated image for: {name}")
rel_path = self.download_image(image_url, name)
if rel_path:
flavor.local_image_paths = [rel_path]
if (
flavor.main_image_path
and flavor.main_image_path not in flavor.local_image_paths
):
flavor.main_image_path = None
self.stdout.write(f" -> Image for: {name}")
flavor.image_url = image_url
flavor.image_urls = [image_url] if image_url else []
flavor.save()
processed_count += 1
+46 -46
View File
@@ -1,10 +1,11 @@
import hashlib
import os
import re
from urllib.parse import urlparse
import requests
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils.text import slugify
from api.models import Category, Flavor
@@ -19,36 +20,48 @@ class Command(BaseCommand):
cleantext = re.sub(cleanr, "", raw_html)
return cleantext.strip()
def download_image(self, url, flavor_name):
def download_image_to_path(self, url, rel_path):
"""Download `url` to MEDIA_ROOT/rel_path. Skip if file already exists. Returns rel_path or None."""
if not url:
return None
abs_path = os.path.join(settings.MEDIA_ROOT, rel_path)
if os.path.exists(abs_path) and os.path.getsize(abs_path) > 0:
return rel_path
try:
safe_name = slugify(flavor_name)
ext = url.split(".")[-1].split("?")[0].lower()
if ext not in ["jpg", "jpeg", "png", "webp", "gif"]:
ext = "png"
filename = f"{safe_name}.{ext}"
filepath = os.path.join(settings.MEDIA_ROOT, "flavors", filename)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
response.raise_for_status()
if os.path.exists(filepath):
os.remove(filepath)
with open(filepath, "wb") as f:
with open(abs_path, "wb") as f:
f.write(response.content)
return f"flavors/{filename}"
return rel_path
except Exception as e:
self.stdout.write(
self.style.WARNING(f"Failed to download image for {flavor_name}: {e}")
)
self.stdout.write(self.style.WARNING(f"Failed to download {url}: {e}"))
return None
@staticmethod
def _ext_for(url):
path = urlparse(url).path
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
return ext if ext in ("jpg", "jpeg", "png", "webp", "gif") else "png"
@staticmethod
def _hash_for(url):
path = urlparse(url).path
return hashlib.sha1(path.encode("utf-8")).hexdigest()[:10]
def download_gallery(self, image_urls, dir_slug):
"""Download every URL into flavors/<dir_slug>/<i>_<hash>.<ext>. Returns list of rel paths."""
paths = []
for i, url in enumerate(image_urls):
if not url:
continue
filename = f"{i:02d}_{self._hash_for(url)}.{self._ext_for(url)}"
rel = os.path.join("flavors", dir_slug, filename)
saved = self.download_image_to_path(url, rel)
if saved:
paths.append(saved)
return paths
def handle(self, *args, **options):
url = "https://weareholy.com/products.json?limit=250"
self.stdout.write(f"Fetching from {url}...")
@@ -143,12 +156,10 @@ class Command(BaseCommand):
if not flavor:
# 2. Try exact name match in category
# REMOVED: is_legacy=False
flavor = Flavor.objects.filter(name=title, category=category).first()
if not flavor:
# 3. Try case-insensitive name match in category (safety for whitespace/case)
# REMOVED: is_legacy=False
flavor = Flavor.objects.filter(name__iexact=title, category=category).first()
if not flavor:
@@ -156,15 +167,11 @@ class Command(BaseCommand):
created_count += 1
else:
updated_count += 1
# Ensure external_id is updated if it was missing
if not flavor.external_id:
flavor.external_id = p["id"]
# Reactivate the flavor if it was previously marked as legacy
if flavor.is_legacy:
flavor.is_legacy = False
# Ensure all synced fields are accurately reflected
if (
flavor.name != title
and not Flavor.objects.filter(name=title, category=category)
@@ -177,24 +184,17 @@ class Command(BaseCommand):
flavor.shop_url = shop_url
flavor.is_available = is_available
if image_url:
# Check if local file exists
file_exists = False
if flavor.image:
abs_path = os.path.join(settings.MEDIA_ROOT, flavor.image.name)
if os.path.exists(abs_path):
file_exists = True
# Download if missing or URL changed
if not file_exists or flavor.image_url != image_url:
rel_path = self.download_image(image_url, title)
if rel_path:
flavor.image = rel_path
self.stdout.write(f"Downloaded image for: {title}")
else:
self.stdout.write(
self.style.WARNING(f"Failed to ensure image for: {title}")
)
# Download whole gallery into flavors/<external_id>/
dir_slug = str(p["id"])
local_paths = self.download_gallery(image_urls_list, dir_slug)
if local_paths:
flavor.local_image_paths = local_paths
# Drop main_image_path if it points to a file no longer in the gallery
if flavor.main_image_path and flavor.main_image_path not in local_paths:
flavor.main_image_path = None
elif not flavor.local_image_paths:
# No new paths and nothing previously stored — leave both empty
flavor.main_image_path = None
flavor.image_url = image_url
flavor.image_urls = image_urls_list