check / check (push) Waiting to run
A /v1/image/ URL whose last segment is a size with no format, such as 800x600 or orig, is served as JPEG XL and signed as jxl, so it shares the signature of the same URL ending in .jxl. An encrypted URL whose token holds no format is served as JPEG XL, as encurl.DefaultFormat is now jxl. The generator page selects JPEG XL by default, and a form with an empty format, or none, makes a URL whose name ends in .jxl. The image processor no longer takes an empty format as orig: both routes give every request a format, so it refuses a request with none instead of keeping a second default. auto still ends with JPEG. Model: opus-5-5
162 lines
6.5 KiB
HTML
162 lines
6.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pixa - URL Generator</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<header>
|
|
<h1>Pixa URL Generator</h1>
|
|
<a href="/logout">
|
|
Logout
|
|
</a>
|
|
</header>
|
|
|
|
{{if .GeneratedURL}}
|
|
<div class="result">
|
|
<h2>Generated URL</h2>
|
|
<div>
|
|
<input
|
|
type="text"
|
|
readonly
|
|
value="{{.GeneratedURL}}"
|
|
id="generated-url"
|
|
>
|
|
<button id="copy-url">
|
|
Copy
|
|
</button>
|
|
</div>
|
|
<p>
|
|
Expires: {{.ExpiresAt}}
|
|
</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Error}}
|
|
<div class="error">
|
|
{{.Error}}
|
|
</div>
|
|
{{end}}
|
|
|
|
<form method="POST" action="/generate" class="card">
|
|
{{ .CSRFField }}
|
|
<div>
|
|
<label for="url">
|
|
Source URL
|
|
</label>
|
|
<input
|
|
type="url"
|
|
id="url"
|
|
name="url"
|
|
required
|
|
placeholder="https://example.com/image.jpg"
|
|
value="{{.FormURL}}"
|
|
>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div>
|
|
<label for="width">
|
|
Width
|
|
</label>
|
|
<input
|
|
type="number"
|
|
id="width"
|
|
name="width"
|
|
min="0"
|
|
max="8192"
|
|
value="{{if .FormWidth}}{{.FormWidth}}{{else}}0{{end}}"
|
|
placeholder="0 = original"
|
|
>
|
|
</div>
|
|
<div>
|
|
<label for="height">
|
|
Height
|
|
</label>
|
|
<input
|
|
type="number"
|
|
id="height"
|
|
name="height"
|
|
min="0"
|
|
max="8192"
|
|
value="{{if .FormHeight}}{{.FormHeight}}{{else}}0{{end}}"
|
|
placeholder="0 = original"
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div>
|
|
<label for="format">
|
|
Format
|
|
</label>
|
|
<select id="format" name="format">
|
|
<option value="orig" {{if eq .FormFormat "orig"}}selected{{end}}>Original</option>
|
|
<option value="auto" {{if eq .FormFormat "auto"}}selected{{end}}>Auto (JPEG XL, AVIF, WebP or JPEG)</option>
|
|
<option value="jpeg" {{if eq .FormFormat "jpeg"}}selected{{end}}>JPEG</option>
|
|
<option value="png" {{if eq .FormFormat "png"}}selected{{end}}>PNG</option>
|
|
<option value="webp" {{if eq .FormFormat "webp"}}selected{{end}}>WebP</option>
|
|
<option value="avif" {{if eq .FormFormat "avif"}}selected{{end}}>AVIF</option>
|
|
<option value="jxl" {{if or (eq .FormFormat "jxl") (eq .FormFormat "")}}selected{{end}}>JPEG XL</option>
|
|
<option value="gif" {{if eq .FormFormat "gif"}}selected{{end}}>GIF</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="quality">
|
|
Quality
|
|
</label>
|
|
<select id="quality" name="quality">
|
|
<option value="25" {{if eq .FormQuality "25"}}selected{{end}}>Potato</option>
|
|
<option value="50" {{if eq .FormQuality "50"}}selected{{end}}>Low</option>
|
|
<option value="70" {{if eq .FormQuality "70"}}selected{{end}}>Medium</option>
|
|
<option value="85" {{if or (eq .FormQuality "85") (eq .FormQuality "")}}selected{{end}}>High</option>
|
|
<option value="100" {{if eq .FormQuality "100"}}selected{{end}}>Ultra</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div>
|
|
<label for="fit">
|
|
Fit Mode
|
|
</label>
|
|
<select id="fit" name="fit">
|
|
<option value="cover" {{if eq .FormFit "cover"}}selected{{end}}>Cover</option>
|
|
<option value="contain" {{if eq .FormFit "contain"}}selected{{end}}>Contain</option>
|
|
<option value="fill" {{if eq .FormFit "fill"}}selected{{end}}>Fill</option>
|
|
<option value="inside" {{if eq .FormFit "inside"}}selected{{end}}>Inside</option>
|
|
<option value="outside" {{if eq .FormFit "outside"}}selected{{end}}>Outside</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="ttl">
|
|
Expires In
|
|
</label>
|
|
<select id="ttl" name="ttl">
|
|
<option value="0" {{if or (eq .FormTTL "0") (eq .FormTTL "")}}selected{{end}}>Never</option>
|
|
<option value="60" {{if eq .FormTTL "60"}}selected{{end}}>1 minute</option>
|
|
<option value="3600" {{if eq .FormTTL "3600"}}selected{{end}}>1 hour</option>
|
|
<option value="86400" {{if eq .FormTTL "86400"}}selected{{end}}>1 day</option>
|
|
<option value="604800" {{if eq .FormTTL "604800"}}selected{{end}}>1 week</option>
|
|
<option value="2592000" {{if eq .FormTTL "2592000"}}selected{{end}}>30 days</option>
|
|
<option value="31536000" {{if eq .FormTTL "31536000"}}selected{{end}}>1 year</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit">
|
|
Generate Encrypted URL
|
|
</button>
|
|
</form>
|
|
|
|
<p class="note">
|
|
Generated URLs are encrypted and cannot be modified. They will expire at the specified time.
|
|
</p>
|
|
</div>
|
|
<script src="/static/generator.js"></script>
|
|
</body>
|
|
</html>
|