245 lines
7.6 KiB
Python
245 lines
7.6 KiB
Python
from flask import Flask, render_template, send_file, jsonify
|
|
import os
|
|
import random
|
|
import json
|
|
|
|
app = Flask(__name__)
|
|
|
|
# Configuration for NASA data paths - using environment variables with defaults
|
|
METADATA_PATH = os.environ.get(
|
|
"NASA_METADATA_PATH", "/Volumes/MediaServer/Images/NASA/metadata"
|
|
)
|
|
IMAGES_PATH = os.environ.get(
|
|
"NASA_IMAGES_PATH", "/Volumes/MediaServer/Images/NASA/images"
|
|
)
|
|
SNAPSHOT_FILE = os.environ.get("SNAPSHOT_FILE", "./files_snapshot.txt")
|
|
|
|
# History tracking
|
|
image_history = []
|
|
MAX_HISTORY = 50
|
|
|
|
|
|
def load_snapshot():
|
|
"""Load the snapshot file to get all available image metadata files"""
|
|
try:
|
|
if not os.path.exists(SNAPSHOT_FILE):
|
|
return []
|
|
|
|
with open(SNAPSHOT_FILE, "r") as f:
|
|
lines = [line.strip() for line in f.readlines() if line.strip()]
|
|
return lines
|
|
except Exception as e:
|
|
print(f"Error loading snapshot: {e}")
|
|
return []
|
|
|
|
|
|
def get_random_image_metadata():
|
|
"""Get a random image from the snapshot"""
|
|
snapshot_files = load_snapshot()
|
|
if not snapshot_files:
|
|
return None
|
|
|
|
selected_file = random.choice(snapshot_files)
|
|
return selected_file
|
|
|
|
|
|
def get_image_data(metadata_filename):
|
|
"""Extract image data from metadata file"""
|
|
try:
|
|
# Construct full path to metadata file
|
|
metadata_path = os.path.join(METADATA_PATH, metadata_filename)
|
|
|
|
if not os.path.exists(metadata_path):
|
|
return None
|
|
|
|
with open(metadata_path, "r") as f:
|
|
metadata = json.load(f)
|
|
|
|
# Extract the image name from metadata filename (remove index- prefix and .json suffix)
|
|
base_name = metadata_filename[6:-5] # Remove "index-" prefix and ".json" suffix
|
|
|
|
# Construct full path to image file
|
|
image_filename = f"{base_name}~orig.jpg"
|
|
image_path = os.path.join(IMAGES_PATH, image_filename)
|
|
|
|
# Parse data structure - it's an array, so get first element
|
|
description = ""
|
|
title = base_name
|
|
|
|
if (
|
|
"data" in metadata
|
|
and isinstance(metadata["data"], list)
|
|
and len(metadata["data"]) > 0
|
|
):
|
|
data_item = metadata["data"][0] # Get the first item from the array
|
|
|
|
if isinstance(data_item, dict):
|
|
# Look for description in the first data element
|
|
if "description" in data_item:
|
|
description = data_item["description"]
|
|
elif "abstract" in data_item:
|
|
description = data_item["abstract"]
|
|
elif "title" in data_item:
|
|
title = data_item["title"]
|
|
|
|
# Additional fallbacks
|
|
if not description and isinstance(data_item, dict):
|
|
for key, value in data_item.items():
|
|
if (
|
|
isinstance(value, str)
|
|
and len(value) > 20
|
|
and not key.startswith("_")
|
|
):
|
|
if len(value) > 100 or (
|
|
len(value) > 50 and "space" in value.lower()
|
|
):
|
|
description = value
|
|
break
|
|
|
|
# If no description from data array, try root level
|
|
if not description and "description" in metadata:
|
|
description = metadata["description"]
|
|
|
|
# If still no description, try looking for long strings at root level
|
|
if not description and isinstance(metadata, dict):
|
|
for key, value in metadata.items():
|
|
if isinstance(value, str) and len(value) > 100:
|
|
description = value
|
|
break
|
|
|
|
# Final fallback
|
|
if not description:
|
|
description = "No description available"
|
|
|
|
return {
|
|
"id": base_name,
|
|
"title": title,
|
|
"description": description,
|
|
"image_path": image_path,
|
|
}
|
|
except Exception as e:
|
|
print(f"Error processing metadata {metadata_filename}: {e}")
|
|
return None
|
|
|
|
|
|
def add_to_history(image_data):
|
|
"""Add image to history with limit"""
|
|
global image_history
|
|
|
|
# Only add if not already in history
|
|
if not any(item["id"] == image_data["id"] for item in image_history):
|
|
image_history.append(image_data)
|
|
|
|
# Limit history size
|
|
if len(image_history) > MAX_HISTORY:
|
|
image_history.pop(0)
|
|
|
|
|
|
def get_next_image():
|
|
"""Get the next image in history or a random one if at end"""
|
|
if not image_history:
|
|
return None
|
|
|
|
# Return random image instead of going to next in history
|
|
# This ensures we always generate new images when at the end
|
|
metadata_filename = get_random_image_metadata()
|
|
if metadata_filename:
|
|
image_data = get_image_data(metadata_filename)
|
|
return image_data
|
|
|
|
return None
|
|
|
|
|
|
def get_previous_image():
|
|
"""Get previous image from history"""
|
|
global image_history
|
|
|
|
if len(image_history) >= 2:
|
|
# Return the second-to-last item (previous in history)
|
|
return image_history[-2]
|
|
elif len(image_history) == 1:
|
|
return image_history[0] # Return current if only one in history
|
|
else:
|
|
return None
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
"""Main page - get initial random image"""
|
|
metadata_filename = get_random_image_metadata()
|
|
if metadata_filename:
|
|
image_data = get_image_data(metadata_filename)
|
|
if image_data:
|
|
add_to_history(image_data)
|
|
return render_template("index.html", facts=[image_data])
|
|
|
|
# Fallback to empty page
|
|
return render_template("index.html", facts=[])
|
|
|
|
|
|
@app.route("/api/facts")
|
|
def get_facts():
|
|
"""Return current fact - for backwards compatibility"""
|
|
if image_history:
|
|
return jsonify([image_history[-1]])
|
|
return jsonify([])
|
|
|
|
|
|
@app.route("/api/fact/<string:fact_id>")
|
|
def get_fact(fact_id):
|
|
"""Get a specific fact by ID - this is primarily for demo purposes"""
|
|
# In our implementation, we don't actually support this since we're generating random images
|
|
return jsonify({"error": "Not implemented in this version"}), 404
|
|
|
|
|
|
@app.route("/api/image/<string:fact_id>")
|
|
def get_image(fact_id):
|
|
"""Get image by ID"""
|
|
try:
|
|
# This is a bit tricky because our structure is different now
|
|
# We'll find the metadata file with that id and return its image
|
|
image_filename = f"{fact_id}~orig.jpg"
|
|
full_image_path = os.path.join(IMAGES_PATH, image_filename)
|
|
|
|
if os.path.exists(full_image_path):
|
|
return send_file(full_image_path)
|
|
else:
|
|
return "Image not found", 404
|
|
except Exception as e:
|
|
return f"Error: {e}", 500
|
|
|
|
|
|
@app.route("/api/random-image")
|
|
def get_random_image():
|
|
"""Get a random image with metadata"""
|
|
metadata_filename = get_random_image_metadata()
|
|
if metadata_filename:
|
|
image_data = get_image_data(metadata_filename)
|
|
if image_data:
|
|
add_to_history(image_data)
|
|
return jsonify(image_data)
|
|
return jsonify({"error": "No images available"}), 404
|
|
|
|
|
|
@app.route("/api/next-image")
|
|
def get_next_image_route():
|
|
"""Get next image (random)"""
|
|
next_image = get_next_image()
|
|
if next_image:
|
|
add_to_history(next_image)
|
|
return jsonify(next_image)
|
|
return jsonify({"error": "No more images"}), 404
|
|
|
|
|
|
@app.route("/api/previous-image")
|
|
def get_previous_image_route():
|
|
"""Get previous image from history"""
|
|
prev_image = get_previous_image()
|
|
if prev_image:
|
|
return jsonify(prev_image)
|
|
return jsonify({"error": "No previous image"}), 404
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.run(debug=True, host="0.0.0.0", port=6008)
|