Spaces:
Sleeping
Sleeping
import os | |
import requests | |
import zipfile | |
import gradio as gr | |
import shutil | |
from PIL import Image | |
# Configuration | |
API_URL = "https://porn-pictures-api.p.rapidapi.com/pornstars/{gender}/{page}" | |
API_HEADERS = { | |
"x-rapidapi-key": "2dcd4142a4msh0d39ff26a5b144cp1e8703jsndf67b0582674", | |
"x-rapidapi-host": "porn-pictures-api.p.rapidapi.com" | |
} | |
OUTPUT_DIR = "downloaded_images" # Base output folder | |
IMAGES_DIR = os.path.join(OUTPUT_DIR, "images") # Subfolder for downloaded images | |
ZIP_FILE = os.path.join(OUTPUT_DIR, "images.zip") # Path for the output ZIP file | |
# Ensure output directory exists | |
os.makedirs(OUTPUT_DIR, exist_ok=True) | |
def fetch_image_urls(gender, num_images): | |
"""Fetch image URLs from the API based on gender and desired number of images.""" | |
image_urls = [] | |
page = 1 | |
items_per_page = 40 # From the response, each page has 40 items | |
while len(image_urls) < num_images: | |
url = API_URL.format(gender=gender.lower(), page=page) | |
try: | |
response = requests.get(url, headers=API_HEADERS) | |
response.raise_for_status() # Raise an error for bad status codes | |
data = response.json() | |
if "result" not in data or not data["result"]: | |
break # No more data to fetch | |
for item in data["result"]: | |
if len(image_urls) >= num_images: | |
break | |
image_urls.append(item["picture"]) | |
page += 1 | |
except Exception as e: | |
print(f"Error fetching page {page}: {e}") | |
break | |
return image_urls[:num_images] | |
def download_images(image_urls): | |
"""Download images from the provided URLs and save to IMAGES_DIR.""" | |
if os.path.exists(IMAGES_DIR): | |
shutil.rmtree(IMAGES_DIR) # Clear previous contents | |
os.makedirs(IMAGES_DIR, exist_ok=True) | |
downloaded_count = 0 | |
image_paths = [] | |
for idx, url in enumerate(image_urls, 1): | |
try: | |
response = requests.get(url, stream=True) | |
response.raise_for_status() | |
image_path = os.path.join(IMAGES_DIR, f"img{idx}.jpg") | |
with open(image_path, "wb") as f: | |
for chunk in response.iter_content(chunk_size=8192): | |
if chunk: | |
f.write(chunk) | |
# Verify the image | |
Image.open(image_path).verify() | |
downloaded_count += 1 | |
image_paths.append(image_path) | |
print(f"Downloaded {idx}/{len(image_urls)}: {url}") | |
except Exception as e: | |
print(f"Error downloading {url}: {e}") | |
return downloaded_count, image_paths | |
def create_zip_file(selected_image_paths): | |
"""Create a ZIP file of the selected images.""" | |
if os.path.exists(ZIP_FILE): | |
os.remove(ZIP_FILE) # Remove previous ZIP | |
with zipfile.ZipFile(ZIP_FILE, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
for image_path in selected_image_paths: | |
arcname = os.path.relpath(image_path, OUTPUT_DIR) | |
zipf.write(image_path, arcname) | |
return ZIP_FILE | |
def process_and_display(gender, num_images): | |
"""Fetch and download images, then prepare data for display.""" | |
num_images = int(num_images) # Convert dropdown selection to integer | |
if num_images > 24: | |
num_images = 24 # Limit to 24 images to fit 6 rows of 4 | |
# Fetch image URLs | |
image_urls = fetch_image_urls(gender, num_images) | |
if not image_urls: | |
return "Failed to fetch image URLs.", None, None, None | |
# Download images | |
downloaded_count, image_paths = download_images(image_urls) | |
if downloaded_count == 0: | |
return "No images were successfully downloaded.", None, None, None | |
return f"Successfully downloaded {downloaded_count}/{num_images} images. Select images to include in ZIP below.", None, image_paths, image_paths | |
def process_zip_submission(image_paths, *checkbox_states): | |
"""Create a ZIP file based on the selected images.""" | |
if not image_paths: | |
return "No images available to process.", None | |
selected_image_paths = [image_paths[i] for i, state in enumerate(checkbox_states) if state] | |
if not selected_image_paths: | |
return "No images selected for ZIP.", None | |
zip_path = create_zip_file(selected_image_paths) | |
return f"ZIP file created with {len(selected_image_paths)} images at {zip_path}", zip_path | |
# Gradio Interface | |
with gr.Blocks(title="Image Downloader") as demo: | |
gr.Markdown("### Select Parameters to Download Images") | |
gender_input = gr.Dropdown( | |
label="Category (Gender, Race, Hair Color, Body Type) - Select or Type Custom", | |
choices=["female", "male", "nonbinary", "black", "latino", "asian", "white", "mixed", | |
"redhead", "blonde", "brunette", "blackhair", "bald", "bbw", "curvy", | |
"slim", "muscular", "thick"], | |
value="female", | |
allow_custom_value=True | |
) | |
num_images_input = gr.Dropdown( | |
label="Number of Images (Max 24)", | |
choices=["4", "8", "12", "16", "20", "24"], # Multiples of 4 up to 24 | |
value="4" | |
) | |
download_button = gr.Button("Fetch and Display Images") | |
gr.Markdown("### Download Status") | |
status_output = gr.Textbox(label="Status", interactive=False) | |
gr.Markdown("### Download Your Images") | |
zip_output = gr.File(label="Download ZIP", visible=False) | |
gr.Markdown("### Image Gallery (Click Thumbnails to View Full Size)") | |
image_paths_state = gr.State() # Store image paths for later use | |
# Define constants for grid layout | |
IMAGES_PER_ROW = 4 | |
MAX_ROWS = 6 # 6 rows of 4 = 24 images max | |
TOTAL_IMAGES = IMAGES_PER_ROW * MAX_ROWS # 24 images max | |
# Create image and checkbox components in a strict 4-per-row grid | |
image_outputs = [] | |
checkbox_outputs = [] | |
for row in range(MAX_ROWS): | |
with gr.Row(): | |
for col in range(IMAGES_PER_ROW): | |
idx = row * IMAGES_PER_ROW + col | |
with gr.Column(min_width=150): # Set a minimum width to force layout | |
image_output = gr.Image( | |
label=f"Image {idx+1}", | |
visible=False, | |
height=150, | |
width=150 | |
) | |
checkbox_output = gr.Checkbox( | |
label=f"Include in ZIP", | |
value=True, | |
visible=False | |
) | |
image_outputs.append(image_output) | |
checkbox_outputs.append(checkbox_output) | |
gr.Markdown("### Submit Selections") | |
submit_button = gr.Button("Create ZIP of Selected Images") | |
def on_download(gender, num_images): | |
status, zip_path, image_paths, _ = process_and_display(gender, num_images) | |
if image_paths: | |
# Update image and checkbox components for the downloaded images | |
updates = { | |
status_output: status, | |
zip_output: gr.File(value=None, visible=False), # Hide ZIP initially | |
image_paths_state: image_paths | |
} | |
for i in range(TOTAL_IMAGES): | |
if i < len(image_paths): | |
updates[image_outputs[i]] = gr.Image( | |
value=image_paths[i], | |
visible=True, | |
label=f"Image {i+1}", | |
width=150, | |
height=150 | |
) | |
updates[checkbox_outputs[i]] = gr.Checkbox( | |
value=True, | |
visible=True, | |
label=f"Include in ZIP" | |
) | |
else: | |
updates[image_outputs[i]] = gr.Image(value=None, visible=False) | |
updates[checkbox_outputs[i]] = gr.Checkbox(value=False, visible=False) | |
return updates | |
return { | |
status_output: status, | |
zip_output: gr.File(visible=False), | |
image_paths_state: None, | |
**{image_outputs[i]: gr.Image(value=None, visible=False) for i in range(TOTAL_IMAGES)}, | |
**{checkbox_outputs[i]: gr.Checkbox(value=False, visible=False) for i in range(TOTAL_IMAGES)} | |
} | |
def on_submit(image_paths, *checkbox_states): | |
status, zip_path = process_zip_submission(image_paths, *checkbox_states) | |
return { | |
status_output: status, | |
zip_output: gr.File(value=zip_path, visible=True) if zip_path else gr.File(visible=False) | |
} | |
download_button.click( | |
fn=on_download, | |
inputs=[gender_input, num_images_input], | |
outputs=[status_output, zip_output, image_paths_state] + image_outputs + checkbox_outputs | |
) | |
submit_button.click( | |
fn=on_submit, | |
inputs=[image_paths_state] + checkbox_outputs, | |
outputs=[status_output, zip_output] | |
) | |
demo.launch() |