Files
moto-adv-website/app/utils/manage_media.py

188 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Media Management Utility for Motorcycle Adventure Community
This script provides utilities for managing post media files:
- Create missing media folders for existing posts
- Clean up orphaned media folders
- Migrate files from old structure to new structure
- Generate thumbnails for images
Usage:
python manage_media.py --help
"""
import os
import sys
import argparse
import shutil
from datetime import datetime
import uuid
# Add the app directory to the path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
from app import create_app
from app.models import Post, PostImage, GPXFile
from app.extensions import db
def create_missing_media_folders():
"""Create media folders for existing posts that don't have them"""
app = create_app()
with app.app_context():
posts_without_folders = Post.query.filter_by(media_folder=None).all()
print(f"Found {len(posts_without_folders)} posts without media folders")
for post in posts_without_folders:
# Generate a media folder name
folder_name = f"post_{uuid.uuid4().hex[:8]}_{post.created_at.strftime('%Y%m%d')}"
post.media_folder = folder_name
# Create the folder structure
media_path = os.path.join(app.root_path, 'static', 'media', 'posts', folder_name)
os.makedirs(os.path.join(media_path, 'images'), exist_ok=True)
os.makedirs(os.path.join(media_path, 'gpx'), exist_ok=True)
print(f"Created media folder for post {post.id}: {folder_name}")
db.session.commit()
print("Media folders created successfully!")
def migrate_old_files():
"""Migrate files from old upload structure to new media structure"""
app = create_app()
with app.app_context():
# Migrate images
old_images_path = os.path.join(app.instance_path, 'uploads', 'images')
if os.path.exists(old_images_path):
print("Migrating image files...")
for image in PostImage.query.all():
if image.post.media_folder:
old_path = os.path.join(old_images_path, image.filename)
new_path = os.path.join(app.root_path, 'static', 'media', 'posts',
image.post.media_folder, 'images', image.filename)
if os.path.exists(old_path) and not os.path.exists(new_path):
os.makedirs(os.path.dirname(new_path), exist_ok=True)
shutil.move(old_path, new_path)
print(f"Moved image: {image.filename}")
# Migrate GPX files
old_gpx_path = os.path.join(app.instance_path, 'uploads', 'gpx')
if os.path.exists(old_gpx_path):
print("Migrating GPX files...")
for gpx_file in GPXFile.query.all():
if gpx_file.post.media_folder:
old_path = os.path.join(old_gpx_path, gpx_file.filename)
new_path = os.path.join(app.root_path, 'static', 'media', 'posts',
gpx_file.post.media_folder, 'gpx', gpx_file.filename)
if os.path.exists(old_path) and not os.path.exists(new_path):
os.makedirs(os.path.dirname(new_path), exist_ok=True)
shutil.move(old_path, new_path)
print(f"Moved GPX file: {gpx_file.filename}")
print("File migration completed!")
def clean_orphaned_folders():
"""Remove media folders that don't have corresponding posts"""
app = create_app()
with app.app_context():
media_posts_path = os.path.join(app.root_path, 'static', 'media', 'posts')
if not os.path.exists(media_posts_path):
print("No media posts directory found")
return
# Get all folder names from database
used_folders = set(post.media_folder for post in Post.query.filter(Post.media_folder.isnot(None)).all())
# Get all actual folders
actual_folders = set(name for name in os.listdir(media_posts_path)
if os.path.isdir(os.path.join(media_posts_path, name)))
# Find orphaned folders
orphaned_folders = actual_folders - used_folders
if orphaned_folders:
print(f"Found {len(orphaned_folders)} orphaned folders:")
for folder in orphaned_folders:
folder_path = os.path.join(media_posts_path, folder)
print(f" {folder}")
# Ask for confirmation before deleting
response = input(f"Delete folder {folder}? (y/N): ")
if response.lower() == 'y':
shutil.rmtree(folder_path)
print(f" Deleted: {folder}")
else:
print(f" Skipped: {folder}")
else:
print("No orphaned folders found")
def show_media_stats():
"""Show statistics about media storage"""
app = create_app()
with app.app_context():
total_posts = Post.query.count()
posts_with_media_folders = Post.query.filter(Post.media_folder.isnot(None)).count()
total_images = PostImage.query.count()
total_gpx_files = GPXFile.query.count()
print("Media Storage Statistics:")
print(f" Total posts: {total_posts}")
print(f" Posts with media folders: {posts_with_media_folders}")
print(f" Posts without media folders: {total_posts - posts_with_media_folders}")
print(f" Total images: {total_images}")
print(f" Total GPX files: {total_gpx_files}")
# Calculate total storage used
media_posts_path = os.path.join(app.root_path, 'static', 'media', 'posts')
if os.path.exists(media_posts_path):
total_size = 0
for root, dirs, files in os.walk(media_posts_path):
for file in files:
file_path = os.path.join(root, file)
total_size += os.path.getsize(file_path)
print(f" Total storage used: {total_size / (1024*1024):.2f} MB")
def main():
parser = argparse.ArgumentParser(description='Media Management Utility')
parser.add_argument('--create-folders', action='store_true',
help='Create missing media folders for existing posts')
parser.add_argument('--migrate-files', action='store_true',
help='Migrate files from old structure to new structure')
parser.add_argument('--clean-orphaned', action='store_true',
help='Clean up orphaned media folders')
parser.add_argument('--stats', action='store_true',
help='Show media storage statistics')
parser.add_argument('--all', action='store_true',
help='Run all operations (create folders, migrate files)')
args = parser.parse_args()
if args.all:
create_missing_media_folders()
migrate_old_files()
elif args.create_folders:
create_missing_media_folders()
elif args.migrate_files:
migrate_old_files()
elif args.clean_orphaned:
clean_orphaned_folders()
elif args.stats:
show_media_stats()
else:
parser.print_help()
if __name__ == '__main__':
main()