Publish snippets and Markdown posts through authenticated uploads
This commit is contained in:
@@ -155,6 +155,112 @@ The token is visible in the shortcut editor; remove it before sharing the shortc
|
||||
Rotate it by replacing the token file and recreating the upload container with
|
||||
`podman compose up -d --force-recreate upload`.
|
||||
|
||||
## Snippets shortcut
|
||||
|
||||
The same service and token also publish to `https://theread.me/snippets/`.
|
||||
Text stays literal (including line breaks and Persian text); standalone HTTP/HTTPS
|
||||
URL lines become clickable links. Images use the same optimization and metadata
|
||||
removal as photo uploads. Each submission is prepended below the introduction,
|
||||
with a separator from the previous snippet. Existing snippets are preserved.
|
||||
|
||||
Create **Publish snippet**:
|
||||
|
||||
1. Enable **Show in Share Sheet**, accepting **Text**, **URLs**, and **Images**.
|
||||
2. **Repeat with Each** item in **Shortcut Input**. Use **Get Type** on the repeat
|
||||
item. If it is **Image**, add the item to a variable called **Snippet Images**.
|
||||
Otherwise use **Get Text from Input** on the item and add its result to
|
||||
**Snippet Text**. These variables accumulate the shared items during this run.
|
||||
3. **Combine Text** from **Snippet Text**, separated by **New Lines**. For an
|
||||
image-only share, leave the text empty. Don't fetch the contents of shared URLs:
|
||||
send the link itself.
|
||||
4. **Ask for Input** (Text): “Note (optional)”. Keep its output separate from the
|
||||
shared text. You can also run the shortcut without shared input and use a text
|
||||
prompt as **Snippet Text** to write a new snippet.
|
||||
5. **Get Contents of URL**: `https://theread.me/api/snippets`, method **POST**,
|
||||
request body **Form**:
|
||||
- Header `Authorization`: `Bearer YOUR_TOKEN` (same token as photos).
|
||||
- `text`: **Text**, the combined shared text.
|
||||
- `caption`: **Text**, the optional note.
|
||||
- `photos`: **File**, **Snippet Images**, when sharing images. For text-only
|
||||
requests, omit this field. Use an **If** on whether there are images to choose
|
||||
between the form with `photos` and the text-only form.
|
||||
- Delete any blank header rows. Do not manually set `Content-Type`.
|
||||
6. **Show Result** using the actual response. A response with `error` means the
|
||||
upload failed; don't show a fixed success message. `queued` means accepted;
|
||||
publishing happens afterwards. The returned `status_url` can be polled with the
|
||||
same authorization header; `published` confirms deployment.
|
||||
|
||||
For the simplest initial shortcut, accept just Text and URLs and omit the image
|
||||
branch and `photos` field; add the image branch when that works on your phone.
|
||||
|
||||
`POST /api/snippets` accepts up to 20,000 characters of `text`, an optional
|
||||
4,000-character `caption`, and up to 20 images in repeated `photos` parts, within
|
||||
the existing 100 MiB request limit. At least text or an image is required.
|
||||
It returns `id`, `count` (image count), `url`, `status_url`, and `status`.
|
||||
`GET /api/snippets/<id>` checks publication, and
|
||||
`POST /api/snippets/<id>/retry` retries failed Git publication. Identical text,
|
||||
note, and original images in the same order are deduplicated.
|
||||
|
||||
Keep `<!-- uploaded-snippets -->` in `snippets.md`: it marks the insertion point.
|
||||
The publisher fails safely if that marker is removed. GitHub Actions includes
|
||||
rendered snippet IDs in `photo-publication.json`, alongside photo IDs.
|
||||
|
||||
## Markdown blog-post shortcut
|
||||
|
||||
Create **Publish blog post** and enable **Show in Share Sheet**, accepting **Files**.
|
||||
Share one UTF-8 `.md` or `.markdown` file, up to 1 MiB. In **Get Contents of URL**:
|
||||
|
||||
- URL: `https://theread.me/api/posts`; method **POST**; request body **Form**.
|
||||
- Header: `Authorization` = `Bearer YOUR_TOKEN` (no empty header rows).
|
||||
- Form field `file`: type **File**, value **Shortcut Input**.
|
||||
- Let Shortcuts set `Content-Type` automatically.
|
||||
|
||||
Show the actual response, and poll `https://theread.me` plus its `status_url`
|
||||
with the same header. Matching happens in the publisher: `202` only means the
|
||||
file was accepted, not that a new post or update was published. The status
|
||||
response supplies the final `url`, `post_id`, and `action` (`created` or `updated`).
|
||||
`failed` includes an error; `published` confirms the deployed revision. An older
|
||||
upload can become `superseded` when a newer revision replaces it.
|
||||
|
||||
No front matter is required. The first `# Heading` becomes the title, or the
|
||||
filename is used if there is no heading. Optional YAML front matter supports
|
||||
`title`, `subtitle`, `lang`, `description`, `categories`, `tags`, `toc`, `math`,
|
||||
`date`, and `permalink` (a path such as `/my-essay/`). Markdown formatting is
|
||||
preserved; Liquid template evaluation is disabled for imported post bodies.
|
||||
The original file is retained privately in the service volume.
|
||||
|
||||
### Automatic updates by content
|
||||
|
||||
The publisher compares the body against existing Markdown posts, ignoring front
|
||||
matter and whitespace changes. It updates a unique match with at least 92% word
|
||||
sequence similarity, at least 200 characters in both texts, and a lead of at
|
||||
least 8 percentage points over the next plausible match. An exact body match of
|
||||
at least 40 characters also qualifies. These scores are a conservative heuristic,
|
||||
not a probability. Renaming the file does not prevent matching; reusing a filename
|
||||
for unrelated writing does not overwrite its previous post.
|
||||
|
||||
If several posts match closely, the upload fails without changing Git. If no
|
||||
post meets the threshold, it creates a new post. Large rewrites and very short
|
||||
posts may therefore need an explicit ID. For a known imported post, add the
|
||||
returned `post_id` to its front matter to target it directly:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My revised essay
|
||||
post_id: THE_ID_FROM_THE_UPLOAD_STATUS
|
||||
---
|
||||
```
|
||||
|
||||
For an older Git-authored post, first add a unique `post_id` to that existing
|
||||
post's front matter and use the same ID in the uploaded file. Updates preserve
|
||||
the original publication date and public URL, and remain reversible through Git.
|
||||
Identical file retries are deduplicated and do not roll back a newer revision.
|
||||
|
||||
The upload takes the Markdown file only. Relative links to images or attachments
|
||||
in an export folder will not upload those files; use existing public image URLs.
|
||||
Export Markdown from the source app before sharing; proprietary note files,
|
||||
PDFs, ZIP bundles, and rich-text files are not Markdown uploads.
|
||||
|
||||
## API, failures, and backups
|
||||
|
||||
All API routes require the bearer token:
|
||||
|
||||
Reference in New Issue
Block a user