parent
1320843aad
commit
8346dc04b3
@ -0,0 +1,88 @@ |
||||
# Pict-rs {#module-services-pict-rs} |
||||
|
||||
pict-rs is a a simple image hosting service. |
||||
|
||||
## Quickstart {#module-services-pict-rs-quickstart} |
||||
|
||||
the minimum to start pict-rs is |
||||
|
||||
```nix |
||||
services.pict-rs.enable = true; |
||||
``` |
||||
|
||||
this will start the http server on port 8080 by default. |
||||
|
||||
## Usage {#module-services-pict-rs-usage} |
||||
|
||||
pict-rs offers the following endpoints: |
||||
- `POST /image` for uploading an image. Uploaded content must be valid multipart/form-data with an |
||||
image array located within the `images[]` key |
||||
|
||||
This endpoint returns the following JSON structure on success with a 201 Created status |
||||
```json |
||||
{ |
||||
"files": [ |
||||
{ |
||||
"delete_token": "JFvFhqJA98", |
||||
"file": "lkWZDRvugm.jpg" |
||||
}, |
||||
{ |
||||
"delete_token": "kAYy9nk2WK", |
||||
"file": "8qFS0QooAn.jpg" |
||||
}, |
||||
{ |
||||
"delete_token": "OxRpM3sf0Y", |
||||
"file": "1hJaYfGE01.jpg" |
||||
} |
||||
], |
||||
"msg": "ok" |
||||
} |
||||
``` |
||||
- `GET /image/download?url=...` Download an image from a remote server, returning the same JSON |
||||
payload as the `POST` endpoint |
||||
- `GET /image/original/{file}` for getting a full-resolution image. `file` here is the `file` key from the |
||||
`/image` endpoint's JSON |
||||
- `GET /image/details/original/{file}` for getting the details of a full-resolution image. |
||||
The returned JSON is structured like so: |
||||
```json |
||||
{ |
||||
"width": 800, |
||||
"height": 537, |
||||
"content_type": "image/webp", |
||||
"created_at": [ |
||||
2020, |
||||
345, |
||||
67376, |
||||
394363487 |
||||
] |
||||
} |
||||
``` |
||||
- `GET /image/process.{ext}?src={file}&...` get a file with transformations applied. |
||||
existing transformations include |
||||
- `identity=true`: apply no changes |
||||
- `blur={float}`: apply a gaussian blur to the file |
||||
- `thumbnail={int}`: produce a thumbnail of the image fitting inside an `{int}` by `{int}` |
||||
square using raw pixel sampling |
||||
- `resize={int}`: produce a thumbnail of the image fitting inside an `{int}` by `{int}` square |
||||
using a Lanczos2 filter. This is slower than sampling but looks a bit better in some cases |
||||
- `crop={int-w}x{int-h}`: produce a cropped version of the image with an `{int-w}` by `{int-h}` |
||||
aspect ratio. The resulting crop will be centered on the image. Either the width or height |
||||
of the image will remain full-size, depending on the image's aspect ratio and the requested |
||||
aspect ratio. For example, a 1600x900 image cropped with a 1x1 aspect ratio will become 900x900. A |
||||
1600x1100 image cropped with a 16x9 aspect ratio will become 1600x900. |
||||
|
||||
Supported `ext` file extensions include `png`, `jpg`, and `webp` |
||||
|
||||
An example of usage could be |
||||
``` |
||||
GET /image/process.jpg?src=asdf.png&thumbnail=256&blur=3.0 |
||||
``` |
||||
which would create a 256x256px JPEG thumbnail and blur it |
||||
- `GET /image/details/process.{ext}?src={file}&...` for getting the details of a processed image. |
||||
The returned JSON is the same format as listed for the full-resolution details endpoint. |
||||
- `DELETE /image/delete/{delete_token}/{file}` or `GET /image/delete/{delete_token}/{file}` to |
||||
delete a file, where `delete_token` and `file` are from the `/image` endpoint's JSON |
||||
|
||||
## Missing {#module-services-pict-rs-missing} |
||||
|
||||
- Configuring the secure-api-key is not included yet. The envisioned basic use case is consumption on localhost by other services without exposing the service to the internet. |
@ -0,0 +1,50 @@ |
||||
{ lib, pkgs, config, ... }: |
||||
with lib; |
||||
let |
||||
cfg = config.services.pict-rs; |
||||
in |
||||
{ |
||||
meta.maintainers = with maintainers; [ happysalada ]; |
||||
# Don't edit the docbook xml directly, edit the md and generate it: |
||||
# `pandoc pict-rs.md -t docbook --top-level-division=chapter --extract-media=media -f markdown+smart > pict-rs.xml` |
||||
meta.doc = ./pict-rs.xml; |
||||
|
||||
options.services.pict-rs = { |
||||
enable = mkEnableOption "pict-rs server"; |
||||
dataDir = mkOption { |
||||
type = types.path; |
||||
default = "/var/lib/pict-rs"; |
||||
description = '' |
||||
The directory where to store the uploaded images. |
||||
''; |
||||
}; |
||||
address = mkOption { |
||||
type = types.str; |
||||
default = "127.0.0.1"; |
||||
description = '' |
||||
The IPv4 address to deploy the service to. |
||||
''; |
||||
}; |
||||
port = mkOption { |
||||
type = types.port; |
||||
default = 8080; |
||||
description = '' |
||||
The port which to bind the service to. |
||||
''; |
||||
}; |
||||
}; |
||||
config = lib.mkIf cfg.enable { |
||||
systemd.services.pict-rs = { |
||||
environment = { |
||||
PICTRS_PATH = cfg.dataDir; |
||||
PICTRS_ADDR = "${cfg.address}:${toString cfg.port}"; |
||||
}; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
serviceConfig = { |
||||
DynamicUser = true; |
||||
StateDirectory = "pict-rs"; |
||||
ExecStart = "${pkgs.pict-rs}/bin/pict-rs"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,162 @@ |
||||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="module-services-pict-rs"> |
||||
<title>Pict-rs</title> |
||||
<para> |
||||
pict-rs is a a simple image hosting service. |
||||
</para> |
||||
<section xml:id="module-services-pict-rs-quickstart"> |
||||
<title>Quickstart</title> |
||||
<para> |
||||
the minimum to start pict-rs is |
||||
</para> |
||||
<programlisting language="bash"> |
||||
services.pict-rs.enable = true; |
||||
</programlisting> |
||||
<para> |
||||
this will start the http server on port 8080 by default. |
||||
</para> |
||||
</section> |
||||
<section xml:id="module-services-pict-rs-usage"> |
||||
<title>Usage</title> |
||||
<para> |
||||
pict-rs offers the following endpoints: - |
||||
<literal>POST /image</literal> for uploading an image. Uploaded |
||||
content must be valid multipart/form-data with an image array |
||||
located within the <literal>images[]</literal> key |
||||
</para> |
||||
<programlisting> |
||||
This endpoint returns the following JSON structure on success with a 201 Created status |
||||
```json |
||||
{ |
||||
"files": [ |
||||
{ |
||||
"delete_token": "JFvFhqJA98", |
||||
"file": "lkWZDRvugm.jpg" |
||||
}, |
||||
{ |
||||
"delete_token": "kAYy9nk2WK", |
||||
"file": "8qFS0QooAn.jpg" |
||||
}, |
||||
{ |
||||
"delete_token": "OxRpM3sf0Y", |
||||
"file": "1hJaYfGE01.jpg" |
||||
} |
||||
], |
||||
"msg": "ok" |
||||
} |
||||
``` |
||||
</programlisting> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para> |
||||
<literal>GET /image/download?url=...</literal> Download an |
||||
image from a remote server, returning the same JSON payload as |
||||
the <literal>POST</literal> endpoint |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>GET /image/original/{file}</literal> for getting a |
||||
full-resolution image. <literal>file</literal> here is the |
||||
<literal>file</literal> key from the <literal>/image</literal> |
||||
endpoint’s JSON |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>GET /image/details/original/{file}</literal> for |
||||
getting the details of a full-resolution image. The returned |
||||
JSON is structured like so: |
||||
<literal>json { "width": 800, "height": 537, "content_type": "image/webp", "created_at": [ 2020, 345, 67376, 394363487 ] }</literal> |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>GET /image/process.{ext}?src={file}&...</literal> |
||||
get a file with transformations applied. existing |
||||
transformations include |
||||
</para> |
||||
<itemizedlist spacing="compact"> |
||||
<listitem> |
||||
<para> |
||||
<literal>identity=true</literal>: apply no changes |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>blur={float}</literal>: apply a gaussian blur to |
||||
the file |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>thumbnail={int}</literal>: produce a thumbnail of |
||||
the image fitting inside an <literal>{int}</literal> by |
||||
<literal>{int}</literal> square using raw pixel sampling |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>resize={int}</literal>: produce a thumbnail of |
||||
the image fitting inside an <literal>{int}</literal> by |
||||
<literal>{int}</literal> square using a Lanczos2 filter. |
||||
This is slower than sampling but looks a bit better in |
||||
some cases |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>crop={int-w}x{int-h}</literal>: produce a cropped |
||||
version of the image with an <literal>{int-w}</literal> by |
||||
<literal>{int-h}</literal> aspect ratio. The resulting |
||||
crop will be centered on the image. Either the width or |
||||
height of the image will remain full-size, depending on |
||||
the image’s aspect ratio and the requested aspect ratio. |
||||
For example, a 1600x900 image cropped with a 1x1 aspect |
||||
ratio will become 900x900. A 1600x1100 image cropped with |
||||
a 16x9 aspect ratio will become 1600x900. |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para> |
||||
Supported <literal>ext</literal> file extensions include |
||||
<literal>png</literal>, <literal>jpg</literal>, and |
||||
<literal>webp</literal> |
||||
</para> |
||||
<para> |
||||
An example of usage could be |
||||
<literal>GET /image/process.jpg?src=asdf.png&thumbnail=256&blur=3.0</literal> |
||||
which would create a 256x256px JPEG thumbnail and blur it |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>GET /image/details/process.{ext}?src={file}&...</literal> |
||||
for getting the details of a processed image. The returned |
||||
JSON is the same format as listed for the full-resolution |
||||
details endpoint. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<literal>DELETE /image/delete/{delete_token}/{file}</literal> |
||||
or <literal>GET /image/delete/{delete_token}/{file}</literal> |
||||
to delete a file, where <literal>delete_token</literal> and |
||||
<literal>file</literal> are from the <literal>/image</literal> |
||||
endpoint’s JSON |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
<section xml:id="module-services-pict-rs-missing"> |
||||
<title>Missing</title> |
||||
<itemizedlist spacing="compact"> |
||||
<listitem> |
||||
<para> |
||||
Configuring the secure-api-key is not included yet. The |
||||
envisioned basic use case is consumption on localhost by other |
||||
services without exposing the service to the internet. |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
</chapter> |
@ -0,0 +1,17 @@ |
||||
import ./make-test-python.nix ({ pkgs, lib, ... }: |
||||
{ |
||||
name = "pict-rs"; |
||||
meta.maintainers = with lib.maintainers; [ happysalada ]; |
||||
|
||||
machine = { ... }: { |
||||
environment.systemPackages = with pkgs; [ curl jq ]; |
||||
services.pict-rs.enable = true; |
||||
}; |
||||
|
||||
testScript = '' |
||||
start_all() |
||||
|
||||
machine.wait_for_unit("pict-rs") |
||||
machine.wait_for_open_port("8080") |
||||
''; |
||||
}) |
Loading…
Reference in new issue