This is a bidirectional synchronizer for Write.As blogs, written in Go. It allows you to write your blog locally, using your favorite text editor or a specialized tool like Obsidian, and then sync your posts to your Write.As blog.
It also allows you to make changes in your Write.As blog, and then sync them back to your local copy.
writeas-sync also integrates with Snap.As, and transparently syncs images with your Snap.As account.
You can install writeas-sync using go get:
$ go install github.com/Cyberax/writeas-sync@latestThis will install the writeas-sync binary into your GOROOT:
$ ~/go/bin/writeas-sync
Synchronizer for your Markdown-based blog
Usage:
writeas-sync [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
download Pull remote changes to your local blog
help Help about any command
sync Synchronize your blog (upload and download)
upload Push your local changes to the remote blog
Flags:
-a, --alias string Write.as alias
-h, --help help for writeas-sync
-l, --login string Write.as login
-p, --password string Write.as password (uses WRITEAS_PASS environment variable if not specified)
-r, --root string Root directory of your blog (default "/Users/cyberax/go/bin")
-s, --snapas-endpoint string Snap.as API endpoint (default "https://snap.as/api")
-w, --writeas-endpoint string Write.as API endpoint (default "https://write.as/api")
Use "writeas-sync [command] --help" for more information about a command.Brew support and a Nix package are ComingSoon(tm).
First, you'll need to create a Write.As account. Then, you'll need to create a blog and get its alias. Make sure to create at least one blog post there.
Then you need to do the initial download, which will create a local copy of your blog in ~/blog:
$ export WRITEAS_PASS=<your password>
$ writeas-sync download --alias <your blog alias> --login <your login> --root ~/blog
2023/11/02 11:13:25 INFO Logging into Write.as
2023/11/02 11:13:26 INFO Building image map
2023/11/02 11:13:29 INFO Enumerating local posts rootDir=/Users/cyberax/blog
2023/11/02 11:13:29 INFO Found local posts num=0
2023/11/02 11:13:29 INFO Fetching the remote posts
2023/11/02 11:13:29 INFO Found remote posts num=5
2023/11/02 11:13:29 INFO Downloading new or changed remote posts
2023/11/02 11:13:29 INFO New remote post slug=testing-upload
2023/11/02 11:13:29 INFO Ensuring that the image path exists path=testing-upload
2023/11/02 11:13:29 INFO Downloading image url=https://i.snap.as/DFbKfX6U.jpeg dest=testing-upload/Bridge.jpeg
...This will create a directory tree that looks like this:
2022-08-14-multitenancy-in-postgresql.md
2023-01-24-untangling-the-aws-ssm.md
2023-03-17-benchmarking-go-and-c-async-await.md
2023-10-08-obsidian-writeas
2023-10-08-obsidian-writeas.md
2023-10-09-testing-upload.md
testing-upload
writeas-sync requires blog filenames to conform to the following format: YYYY-MM-DD-post-slug.md. The date
part is used to ensure the correct sorting order. The post-slug part is used to generate the post URL.
It is immutable, as all content URLs must forever be. So make sure to get it right on the first try :)
The first first-level caption of the post is used as the post title.
For example, you can create a simple post that references an image (of course, the image minerals/obsidian.jpg
needs to be present). You also can add tags to your posts, by adding a #tags at the last line of the post,
multiple tags need to be separated by spaces.
# This is an upload test
I like minerals. Here's Obsidian:

#obsidian #mineralsSave the post as 2023-11-02-frist-post.md and run the upload command:
$ export WRITEAS_PASS=<your password>
$ writeas-sync upload --alias <your blog alias> --login <your login> --root ~/blogThis will publish the post to your WriteAs blog, under the url: https://write.as/<alias>/frist-post. If you press
the Edit link on WriteAs, you'll see that the local image reference has been replaced with a link to SnapAs:
As a shortcut for download and upload, you can use the sync command that runs both:
$ export WRITEAS_PASS=<your password>
$ writeas-sync sync --alias <your blog alias> --login <your login> --root ~/blogYou can edit your posts using the Write.As web interface and synchronize the changes back to your local copy. However,
keep in mind that writeas-sync doesn't support merging changes. So if you edit the same post both locally and on
Write.As, the one with the latest timestamp will win.
I suggest keeping your local posts inside a Git repository, so that you can easily revert the changes if something ever goes wrong.
writeas-sync also doesn't support post deletion, so you need to make sure that you delete an unwanted post both
locally and remotely. Otherwise, it'll keep getting 'resurrected' with each sync.
writeas-sync supports simple image management via Snap.As. When you write a post locally, you can reference images in
subdirectories of your post directory. For example, if you have a post 2023-11-02-frist-post.md, you can reference
an image minerals/obsidian.jpg in it.
When you upload the post, writeas-sync will upload the image to Snap.As and replace the local image reference with
a link to the uploaded image. The source directory will be preserved in the filename property of the image on SnapAs.
If you edit or create a post on Write.As, they will lack the filename property, so writeas-sync will download
them into the subdirectory named after the post slug (essentially, the filename without the .md suffix).
Alternatively, you can use WebDAV to manage your images. In this case, you need to set --image-hosting-type flag
to webdav, and also specify the WebDAV endpoint and credentials if they are different from your Write.As credentials.
You also need to specify the WebDAV server URL via the --webdav-endpoint flag, and the publicly accessible URL that
corresponds to that endpoint.
For example, you might use a WebDAV server available at https://mydav.example.com:5060/myimages, and expose that
directory via https://myimages.example.com. In this case, you'd need to specify that public endpoint via the
--webdav-published-url flag.
Here's an example of the command line:
writeas-sync sync --image-hosting-type webdav --image-login imageupload --image-password 123 \
--webdav-endpoint https://mydav.example.com:5060/myimages --webdav-published-url https://myimages.example.com \
--alias <your_alias> --login <your_login> --root ~/blogAlternatively, you can use WRITEAS_WEBDAV_URL and WRITEAS_WEBDAV_PUBLISHED_URL environment variables to specify
the WebDAV endpoint and the published URL.
- The blog structure is very simple: it's just a list of posts, prefixed with a timestamp.
- The blog is stored in a single directory. If you have multiple blogs, you'll need to run multiple instances of the synchronizer.
- Snap.As processes the images, seriously degrading their quality.
- SnapAs integration doesn't support mutating images. So if you want to edit a local image, you need to change its filename.
- TODO: add support for collections in Snap.As.
- TODO: add GC support for unreferenced images in Snap.As.