berrypod/lib/mix/tasks/generate_mockups.ex
jamey af207d7a35 switch mockup generator to UK print providers and add --replace flag
- Prefer Print Clever (72) for canvas, Monster Digital (29) for
  apparel and mugs where available, fall back to default providers
- Rename Art Print products to Canvas (new Satin Canvas blueprint)
- Add Canvas Prints category in Printify tag extraction
- Add --replace/-r flag to purge existing Printify products before
  generating (with interactive confirmation)
- Add purge_all_products/1 to generator module
- Remove old art print mockups, add new canvas + extra provider mockups

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:00:59 +00:00

237 lines
6.9 KiB
Elixir

defmodule Mix.Tasks.GenerateMockups do
@moduledoc """
Generates product mockups using the Printify API.
This task automates the creation of product mockups for the SimpleshopTheme
sample content. It downloads artwork from Unsplash, uploads it to Printify,
creates products, and downloads the generated mockups.
## Requirements
- A Printify account with API access
- The PRINTIFY_API_TOKEN environment variable must be set
## Usage
# Generate mockups (keeps products in Printify)
mix generate_mockups
# Delete existing products first, then generate fresh ones
mix generate_mockups --replace
# Generate mockups and delete products afterwards
mix generate_mockups --cleanup
# Search for available blueprints
mix generate_mockups --search "poster"
# List all blueprints
mix generate_mockups --list-blueprints
## Output
Mockup images are saved to: priv/static/mockups/
"""
use Mix.Task
alias SimpleshopTheme.Mockups.Generator, as: MockupGenerator
@shortdoc "Generates product mockups using Printify API"
@impl Mix.Task
def run(args) do
# Start required applications
Mix.Task.run("app.start")
{opts, _, _} =
OptionParser.parse(args,
switches: [
cleanup: :boolean,
replace: :boolean,
search: :string,
list_blueprints: :boolean,
help: :boolean
],
aliases: [
c: :cleanup,
r: :replace,
s: :search,
l: :list_blueprints,
h: :help
]
)
cond do
opts[:help] ->
print_help()
opts[:list_blueprints] ->
list_blueprints()
opts[:search] ->
search_blueprints(opts[:search])
true ->
generate_mockups(opts)
end
end
defp print_help do
Mix.shell().info("""
Printify Mockup Generator
=========================
Generates product mockups using the Printify API.
Usage:
mix generate_mockups [options]
Options:
--replace, -r Delete ALL existing products from Printify before generating (with confirmation)
--cleanup, -c Delete created products from Printify after downloading mockups
--search, -s TERM Search for blueprints by name
--list-blueprints List all available blueprint IDs and names
--help, -h Show this help message
Environment:
PRINTIFY_API_TOKEN Required. Your Printify API token.
Examples:
# Generate all mockups
export PRINTIFY_API_TOKEN="your-token"
mix generate_mockups
# Generate and cleanup
mix generate_mockups --cleanup
# Find blueprint IDs
mix generate_mockups --search "poster"
""")
end
defp list_blueprints do
Mix.shell().info("Fetching blueprints from Printify...")
case MockupGenerator.list_blueprints() do
blueprints when is_list(blueprints) ->
Mix.shell().info("\nAvailable Blueprints:\n")
blueprints
|> Enum.each(fn {id, title} ->
Mix.shell().info(" #{id}: #{title}")
end)
Mix.shell().info("\nTotal: #{length(blueprints)} blueprints")
{:error, reason} ->
Mix.shell().error("Error fetching blueprints: #{inspect(reason)}")
end
end
defp search_blueprints(term) do
Mix.shell().info("Searching for blueprints matching '#{term}'...")
case MockupGenerator.search_blueprints(term) do
results when is_list(results) ->
if results == [] do
Mix.shell().info("No blueprints found matching '#{term}'")
else
Mix.shell().info("\nMatching Blueprints:\n")
results
|> Enum.each(fn {id, title} ->
Mix.shell().info(" #{id}: #{title}")
end)
Mix.shell().info("\nFound: #{length(results)} blueprints")
end
{:error, reason} ->
Mix.shell().error("Error searching blueprints: #{inspect(reason)}")
end
end
defp generate_mockups(opts) do
cleanup = Keyword.get(opts, :cleanup, false)
replace = Keyword.get(opts, :replace, false)
Mix.shell().info("""
╔═══════════════════════════════════════════╗
║ Printify Mockup Generator ║
╠═══════════════════════════════════════════╣
║ Replace mode: #{if replace, do: "ON ", else: "OFF"}
║ Cleanup mode: #{if cleanup, do: "ON ", else: "OFF"}
╚═══════════════════════════════════════════╝
""")
# Verify API token is set
case System.get_env("PRINTIFY_API_TOKEN") do
nil ->
Mix.shell().error("""
Error: PRINTIFY_API_TOKEN environment variable is not set.
To get your API token:
1. Log in to Printify
2. Go to Settings > API tokens
3. Create a new token with required permissions
Then run:
export PRINTIFY_API_TOKEN="your-token"
mix generate_mockups
""")
_token ->
if replace, do: purge_existing_products()
results = MockupGenerator.generate_all(cleanup: cleanup)
# Summary
successful = Enum.count(results, &match?({:ok, _, _, _}, &1))
failed = Enum.count(results, &match?({:error, _, _}, &1))
Mix.shell().info("""
═══════════════════════════════════════════
Summary
═══════════════════════════════════════════
Successful: #{successful}
Failed: #{failed}
═══════════════════════════════════════════
""")
if failed > 0 do
Mix.shell().error(
"Some products failed to generate. Check the output above for details."
)
end
end
end
defp purge_existing_products do
alias SimpleshopTheme.Clients.Printify, as: Client
Mix.shell().info("Fetching existing products...")
{:ok, shop_id} = Client.get_shop_id()
{:ok, %{"data" => products}} = Client.list_products(shop_id)
count = length(products)
if count == 0 do
Mix.shell().info("No existing products to delete.\n")
else
Mix.shell().info("Found #{count} existing products in Printify.")
if Mix.shell().yes?("Delete all #{count} products before generating new ones?") do
deleted = MockupGenerator.purge_all_products(shop_id)
Mix.shell().info("Deleted #{deleted} products.\n")
else
Mix.shell().info("Skipping purge.\n")
end
end
end
end