berrypod/lib/mix/tasks/generate_mockups.ex
jamey 9528700862 rename project from SimpleshopTheme to Berrypod
All modules, configs, paths, and references updated.
836 tests pass, zero warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:23:15 +00:00

292 lines
9.1 KiB
Elixir

defmodule Mix.Tasks.GenerateMockups do
@moduledoc """
Generates product mockups using Printify or Printful APIs.
This task automates the creation of product mockups for the Berrypod
sample content. It downloads artwork from Unsplash, uploads it to the
print-on-demand provider, creates products, and downloads the generated mockups.
## Usage
# Printify (default)
mix generate_mockups
mix generate_mockups --cleanup
mix generate_mockups --replace
# Printful
mix generate_mockups --provider printful
mix generate_mockups --provider printful --mockups-only
mix generate_mockups --provider printful --products-only
mix generate_mockups --provider printful --cleanup
## Output
Mockup images are saved to: priv/static/mockups/
"""
use Mix.Task
alias Berrypod.Mockups.Generator, as: PrintifyGenerator
alias Berrypod.Mockups.PrintfulGenerator
@shortdoc "Generates product mockups using Printify or Printful API"
@impl Mix.Task
def run(args) do
Mix.Task.run("app.start")
{opts, _, _} =
OptionParser.parse(args,
switches: [
cleanup: :boolean,
replace: :boolean,
search: :string,
list_blueprints: :boolean,
help: :boolean,
provider: :string,
mockups_only: :boolean,
products_only: :boolean
],
aliases: [
c: :cleanup,
r: :replace,
s: :search,
l: :list_blueprints,
h: :help,
p: :provider
]
)
provider = Keyword.get(opts, :provider, "printify")
cond do
opts[:help] ->
print_help()
provider == "printful" ->
run_printful(opts)
opts[:list_blueprints] ->
list_blueprints()
opts[:search] ->
search_blueprints(opts[:search])
true ->
run_printify(opts)
end
end
defp print_help do
Mix.shell().info("""
Mockup Generator
================
Generates product mockups using Printify or Printful APIs.
Usage:
mix generate_mockups [options]
Common options:
--provider, -p NAME Provider to use: "printify" (default) or "printful"
--cleanup, -c Delete created products after downloading mockups
--help, -h Show this help message
Printify options:
--replace, -r Delete ALL existing products before generating (with confirmation)
--search, -s TERM Search for blueprints by name
--list-blueprints List all available blueprint IDs and names
Printful options:
--mockups-only Only generate mockup images (skip product creation)
--products-only Only create sync products (skip mockup images)
Environment:
PRINTIFY_API_TOKEN Required for Printify provider
PRINTFUL_API_TOKEN Required for Printful provider
Examples:
mix generate_mockups
mix generate_mockups --provider printful
mix generate_mockups --provider printful --mockups-only
mix generate_mockups --provider printful --cleanup
""")
end
defp list_blueprints do
Mix.shell().info("Fetching blueprints from Printify...")
case PrintifyGenerator.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 PrintifyGenerator.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
# ===========================================================================
# Printify
# ===========================================================================
defp run_printify(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"}
╚═══════════════════════════════════════════╝
""")
case System.get_env("PRINTIFY_API_TOKEN") do
nil ->
Mix.shell().error("""
Error: PRINTIFY_API_TOKEN environment variable is not set.
Set it and retry:
export PRINTIFY_API_TOKEN="your-token"
mix generate_mockups
""")
_token ->
if replace, do: purge_existing_printify_products()
results = PrintifyGenerator.generate_all(cleanup: cleanup)
successful = Enum.count(results, &match?({:ok, _, _, _}, &1))
failed = Enum.count(results, &match?({:error, _, _}, &1))
Mix.shell().info("""
Summary: #{successful} succeeded, #{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_printify_products do
alias Berrypod.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 = PrintifyGenerator.purge_all_products(shop_id)
Mix.shell().info("Deleted #{deleted} products.\n")
else
Mix.shell().info("Skipping purge.\n")
end
end
end
# ===========================================================================
# Printful
# ===========================================================================
defp run_printful(opts) do
mockups_only = Keyword.get(opts, :mockups_only, false)
products_only = Keyword.get(opts, :products_only, false)
cleanup = Keyword.get(opts, :cleanup, false)
do_mockups = !products_only
do_products = !mockups_only
Mix.shell().info("""
╔═══════════════════════════════════════════╗
║ Printful Mockup Generator ║
╠═══════════════════════════════════════════╣
║ Mockups: #{if do_mockups, do: "ON ", else: "OFF"}
║ Products: #{if do_products, do: "ON ", else: "OFF"}
║ Cleanup: #{if cleanup, do: "ON ", else: "OFF"}
╚═══════════════════════════════════════════╝
""")
case System.get_env("PRINTFUL_API_TOKEN") do
nil ->
Mix.shell().error("""
Error: PRINTFUL_API_TOKEN environment variable is not set.
Set it and retry:
export PRINTFUL_API_TOKEN="your-token"
mix generate_mockups --provider printful
""")
_token ->
results =
PrintfulGenerator.generate_all(
mockups: do_mockups,
products: do_products,
cleanup: cleanup
)
mockup_ok = Enum.count(results.mockups, &match?({:ok, _, _}, &1))
mockup_fail = Enum.count(results.mockups, &match?({:error, _, _}, &1))
product_ok = Enum.count(results.products, &match?({:ok, _, _}, &1))
product_fail = Enum.count(results.products, &match?({:error, _, _}, &1))
Mix.shell().info("""
Summary:
Mockups: #{mockup_ok} succeeded, #{mockup_fail} failed
Products: #{product_ok} succeeded, #{product_fail} failed
""")
if mockup_fail + product_fail > 0 do
Mix.shell().error("Some operations failed. Check the output above for details.")
end
end
end
end