sort of working, more changes
This commit is contained in:
@ -1,21 +1,38 @@
|
||||
# plugins/media/utils.py
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from PIL import Image
|
||||
from flask import current_app, url_for
|
||||
from app import db
|
||||
from .models import Media
|
||||
from plugins.plant.models import Plant
|
||||
|
||||
|
||||
def get_upload_path():
|
||||
"""
|
||||
Return (full_disk_path, subdir) based on UTC date,
|
||||
creating directories if needed.
|
||||
e.g. ('/app/static/uploads/2025/06/09', '2025/06/09')
|
||||
"""
|
||||
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||
now = datetime.utcnow()
|
||||
subdir = os.path.join(str(now.year), f"{now.month:02}", f"{now.day:02}")
|
||||
full = os.path.join(base, subdir)
|
||||
os.makedirs(full, exist_ok=True)
|
||||
return full, subdir
|
||||
|
||||
|
||||
def generate_random_filename(original_filename):
|
||||
"""
|
||||
Returns a random filename preserving the original extension.
|
||||
e.g. “abcd1234efgh.jpg” for “myphoto.jpg”.
|
||||
Preserve extension, randomize base name.
|
||||
"""
|
||||
ext = os.path.splitext(original_filename)[1].lower() # includes dot, e.g. ".jpg"
|
||||
random_name = uuid.uuid4().hex # 32‐char hex string
|
||||
return f"{random_name}{ext}"
|
||||
ext = os.path.splitext(original_filename)[1].lower()
|
||||
return f"{uuid.uuid4().hex}{ext}"
|
||||
|
||||
|
||||
def strip_metadata_and_save(source_file, destination_path):
|
||||
"""
|
||||
Opens an image with Pillow, strips EXIF (metadata), and saves it cleanly.
|
||||
Opens an image with Pillow, strips EXIF metadata, and saves it.
|
||||
Supports common formats (JPEG, PNG).
|
||||
"""
|
||||
with Image.open(source_file) as img:
|
||||
@ -23,3 +40,72 @@ def strip_metadata_and_save(source_file, destination_path):
|
||||
clean_image = Image.new(img.mode, img.size)
|
||||
clean_image.putdata(data)
|
||||
clean_image.save(destination_path)
|
||||
|
||||
|
||||
def generate_image_url(path):
|
||||
"""
|
||||
If path is set, route through /media/files/<path>; otherwise
|
||||
return a placehold.co URL sized to STANDARD_IMG_SIZE.
|
||||
"""
|
||||
if path:
|
||||
return url_for("media.media_file", filename=path)
|
||||
w, h = current_app.config.get("STANDARD_IMG_SIZE", (300, 200))
|
||||
return f"https://placehold.co/{w}x{h}"
|
||||
|
||||
|
||||
def save_media_file(file_storage, uploader_id, related_model=None, related_uuid=None):
|
||||
"""
|
||||
- file_storage: Werkzeug FileStorage
|
||||
- uploader_id: current_user.id
|
||||
- related_model: e.g. 'plant'
|
||||
- related_uuid: the Plant.uuid string
|
||||
Returns the new Media instance.
|
||||
"""
|
||||
full_path, subdir = get_upload_path()
|
||||
filename = generate_random_filename(file_storage.filename)
|
||||
disk_path = os.path.join(full_path, filename)
|
||||
file_storage.save(disk_path)
|
||||
|
||||
media = Media(
|
||||
file_url=os.path.join(subdir, filename).replace("\\", "/"),
|
||||
uploader_id=uploader_id
|
||||
)
|
||||
|
||||
# Associate to plant if requested
|
||||
if related_model == "plant" and related_uuid:
|
||||
plant = Plant.query.filter_by(uuid=related_uuid).first()
|
||||
if plant:
|
||||
media.plant_id = plant.id
|
||||
|
||||
db.session.add(media)
|
||||
db.session.commit()
|
||||
return media
|
||||
|
||||
|
||||
def delete_media_file(media):
|
||||
"""
|
||||
Remove file from disk and delete DB record.
|
||||
"""
|
||||
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||
path = os.path.join(base, media.file_url)
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass
|
||||
db.session.delete(media)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def rotate_media_file(media, angle=-90):
|
||||
"""
|
||||
Rotate the file on disk (in place) and leave DB record intact.
|
||||
"""
|
||||
base = current_app.config.get("UPLOAD_FOLDER", "static/uploads")
|
||||
path = os.path.join(base, media.file_url)
|
||||
try:
|
||||
with Image.open(path) as img:
|
||||
rotated = img.rotate(angle, expand=True)
|
||||
rotated.save(path)
|
||||
except Exception:
|
||||
pass
|
||||
# no DB changes needed
|
||||
|
Reference in New Issue
Block a user