diff --git a/res/include/md/api.md b/res/include/md/api.md
new file mode 100644
index 0000000..3d515d7
--- /dev/null
+++ b/res/include/md/api.md
@@ -0,0 +1,52 @@
+# Pixeldrain API documentation
+
+The methods for uploading and retrieving files don't require an API key. The
+methods for creating and retrieving lists also don't require an API key. All
+methods which delete or modify a resource **do** require an API key.
+
+API keys can be obtained from your user account's [API keys
+page](/user/api_keys).
+
+To use the API key you need to enter it in the password field of [HTTP Basic
+Access
+Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). The
+username field does not matter, it can be empty or anything else.
+
+Example usage in JavaScript:
+
+```js
+const resp = await fetch(
+ "https://pixeldrain.com/api/user/files",
+ headers: {
+ "Authorization": "Basic "+btoa(":"+api_key),
+ // The btoa function encodes the key to Base64
+ },
+)
+if(resp.status >= 400) {
+ throw new Error(await resp.json())
+}
+result = await resp.json()
+```
+
+Some JSON responses include fields which end in "_href" (some people don't know
+this, but "href" stands for "Hypertext Reference", the more you know). These
+point to different places in the API, which you can retrieve with a GET request.
+The path is to be appended to the API URL, so "/file/someid/thumbnail" becomes
+"{{apiUrl}}/file/someid/thumbnail".
+
+The base URL for the API is "{{apiUrl}}", all paths below are relative to that
+URL.
+
+## Form value order
+
+I recommend you put files at the end of every file upload form. By doing this
+the pixeldrain server can respond to malformed requests before the file upload
+finishes and this may save you a lot of time and bandwidth when uploading large
+files. Make sure your HTTP client has support for premature responses,
+pixeldrain uses them a lot. If the server responds before your request is
+finished it will always indicate an error and you may abort the connection.
+
+
+{{template "api_file.md"}}
+{{template "api_list.md"}}
+{{template "api_user.md"}}
diff --git a/res/include/md/api_file.md b/res/include/md/api_file.md
new file mode 100644
index 0000000..f683840
--- /dev/null
+++ b/res/include/md/api_file.md
@@ -0,0 +1,267 @@
+## File Methods
+
+
+POST/file
+
+
+### Description
+
+Upload a file.
+
+### Parameters
+
+Param | Type | Required | Maximum Size | Default | Description
+----------|----------------|----------|------------------------------|---------------------|-----------------------------------
+name | string | false | 255 characters | multipart file name | Name of the file to upload
+anonymous | boolean | false | N/A | false | File is not linked to user if true
+file | multipart file | true | Depends on user subscription | none | File to upload
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "abc123" // ID of the newly uploaded file
+}
+```
+
+HTTP 422: Unprocessable Entity
+```
+{
+ "success": false,
+ "value": "no_file",
+ "message": "The file does not exist or is empty."
+}
+```
+
+HTTP 500: Internal Server Error
+```
+{
+ "success": false,
+ "value": "internal",
+ "message": "An internal server error occurred."
+}
+```
+
+HTTP 413: Payload Too Large
+```
+{
+ "success": false,
+ "value": "file_too_large",
+ "message": "The file you tried to upload is too large"
+}
+```
+
+HTTP 500: Internal Server Error
+```
+{
+ "success": false,
+ "value": "writing",
+ "message": "Something went wrong while writing the file to disk, the server may be out of storage space."
+}
+```
+
+HTTP 413: Payload Too Large
+```
+{
+ "success": false,
+ "value": "name_too_long",
+ "message": "File Name is too long, Max 255 characters allowed."
+}
+```
+
+
+
+
+GET/file/{id}
+
+
+### Description
+
+Returns the full file associated with the ID. Supports byte range requests.
+
+When '?download' is added to the URL the server will send an attachment header
+instead of inline rendering, which causes the browser to show a 'Save File'
+dialog.
+
+Warning: If a file is using too much bandwidth it can be rate limited. The rate
+limit will be enabled if a file has ten times more downloads than views. The
+owner of a file can always download it. When a file is rate limited the user
+will need to fill out a captcha in order to continue downloading the file. The
+captcha will only appear on the file viewer page (pixeldrain.com/u/{id}). Rate
+limiting has been added to prevent the spread of viruses and to stop direct
+linking.
+
+Pixeldrain also includes a virus scanner. If a virus has been detected in a file
+the user will also have to fill in a captcha to download it.
+
+### Parameters
+
+Param | Required | Location | Description
+---------|----------|----------|------------------------------------------
+id | true | URL | ID of the file to request
+download | false | URL | Sends attachment header instead of inline
+
+### Returns
+
+```
+HTTP 200: OK
+
+Requested file data
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "not_found",
+ "message": "The entity you requested could not be found"
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "file_rate_limited_captcha_required",
+ "message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page"
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "virus_detected_captcha_required",
+ "message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page"
+}
+```
+
+
+
+
+GET/file/{id}/info
+
+
+### Description
+
+Returns information about one or more files. You can also put a comma separated
+list of file IDs in the URL and it will return an array of file info, instead of
+a single object.
+
+### Parameters
+
+Param | Required | Location | Description
+------|----------|----------|---------------
+id | true | URL | ID of the file
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "1234abcd",
+ "name": "screenshot.png",
+ "date_upload": 2020-02-04T18:34:05.706801Z,
+ "date_last_view": 2020-02-04T18:34:05.706801Z,
+ "size": 5694837, // Bytes
+ "views" 1234, // Amount of unique file views
+ "bandwidth_used": 1234567890, // Bytes
+ "mime_type" "image/png",
+ "thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file
+}
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "file_not_found"
+}
+```
+
+
+
+
+GET/file/{id}/thumbnail?width=x&height=x
+
+
+### Description
+
+Returns a PNG thumbnail image representing the file. The thumbnail image will be
+128x128 px by default. You can specify the width and height with parameters in
+the URL. The width and height parameters need to be a multiple of 16. So the
+allowed values are 16, 32, 48, 64, 80, 96, 112 and 128. If a thumbnail cannot be
+generated for the file you will be redirected to a mime type image of 128x128
+px.
+
+### Parameters
+
+Param | Required | Location | Description
+-------|----------|----------|--------------------------------------
+id | true | URL | ID of the file to get a thumbnail for
+width | false | URL | Width of the thumbnail image
+height | false | URL | Height of the thumbnail image
+
+### Returns
+
+A PNG image if a thumbnail can be generated. If a thumbnail cannot be generated
+you will get a 301 redirect to an image representing the type of the file.
+
+
+
+
+DELETE/file/{id}
+
+
+### Description
+
+Deletes a file. Only works when the users owns the file.
+
+### Parameters
+
+Param | Required | Location | Description
+------|----------|----------|-------------------------
+id | true | URL | ID of the file to delete
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "value": "file_deleted",
+ "message": "The file has been deleted."
+}
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "file_not_found",
+ "message": "File ID was not found in the database."
+}
+```
+
+HTTP 401: Unauthorized
+```
+{
+ "success": false,
+ "value": "unauthorized",
+ "message": "You are not logged in."
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "forbidden",
+ "message": "This is not your file."
+}
+```
+
+
diff --git a/res/include/md/api_file_post.md b/res/include/md/api_file_post.md
new file mode 100644
index 0000000..f683840
--- /dev/null
+++ b/res/include/md/api_file_post.md
@@ -0,0 +1,267 @@
+## File Methods
+
+
+POST/file
+
+
+### Description
+
+Upload a file.
+
+### Parameters
+
+Param | Type | Required | Maximum Size | Default | Description
+----------|----------------|----------|------------------------------|---------------------|-----------------------------------
+name | string | false | 255 characters | multipart file name | Name of the file to upload
+anonymous | boolean | false | N/A | false | File is not linked to user if true
+file | multipart file | true | Depends on user subscription | none | File to upload
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "abc123" // ID of the newly uploaded file
+}
+```
+
+HTTP 422: Unprocessable Entity
+```
+{
+ "success": false,
+ "value": "no_file",
+ "message": "The file does not exist or is empty."
+}
+```
+
+HTTP 500: Internal Server Error
+```
+{
+ "success": false,
+ "value": "internal",
+ "message": "An internal server error occurred."
+}
+```
+
+HTTP 413: Payload Too Large
+```
+{
+ "success": false,
+ "value": "file_too_large",
+ "message": "The file you tried to upload is too large"
+}
+```
+
+HTTP 500: Internal Server Error
+```
+{
+ "success": false,
+ "value": "writing",
+ "message": "Something went wrong while writing the file to disk, the server may be out of storage space."
+}
+```
+
+HTTP 413: Payload Too Large
+```
+{
+ "success": false,
+ "value": "name_too_long",
+ "message": "File Name is too long, Max 255 characters allowed."
+}
+```
+
+
+
+
+GET/file/{id}
+
+
+### Description
+
+Returns the full file associated with the ID. Supports byte range requests.
+
+When '?download' is added to the URL the server will send an attachment header
+instead of inline rendering, which causes the browser to show a 'Save File'
+dialog.
+
+Warning: If a file is using too much bandwidth it can be rate limited. The rate
+limit will be enabled if a file has ten times more downloads than views. The
+owner of a file can always download it. When a file is rate limited the user
+will need to fill out a captcha in order to continue downloading the file. The
+captcha will only appear on the file viewer page (pixeldrain.com/u/{id}). Rate
+limiting has been added to prevent the spread of viruses and to stop direct
+linking.
+
+Pixeldrain also includes a virus scanner. If a virus has been detected in a file
+the user will also have to fill in a captcha to download it.
+
+### Parameters
+
+Param | Required | Location | Description
+---------|----------|----------|------------------------------------------
+id | true | URL | ID of the file to request
+download | false | URL | Sends attachment header instead of inline
+
+### Returns
+
+```
+HTTP 200: OK
+
+Requested file data
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "not_found",
+ "message": "The entity you requested could not be found"
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "file_rate_limited_captcha_required",
+ "message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page"
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "virus_detected_captcha_required",
+ "message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page"
+}
+```
+
+
+
+
+GET/file/{id}/info
+
+
+### Description
+
+Returns information about one or more files. You can also put a comma separated
+list of file IDs in the URL and it will return an array of file info, instead of
+a single object.
+
+### Parameters
+
+Param | Required | Location | Description
+------|----------|----------|---------------
+id | true | URL | ID of the file
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "1234abcd",
+ "name": "screenshot.png",
+ "date_upload": 2020-02-04T18:34:05.706801Z,
+ "date_last_view": 2020-02-04T18:34:05.706801Z,
+ "size": 5694837, // Bytes
+ "views" 1234, // Amount of unique file views
+ "bandwidth_used": 1234567890, // Bytes
+ "mime_type" "image/png",
+ "thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file
+}
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "file_not_found"
+}
+```
+
+
+
+
+GET/file/{id}/thumbnail?width=x&height=x
+
+
+### Description
+
+Returns a PNG thumbnail image representing the file. The thumbnail image will be
+128x128 px by default. You can specify the width and height with parameters in
+the URL. The width and height parameters need to be a multiple of 16. So the
+allowed values are 16, 32, 48, 64, 80, 96, 112 and 128. If a thumbnail cannot be
+generated for the file you will be redirected to a mime type image of 128x128
+px.
+
+### Parameters
+
+Param | Required | Location | Description
+-------|----------|----------|--------------------------------------
+id | true | URL | ID of the file to get a thumbnail for
+width | false | URL | Width of the thumbnail image
+height | false | URL | Height of the thumbnail image
+
+### Returns
+
+A PNG image if a thumbnail can be generated. If a thumbnail cannot be generated
+you will get a 301 redirect to an image representing the type of the file.
+
+
+
+
+DELETE/file/{id}
+
+
+### Description
+
+Deletes a file. Only works when the users owns the file.
+
+### Parameters
+
+Param | Required | Location | Description
+------|----------|----------|-------------------------
+id | true | URL | ID of the file to delete
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "value": "file_deleted",
+ "message": "The file has been deleted."
+}
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "file_not_found",
+ "message": "File ID was not found in the database."
+}
+```
+
+HTTP 401: Unauthorized
+```
+{
+ "success": false,
+ "value": "unauthorized",
+ "message": "You are not logged in."
+}
+```
+
+HTTP 403: Forbidden
+```
+{
+ "success": false,
+ "value": "forbidden",
+ "message": "This is not your file."
+}
+```
+
+
diff --git a/res/include/md/api_filesystem.md b/res/include/md/api_filesystem.md
new file mode 100644
index 0000000..cb6bcda
--- /dev/null
+++ b/res/include/md/api_filesystem.md
@@ -0,0 +1,160 @@
+## Filesystem Methods
+
+
+ POST/filesystem/{path}
+
+
Description
+
+ Creates a new directory or uploads a file to an existing directory.
+
+
+
Parameters
+
+ The form parameters must be sent in the order displayed below
+ for the realtime error checking to work. If 'name' comes after
+ 'file' it will be ignored.
+
+
+
+ Param |
+ Location |
+ Description |
+
+
+ type |
+ Form Values |
+ The type of node to create, can either be 'directory', or 'file' |
+
+
+ name |
+ Form Values |
+
+ Name of the directory to create, or of file to create. Not
+ required if 'type' is 'file'
+ |
+
+
+ file |
+ Form Values |
+
+ Multipart file to upload to the directory. Will be ignored
+ if 'type' is 'directory'
+ |
+
+
+
+
Returns
+
HTTP 200: OK
+{
+ "success": true,
+ "id": "abc123" // ID of the newly uploaded file
+}
+ todo
+
+
+
+
+ GET/filesystem/{path}
+
+
Description
+
+ Returns information about the requested path.
+
+
Parameters
+
+
+ Param |
+ Required |
+ Location |
+ Description |
+
+
+ path |
+ true |
+ URL |
+ Path to the directory or file to request |
+
+
+ download |
+ false |
+ URL |
+
+ If the URL paramater '?download' is passed the requested
+ file will be downloaded (if it is a file)
+ |
+
+
+
Returns
+
When the requested entity is a directory:
+
HTTP 200: OK
+{
+ "success": true,
+ "name": "some dir",
+ "path": "/some dir",
+ "type": "directory",
+ "child_directories": [
+ {
+ "name": "some other directory",
+ "type": "directory",
+ "path": "/some dir/some other directory"
+ }
+ ],
+ "child_files": [
+ {
+ "name": "11. Lenny Kravitz - Fly away.ogg",
+ "type": "file",
+ "path": "/some dir/11. Lenny Kravitz - Fly away.ogg"
+ }
+ ]
+}
+
When the requested entity is a file:
+
HTTP 200: OK
+{
+ "success": true,
+ "name": "11. Lenny Kravitz - Fly away.ogg",
+ "path": "/some dir/11. Lenny Kravitz - Fly away.ogg",
+ "type": "file",
+ "file_info": {
+ "success": true,
+ "id": "Jf_u5TI9",
+ "name": "11. Lenny Kravitz - Fly away.ogg",
+ "date_upload": "2018-07-04T22:24:48Z",
+ "date_last_view": "2018-07-04T22:24:48Z",
+ "size": 9757269,
+ "views": 0,
+ "mime_type": "application/ogg",
+ "thumbnail_href": "/file/Jf_u5TI9/thumbnail"
+ }
+}
+
+
+
+
+ DELETE/filesystem/{path}
+
+
Description
+
+ Deletes a filesystem node.
+
+
Parameters
+
+
+ Param |
+ Required |
+ Location |
+ Description |
+
+
+ path |
+ true |
+ URL |
+ Path of the entity to delete |
+
+
+
Returns
+
HTTP 200: OK
+{
+ "success": true
+}
+
+
diff --git a/res/include/md/api_list.md b/res/include/md/api_list.md
new file mode 100644
index 0000000..dabe7bc
--- /dev/null
+++ b/res/include/md/api_list.md
@@ -0,0 +1,188 @@
+## List Methods
+
+
+POST/list
+
+
+### Description
+
+Creates a list of files that can be viewed together on the file viewer page.
+
+### Parameters
+
+POST body should be a JSON object, example below. A list can contain at most
+10000 files. If you try to add more the request will fail.
+
+#### Example
+```
+{
+ "title": "My beautiful photos", // Defaults to "Pixeldrain List"
+ "anonymous": false / true, // If true this list will not be linked to your user account. Defaults to "false"
+ "files": [ // Ordered array of files to add to the list
+ {
+ "id": "abc123",
+ "description": "First photo of the week, such a beautiful valley"
+ },
+ {
+ "id": "123abc",
+ "description": "The week went by so quickly, here's a photo from the plane back"
+ }
+ ]
+}
+```
+
+### Returns
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "yay137" // ID of the newly created list
+}
+```
+
+HTTP 422: Unprocessable Entity
+```
+{
+ "success": false,
+ "value": "list_file_not_found",
+ "message": "File Oh42No was not found in the database.",
+ "extra": {
+ "file_not_found": "0h42No" // The file you tried to add with this ID does not exist
+ }
+}
+```
+
+HTTP 413: Payload too large
+```
+{
+ "success": false,
+ "value": "too_many_files",
+ "message": "This list contains too many files, max 10000 allowed."
+}
+```
+
+HTTP 422: Unprocessable Entity
+```
+{
+ "success": false,
+ "value": "json_parse_failed",
+ "message": "The JSON object in the request body could not be read."
+}
+```
+
+HTTP 413: Payload too large
+```
+{
+ "success": false,
+ "value": "title_too_long",
+ "message": "The title of this list is too long, max 300 characters allowed."
+}
+```
+
+HTTP 413: Payload too large
+```
+{
+ "success": false,
+ "value": "description_too_long",
+ "message": "The description of one of the files in the list is too long, max 3000 characters allowed."
+}
+```
+
+HTTP 422: Unprocessable Entity
+```
+{
+ "success": false,
+ "value": "cannot_create_empty_list",
+ "message": "You cannot make a list with no files."
+}
+```
+
+
+
+
+GET/list/{id}
+
+
+### Description
+
+Returns information about a file list and the files in it.
+
+### Parameters
+
+
+Param | Required | Location | Description
+------|----------|----------|---------------
+id | true | URL | ID of the list
+
+### Returns
+
+The API will return some basic information about every file. Every file also has
+a "detail_href" field which contains a URL to the info API of the file. Follow
+that link to get more information about the file like size, checksum, mime type,
+etc. The address is relative to the API URL and should be appended to the end.
+
+HTTP 200: OK
+```
+{
+ "success": true,
+ "id": "L8bhwx",
+ "title": "Rust in Peace",
+ "date_created": 2020-02-04T18:34:13.466276Z,
+ "files": [
+ // These structures are the same as the file info response, except for the detail_href and description fields
+ {
+ "detail_href": "/file/_SqVWi/info",
+ "description": "",
+ "success": true,
+ "id": "_SqVWi",
+ "name": "01 Holy Wars... The Punishment Due.mp3",
+ "size": 123456,
+ "date_created": 2020-02-04T18:34:13.466276Z,
+ "date_last_view": 2020-02-04T18:34:13.466276Z,
+ "mime_type": "audio/mp3",
+ "views": 1,
+ "bandwidth_used": 1234567890,
+ "thumbnail_href": "/file/_SqVWi/thumbnail"
+ },
+ {
+ "detail_href": "/file/RKwgZb/info",
+ "description": "",
+ "success": true,
+ "id": "RKwgZb",
+ "name": "02 Hangar 18.mp3",
+ "size": 123456,
+ "date_created": 2020-02-04T18:34:13.466276Z,
+ "date_last_view": 2020-02-04T18:34:13.466276Z,
+ "mime_type": "audio/mp3",
+ "views": 2,
+ "bandwidth_used": 1234567890,
+ "thumbnail_href": "/file/RKwgZb/thumbnail"
+ },
+ {
+ "detail_href": "/file/DRaL_e/info",
+ "description": "",
+ "success": true,
+ "id": "DRaL_e",
+ "name": "03 Take No Prisoners.mp3",
+ "size": 123456,
+ "date_created": 2020-02-04T18:34:13.466276Z,
+ "date_last_view": 2020-02-04T18:34:13.466276Z,
+ "mime_type": "audio/mp3",
+ "views": 3,
+ "bandwidth_used": 1234567890,
+ "thumbnail_href": "/file/DRaL_e/thumbnail"
+ }
+ ]
+}
+```
+
+HTTP 404: Not Found
+```
+{
+ "success": false,
+ "value": "list_not_found",
+}
+```
+
+
diff --git a/res/include/md/api_user.md b/res/include/md/api_user.md
new file mode 100644
index 0000000..643ce8c
--- /dev/null
+++ b/res/include/md/api_user.md
@@ -0,0 +1,18 @@
+## User Methods
+
+These methods all require authentication.
+
+
+ GET/user/files
+
+ Documentation pending. Click here to see the response for your account:
+ [/user/files](/api/user/files).
+
+
+
+ GET/user/lists
+
+ Documentation pending. Click here to see the response for your account:
+ [/user/lists](/api/user/lists).
+
+
diff --git a/res/include/md/apidoc.md b/res/include/md/apidoc.md
deleted file mode 100644
index fdc78d7..0000000
--- a/res/include/md/apidoc.md
+++ /dev/null
@@ -1,644 +0,0 @@
-# Pixeldrain API documentation
-
-The methods for uploading and retrieving files don't require an API key. The
-methods for creating and retrieving lists also don't require an API key. All
-methods which delete or modify a resource **do** require an API key.
-
-API keys can be obtained from the login API.
-
-Some JSON responses include fields which end in "_href" (some people don't know
-this, but "href" stands for "Hypertext Reference", the more you know). These
-point to different places in the API, which you can retrieve with a GET request.
-The path is to be appended to the API URL, so "/file/someid/thumbnail" becomes
-"{{apiUrl}}/file/someid/thumbnail".
-
-The base URL for the API is "{{apiUrl}}", all paths below are relative to that
-URL.
-
-## Form value order
-
-I recommend you put files at the end of every file upload form. By doing this
-the pixeldrain server can respond to malformed requests before the file upload
-finishes and this may save you a lot of time and bandwidth when uploading large
-files. Make sure your HTTP client has support for premature responses,
-pixeldrain uses them a lot. If the server responds before your request is
-finished it will always indicate an error and you may abort the connection.
-
-## File Methods
-
-
-POST/file
-
-
-### Description
-
-Upload a file.
-
-### Parameters
-
-Param | Type | Required | Maximum Size | Default | Description
-----------|----------------|----------|----------------|---------------------|-----------------------------------
-name | string | false | 255 characters | multipart file name | Name of the file to upload
-anonymous | boolean | false | N/A | false | File is not linked to user if true
-file | multipart file | true | 1000^3 bytes | none | File to upload
-
-### Returns
-
-HTTP 200: OK
-```
-{
- "success": true,
- "id": "abc123" // ID of the newly uploaded file
-}
-```
-
-HTTP 422: Unprocessable Entity
-```
-{
- "success": false,
- "value": "no_file",
- "message": "The file does not exist or is empty."
-}
-```
-
-HTTP 500: Internal Server Error
-```
-{
- "success": false,
- "value": "internal",
- "message": "An internal server error occurred."
-}
-```
-
-HTTP 413: Payload Too Large
-```
-{
- "success": false,
- "value": "file_too_large",
- "message": "The file you tried to upload is too large"
-}
-```
-
-HTTP 500: Internal Server Error
-```
-{
- "success": false,
- "value": "writing",
- "message": "Something went wrong while writing the file to disk, the server may be out of storage space."
-}
-```
-
-HTTP 413: Payload Too Large
-```
-{
- "success": false,
- "value": "name_too_long",
- "message": "File Name is too long, Max 255 characters allowed."
-}
-```
-
-
-
-
-GET/file/{id}
-
-
-### Description
-
-Returns the full file associated with the ID. Supports byte range requests.
-
-When '?download' is added to the URL the server will send an attachment header
-instead of inline rendering, which causes the browser to show a 'Save File'
-dialog.
-
-Warning: If a file is using too much bandwidth it can be rate limited. The rate
-limit will be enabled if a file has ten times more downloads than views. The
-owner of a file can always download it. When a file is rate limited the user
-will need to fill out a captcha in order to continue downloading the file. The
-captcha will only appear on the file viewer page (pixeldrain.com/u/{id}). Rate
-limiting has been added to prevent the spread of viruses and to stop direct
-linking.
-
-Pixeldrain also includes a virus scanner. If a virus has been detected in a file
-the user will also have to fill in a captcha to download it.
-
-### Parameters
-
-Param | Required | Location | Description
----------|----------|----------|------------------------------------------
-id | true | URL | ID of the file to request
-download | false | URL | Sends attachment header instead of inline
-
-### Returns
-
-```
-HTTP 200: OK
-
-Requested file data
-```
-
-HTTP 404: Not Found
-```
-{
- "success": false,
- "value": "not_found",
- "message": "The entity you requested could not be found"
-}
-```
-
-HTTP 403: Forbidden
-```
-{
- "success": false,
- "value": "file_rate_limited_captcha_required",
- "message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page"
-}
-```
-
-HTTP 403: Forbidden
-```
-{
- "success": false,
- "value": "virus_detected_captcha_required",
- "message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page"
-}
-```
-
-
-
-
-GET/file/{id}/info
-
-
-### Description
-
-Returns information about one or more files. You can also put a comma separated
-list of file IDs in the URL and it will return an array of file info, instead of
-a single object.
-
-### Parameters
-
-Param | Required | Location | Description
-------|----------|----------|---------------
-id | true | URL | ID of the file
-
-### Returns
-
-HTTP 200: OK
-```
-{
- "success": true,
- "id": "1234abcd",
- "name": "screenshot.png",
- "date_upload": 2020-02-04T18:34:05.706801Z,
- "date_last_view": 2020-02-04T18:34:05.706801Z,
- "size": 5694837, // Bytes
- "views" 1234, // Amount of unique file views
- "bandwidth_used": 1234567890, // Bytes
- "mime_type" "image/png",
- "thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file
-}
-```
-
-HTTP 404: Not Found
-```
-{
- "success": false,
- "value": "file_not_found"
-}
-```
-
-
-
-
-
-## List Methods
-
-
-POST/list
-
-
-### Description
-
-Creates a list of files that can be viewed together on the file viewer page.
-
-### Parameters
-
-POST body should be a JSON object, example below. A list can contain at most
-10000 files. If you try to add more the request will fail.
-
-#### Example
-```
-{
- "title": "My beautiful photos", // Defaults to "Pixeldrain List"
- "anonymous": false / true, // If true this list will not be linked to your user account. Defaults to "false"
- "files": [ // Ordered array of files to add to the list
- {
- "id": "abc123",
- "description": "First photo of the week, such a beautiful valley"
- },
- {
- "id": "123abc",
- "description": "The week went by so quickly, here's a photo from the plane back"
- }
- ]
-}
-```
-
-### Returns
-
-HTTP 200: OK
-```
-{
- "success": true,
- "id": "yay137" // ID of the newly created list
-}
-```
-
-HTTP 422: Unprocessable Entity
-```
-{
- "success": false,
- "value": "list_file_not_found",
- "message": "File Oh42No was not found in the database.",
- "extra": {
- "file_not_found": "0h42No" // The file you tried to add with this ID does not exist
- }
-}
-```
-
-HTTP 413: Payload too large
-```
-{
- "success": false,
- "value": "too_many_files",
- "message": "This list contains too many files, max 10000 allowed."
-}
-```
-
-HTTP 422: Unprocessable Entity
-```
-{
- "success": false,
- "value": "json_parse_failed",
- "message": "The JSON object in the request body could not be read."
-}
-```
-
-HTTP 413: Payload too large
-```
-{
- "success": false,
- "value": "title_too_long",
- "message": "The title of this list is too long, max 300 characters allowed."
-}
-```
-
-HTTP 413: Payload too large
-```
-{
- "success": false,
- "value": "description_too_long",
- "message": "The description of one of the files in the list is too long, max 3000 characters allowed."
-}
-```
-
-HTTP 422: Unprocessable Entity
-```
-{
- "success": false,
- "value": "cannot_create_empty_list",
- "message": "You cannot make a list with no files."
-}
-```
-
-
-
-
-GET/list/{id}
-
-
-### Description
-
-Returns information about a file list and the files in it.
-
-### Parameters
-
-
-Param | Required | Location | Description
-------|----------|----------|---------------
-id | true | URL | ID of the list
-
-### Returns
-
-The API will return some basic information about every file. Every file also has
-a "detail_href" field which contains a URL to the info API of the file. Follow
-that link to get more information about the file like size, checksum, mime type,
-etc. The address is relative to the API URL and should be appended to the end.
-
-HTTP 200: OK
-```
-{
- "success": true,
- "id": "L8bhwx",
- "title": "Rust in Peace",
- "date_created": 2020-02-04T18:34:13.466276Z,
- "files": [
- // These structures are the same as the file info response, except for the detail_href and description fields
- {
- "detail_href": "/file/_SqVWi/info",
- "description": "",
- "success": true,
- "id": "_SqVWi",
- "name": "01 Holy Wars... The Punishment Due.mp3",
- "size": 123456,
- "date_created": 2020-02-04T18:34:13.466276Z,
- "date_last_view": 2020-02-04T18:34:13.466276Z,
- "mime_type": "audio/mp3",
- "views": 1,
- "bandwidth_used": 1234567890,
- "thumbnail_href": "/file/_SqVWi/thumbnail"
- },
- {
- "detail_href": "/file/RKwgZb/info",
- "description": "",
- "success": true,
- "id": "RKwgZb",
- "name": "02 Hangar 18.mp3",
- "size": 123456,
- "date_created": 2020-02-04T18:34:13.466276Z,
- "date_last_view": 2020-02-04T18:34:13.466276Z,
- "mime_type": "audio/mp3",
- "views": 2,
- "bandwidth_used": 1234567890,
- "thumbnail_href": "/file/RKwgZb/thumbnail"
- },
- {
- "detail_href": "/file/DRaL_e/info",
- "description": "",
- "success": true,
- "id": "DRaL_e",
- "name": "03 Take No Prisoners.mp3",
- "size": 123456,
- "date_created": 2020-02-04T18:34:13.466276Z,
- "date_last_view": 2020-02-04T18:34:13.466276Z,
- "mime_type": "audio/mp3",
- "views": 3,
- "bandwidth_used": 1234567890,
- "thumbnail_href": "/file/DRaL_e/thumbnail"
- }
- ]
-}
-```
-
-HTTP 404: Not Found
-```
-{
- "success": false,
- "value": "list_not_found",
-}
-```
-
-
-
-
diff --git a/webcontroller/web_controller.go b/webcontroller/web_controller.go
index 94050f8..7781216 100644
--- a/webcontroller/web_controller.go
+++ b/webcontroller/web_controller.go
@@ -131,7 +131,7 @@ func New(
}{
// General navigation
{GET, "" /* */, wc.serveTemplate("home", handlerOpts{})},
- {GET, "api" /* */, wc.serveMarkdown("apidoc.md", handlerOpts{})},
+ {GET, "api" /* */, wc.serveMarkdown("api.md", handlerOpts{})},
{GET, "history" /* */, wc.serveTemplate("history_cookies", handlerOpts{})},
{GET, "u/:id" /* */, wc.serveFileViewer},
{GET, "u/:id/preview" /* */, wc.serveFilePreview},
@@ -160,7 +160,6 @@ func New(
{GET, "logout" /* */, wc.serveTemplate("logout", handlerOpts{Auth: true, NoEmbed: true})},
{PST, "logout" /* */, wc.serveLogout},
{GET, "user_old" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
- {GET, "user" /* */, wc.serveTemplate("user_home_svelte", handlerOpts{Auth: true})},
{GET, "user/files" /* */, wc.serveTemplate("user_files", handlerOpts{Auth: true})},
{GET, "user/lists" /* */, wc.serveTemplate("user_lists", handlerOpts{Auth: true})},
{GET, "user/buckets" /* */, wc.serveTemplate("user_buckets", handlerOpts{Auth: true})},
@@ -169,7 +168,9 @@ func New(
{GET, "user/export/lists" /**/, wc.serveUserExportLists},
// User account settings
+ {GET, "user" /* */, wc.serveTemplate("user_home_svelte", handlerOpts{Auth: true})},
{GET, "user/settings" /* */, wc.serveTemplate("user_home_svelte", handlerOpts{Auth: true})},
+ {GET, "user/api_keys" /* */, wc.serveTemplate("user_home_svelte", handlerOpts{Auth: true})},
{GET, "user/settings_old" /* */, wc.serveUserSettings},
{PST, "user/settings_old" /* */, wc.serveUserSettings},
{GET, "user/confirm_email" /* */, wc.serveEmailConfirm},