docs: add mkdocs site :O

This commit is contained in:
Mark Joshwel 2024-06-18 18:59:55 +08:00
parent 40d318bef7
commit c6eadc6045
23 changed files with 2302 additions and 0 deletions

121
docs/CC0 Normal file
View file

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

325
docs/changelog.md Normal file
View file

@ -0,0 +1,325 @@
# changelog
## surplus v2024.0.0
(unreleased)
!!! information
this is a tentative release. surplus is currently versioned as `2024.0.0-beta`, as its
behaviour is not stabilized
!!! warning
this is an api-breaking release. see 'the great api break'.
command-line usage of surplus has not changed
### what's new
- added flag `--show-user-agent`, printing the fingerprinted user agent string and exiting
### what's changed
- `default_geocoder()` and `default_reverser()` have been deprecated since v2.1.0 and are now
removed. use the `SurplusDefaultGeocoding` class instead
- `SurplusException` is now `SurplusError`
### the great api break
TODO
### thanks!
- [vlshields](https://github.com/vlshields/) for their support with a drink!
full changelog: <https://github.com/markjoshwel/surplus/compare/v2.2.0...v2024.0.0>
## surplus on wheels v2
(released on the 1st of July 2024 on tag `v2.2024.25+spow`)
### changes
- you can now customize command invocations with `SURPLUS_CMD` and `LOCATION_CMD` environment variables
- surplus on wheels will purge logs when setting the `SPOW_PRIVATE` environment flag
### thanks!
- [vlshields](https://github.com/vlshields/) for their support with a drink!
---
## surplus on wheels: WhatsApp Bridge v2.2024.25
(released on the 17th of June 2024 on tag `v2.2024.25+spow-whatsapp-bridge`)
!!! note
from henceforth, the WhatsApp Bridge is now versioned with a modified calendar versioning scheme
of `MAJOR.YEAR.ISOWEEK`, where the `MAJOR` version segment will be bumped with codebase changes,
whereas the `YEAR` and `ISOWEEK` segments will represent the time of which the release was
built at
### changes
- updated dependencies to latest versions
- added `pair-phone` and `reconnect` subcommands
- TODO added optional helper script to auto-update to newer versions via a user-made daily cron job
### thanks!
- [vlshields](https://github.com/vlshields/) for their support with a drink!
---
## surplus on wheels: Telegram Bridge v2.2024.25
(released on the 17th of June 2024 on tag `v2.2024.25+spow-telegram-bridge`)
!!! note
from henceforth, the Telegram Bridge will automatically release a new version once a week if
there are updates to its dependencies
as such, the bridge is now versioned with a modified calendar versioning scheme of
`MAJOR.YEAR.ISOWEEK`, where the `MAJOR` version segment will be bumped with codebase changes,
whereas the `YEAR` and `ISOWEEK` segments will represent the time of which the release was
built at
### changes
- updated dependencies to latest versions
- added `logout` subcommand
- TODO added optional helper script to auto-update to newer versions via a user-made daily cron job
### thanks!
- [vlshields](https://github.com/vlshields/) for their support with a drink!
---
## surplus on wheels v1
initial release on the 9th of November 2023
---
## surplus on wheels: WhatsApp Bridge v1
initial release on the 7th of November 2023
---
## surplus on wheels: Telegram Bridge v1
initial release on the 7th of November 2023
---
## surplus v2.2.0
(released on the 14th of October 2023)
!!! warning
constants are changed in this update!
fixed a bug installing surplus on Python 3.12 and italian sharetext fixes
### what's new
- special key arrangements for malaysia
- support for termux-location json input
### what's fixed
- fixed typing-extensions as an unwritten dependency
this also fixes a bug in not being able to run surplus in Python 3.12
- fixed italian key arrangements [#34](https://github.com/markjoshwel/surplus/pull/34)
### what's changed
- **`SHAREABLE*` constants are now dictionaries, see api docs for more information**
<https://github.com/markjoshwel/surplus/compare/v2.1.1...v2.2.0>
---
## surplus v2.1.1
(released on the 19th of September 2023)
fix roads not coming first in Italian addresses (#31)
- documentation enhancements
- remove self in `SurplusReverserProtocol` conforming signature
- fix mismatching carets and add info on `split_iso3166_2`
- alternative line 3 arrangement for IT/Italy in [#31](https://github.com/markjoshwel/surplus/pull/31)
<https://github.com/markjoshwel/surplus/compare/v2.1.0...v2.1.1>
---
## surplus v2.1.0
(released on the 6th of September 2023)
!!! warning
there are backwards-compatible api changes in this release.
type-to-type location representation conversions and quality of life changes/fixes
- **`default_geocoder()` and `default_reverser()` functions have been deprecated in favour of the
new [`SurplusDefaultGeocoding` class](https://github.com/markjoshwel/surplus/tree/main#class-surplusdefaultgeocoding)**
- add reading from stdin when query is "-" in [#23](https://github.com/markjoshwel/surplus/pull/23)
- type to type conversion in [#24](https://github.com/markjoshwel/surplus/pull/24)
- fix local codes not being recognised if split with comma in [#29](https://github.com/markjoshwel/surplus/pull/29)
- more verbose -v/--version information in [#21](https://github.com/markjoshwel/surplus/pull/21)
<https://github.com/markjoshwel/surplus/compare/v2.0.1...v2.1.0>
---
## surplus v2.0.1
(released on the 5th of September 2023)
- expose surplus.Result in `__init__.py` by in [#28](https://github.com/markjoshwel/surplus/pull/28)
<https://github.com/markjoshwel/surplus/compare/v2.0.0...v2.0.1>
---
## surplus v2.0.0
(released on the 3rd of September 2023)
!!! warning
this is an api-breaking release. see 'the great api break'.
command-line usage of surplus has not changed
!!! information
python 3.11 or later is required due to a bug in earlier versions
[(python/cpython#88089)](https://github.com/python/cpython/issues/88089)
complete rewrite and string query support
### changes
- surplus has been fully rewritten in [#19](https://github.com/markjoshwel/surplus/pull/19)
- support for string queries
```text
$ s+ Wisma Atria
surplus version 2.0.0
Wisma Atria
435 Orchard Road
238877
Central, Singapore
```
- mypy will now recognise surplus as a typed module
- **python 3.11 is now the minimum version**
### the great api break
#### what is new
- nominatim keys are now stored in tuple constants
- surplus exception classes are now a thing
- surplus functions now operate using a unified `Behaviour` object
- surplus functions now return a `Result` object for safer value retrieval instead of the previous
`(bool, value)` tuple
- dedicated NamedTuple classes for each query type
#### what has been removed
- `surplus.handle_query()`
instead, use `.to_lat_long_coord()` on your surplus 2.x query object
#### what has remained
- `surplus.surplus()`, the function
- `surplus.parse_query()`, the function
#### what has changed
- `surplus.surplus()`
1. `reverser` and `debug` arguments are now under the unified `surplus.Behaviour` object
2. function now returns a `surplus.Result[str]` for safer error handling
- `surplus.parse_query()`
1. `query` and `debug` arguments are now under the unified `surplus.Behaviour` object
2. function now returns a `surplus.Result[surplus.Query]` for safer error handling
- `surplus.Latlong`
attributes `lat` and `long` have been renamed to `latitude` and `longitude` respectively
- `surplus.Localcode`
renamed to `surplus.LocalCodeQuery`
- `Localcode.full_length()`
renamed to `LocalCodeQuery.to_full_plus_code()`, and returns a `surplus.Result[str]` for safer
error handling
full changelog: <https://github.com/markjoshwel/surplus/compare/v1.1.3...v2.0.0>
## surplus v1.1.3
(released on the 21st of June 2023)
general output fixes and quality of life updates
- ci(qc) workflow tweaks by [markjoshwel](https://github.com/markjoshwel) in [#13](https://github.com/markjoshwel/surplus/pull/13)
- cc: remove woodlands test + brackets by [markjoshwel](https://github.com/markjoshwel) in [#14](https://github.com/markjoshwel/surplus/pull/14)
- s+: display county before state by [markjoshwel](https://github.com/markjoshwel) in [#15](https://github.com/markjoshwel/surplus/pull/15)
<https://github.com/markjoshwel/surplus/compare/v1.1.2...v1.1.3>
---
## surplus v1.1.2
(released on the 18th of June 2023)
general output fixes and quality of life updates
- do not repeat details by [markjoshwel](https://github.com/markjoshwel) in #9
- add -v/--version flag by [markjoshwel](https://github.com/markjoshwel) in #11
<https://github.com/markjoshwel/surplus/compare/v1.1.0...v1.1.1>
---
## surplus v1.1.1
(released on the 16th of June 2023)
### changes
fixes and output tweaks
- fix reverser returning a None location by [shamsu07](https://github.com/shamsu07) in #5
### thanks!
- [shamsu07](https://github.com/shamsu07) made their first contribution!
<https://github.com/markjoshwel/surplus/compare/v1.1.0...v1.1.1>
---
## surplus v1.1.0
(released on the 3rd of June 2023)
short code and latitude longitude coordinate pair support!
- code: s+ alternative shorthand script
- code: handle none/list locations
- code: query by lat long support
- code: support shortcodes with localities
- code: implement more address detail tags from nominatim
- meta: slsa 3 compliance
<https://github.com/markjoshwel/surplus/compare/v1.0.0...v1.1.0>
---
## surplus v1.0.0
initial release on the 2nd of June 2023

80
docs/contributing.md Normal file
View file

@ -0,0 +1,80 @@
# the contributor's handbook
expected details on development workflows? see [the developer's handbook](developing.md)
## which forge do i use?
as at the time of writing this documentation, i am actively using both
<https://github.com/markjoshwel/surplus> and <https://forge.joshwel.co/mark/surplus>
use whatever is more comfortable to you. do you not like microsoft and/or have moved away from github?
feel free to use <https://forge.joshwel.co>. don't want to make an account for either? did the forge
implode and is down? okay! mail in a git patch at <mark@joshwel.co>
## git workflow
1. fork the repository and branch off from the `future` branch,
or `main` if not available
2. make and commit your changes!
3. pull in any changes from upstream, and resolve any conflicts, if any
4. if needed, **commit your copyright waiver** (_see [waiving copyright](#waiving-copyright)_)
5. submit a pull request (_or mail in a patch_)
### waiving copyright
!!! danger "Warning"
this section is a **must** to follow if you have modified **any** unlicenced code:
- top-level surplus files (`releaser.py`, etc)
- surplus (`src/surplus`)
- surplus Documentation (`docs/`)
- surplus on wheels (`src/surplus-on-wheels`)
- surplus on wheels: Telegram Bridge (`src/spow-telegram-bridge`)
!!! info
the command to create an empty commit is `git commit --allow-empty`
when contributing your first changes, please include an empty commit for a copyright
waiver using the following message (replace `Your Name` with your name or username):
```text
Your Name Copyright Waiver
I dedicate any and all copyright interest in this software to the
public domain. I make this dedication for the benefit of the public at
large and to the detriment of my heirs and successors. I intend this
dedication to be an overt act of relinquishment in perpetuity of all
present and future rights to this software under copyright law.
To the best of my knowledge and belief, my contributions are either
originally authored by me or are derived from prior works which I have
verified are also in the public domain and are not subject to claims
of copyright by other parties.
To the best of my knowledge and belief, no individual, business,
organization, government, or other entity has any copyright interest
in my contributions, and I affirm that I will not make contributions
that are otherwise encumbered.
```
(from <https://unlicense.org/WAIVER>)
for documentation contributors, if you have contributed a
[legally significant](https://www.gnu.org/prep/maintain/maintain.html#Legally-Significant) or have
repeatedly commited multiple small changes, waive your copyright with the CC0 deed
(replace `Your Name` with your name or username):
```text
Your Name Copyright Waiver
The person who associated a work with this deed has dedicated the work to
the public domain by waiving all of his or her rights to the work worldwide
under copyright law, including all related and neighboring rights, to the
extent allowed by law.
```
(from <https://creativecommons.org/publicdomain/zero/1.0/>)
## reporting incorrect output
TODO

319
docs/developing.md Normal file
View file

@ -0,0 +1,319 @@
# the developers handbook
!!! abstract
i (mark), heavily use nix to manage my projects, either with
[devbox](https://github.com/jetpack-io/devbox) or flakes
if you are going to develop for surplus or its' sibling projects (except surplus on wheels,
which only needs `shfmt` and `shellcheck`), i would recommend you install Nix using
[Determinate Systems' Nix Installer](https://github.com/DeterminateSystems/nix-installer):
```text
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
```
if i, a very very inexperienced Nix and NixOS user to give a rundown on why to use it:
1. **environments and builds are reproducible**
nix is part package manager, operating system (as NixOS), and functional programming
language. because it's functional, having X as an input will always produce Y as an output,
no matter what. even in the event of environmental, social, economic, or structural collapse
**what does this mean for you?**
when i use `nix develop` and you use `nix develop` to start a development environment, your
version of python will be the same as my version of python. your version of go will be same
as my version of go, etc
if i can build it, and the locked inputs of the nix flake are still available on the internet,
you can build it too
2. **the nix store**, located literally at `/nix/store`
it's where it stores every package you need, separate and isolated from other packages.
lets say you have a tool that needs python (3.8), and another tool that needs python (3.11).
nix store will download and store the binaries for both python installations, instead of
sharing the earliest downloaded python version for both tools
**what does this mean for you?**
whatever project you're working on that can use nix for development environments and builds
will not dirty anything else on your system. any build dependencies of surplus provided with
`nix develop` will **not** mess up software installed for other projects or even the system.
neat, if you ask me tbh
**tl;dr**: things will just werk with nix. but if you see all of this and go, "eh. i can manage
what i install.", then power to you! i list down exactly what prerequisite software needs to be
installed for each project anyways, so have fun! (●'◡'●)
## surplus (and Documentation)
### environment setup
!!! note
all prerequisite software are available in a nix flake. if you want a reproducible environment,
run `nix develop --impure` in the repository root
- for NixOS users, [nix-ld](https://github.com/Mic92/nix-ld) is needed. if you use flakes to
declare your system, follow accordingly. else, use `/etc/nixos/configuration.nix`
for NixOS-on-WSL users, use [nix-ld-rs](https://github.com/nix-community/nix-ld-rs)
once you're done installing `nix-ld` or `nix-ld-rs`,
don't forget to run `sudo nixos-rebuild switch`
prerequisite software:
- [Python](https://www.python.org/downloads/), 3.11 or newer
- [Hatch](https://hatch.pypa.io/latest/): dependency management and build tool
to start a development environment:
```text
hatch shell
```
for docs:
```text
hatch -e docs shell
```
### workflow for python code
TODO
### workflow for markdown documentation
run the documentation server with:
```text
hatch run docs:serve
```
i personally don't use a linter for markdown files, if it looks good on my code editor, then
whatever. if you're going to contribute back, i ask for three things:
- run it through a spell checker or something similar
- line limit of 100
- should be readable as-is on a code editor, **not the markdown preview pane**.
my stance is, if you can afford a fancy preview of the markdown file, use the nice-ned
documentation website. else, read it as a plaintext file
(make it look pretty on the doc site and in plaintext)
---
## surplus on wheels
### environment setup
!!! note
all prerequisite software are available in a nix flake. if you want a reproducible environment,
run `nix develop` in `src/surplus-on-wheels`
prerequisite software:
- [shfmt](https://github.com/patrickvane/shfmt): formatter
- [ShellCheck](https://www.shellcheck.net/): static analyser
### workflow
- formatting s+ow:
- run `shfmt s+ow > s+ow.new`
- mv `s+ow.new` into `s+ow`
sometimes when piping shfmt's output immediately into the same file
results in the file being empty :(
- checking s+ow:
- run `shellcheck s+ow`
if there's no output, that means it passed :)
- if commiting back into the repository, try it out on your Termux system for a day or two,
just to make sure it runs correctly
---
## surplus on wheels: Telegram Bridge
### environment setup
!!! note
all prerequisite software are available in a nix flake. if you want a reproducible environment,
run `nix develop` in `src/spow-telegram-bridge`. it uses
[poetry2nix](https://github.com/nix-community/poetry2nix), so you won't need to run
`poetry shell` afterwards. if you've changed the `pyproject.toml` file,
just exit and re-run `nix develop`
prerequisite software:
- [Python](https://www.python.org/downloads/), 3.11 or newer
- [Poetry](https://python-poetry.org/): dependency management and build tool
to start a development environment:
```text
poetry shell
```
### workflow
after modifying,
1. `mypy bridge.py`
2. `ruff format bridge.py`
3. `ruff check bridge.py`
4. [test the binary](#workflow-for-testing-the-binary)
if the bridge behaves nominally, [bump the version](#versioning-surplus-on-wheels-telegram-bridge)
and commit!
---
## surplus on wheels: WhatsApp Bridge
### environment setup
!!! note
all prerequisite software are available in a nix flake. if you want a reproducible environment,
run `nix develop` in `src/spow-whatsapp-bridge`
the flake will pull in the Android SDK and NDK for building on Termux, and as such can only be
ran on `x86_64-linux` and `x86_64-darwin`
prerequisite software:
- [Go](https://go.dev): 1.22 or newer
- [Android NDK](https://developer.android.com/ndk/downloads), if building for Termux
### workflow for modifying bridge code
the bridge's code is just modified [mdtest](https://github.com/tulir/whatsmeow/tree/main/mdtest)
code, and as such, whenever in doubt, do a diff between mdtest and the bridge code
after modifying,
1. [build a binary](#workflow-for-building-a-binary)
2. [test the binary](#workflow-for-testing-the-binary)
3. and if all goes well, [bump the version](#versioning-surplus-on-wheels-whatsapp-bridge)
and commit!
### workflow for bumping dependencies
- check with your editor, plugin, or online if there's newer patch/minor (see
[semantic versioning](https://semver.org/)) versions to update to
- change the `go.mod` accordingly
after bumping,
1. [build a binary](#workflow-for-building-a-binary)
2. [test the binary](#workflow-for-testing-the-binary)
3. and if all goes well, [bump the version](#versioning-surplus-on-wheels-whatsapp-bridge)
and commit!
### workflow for building a binary
ensure you already have c compiler on the system (if you're using `nix develop` then yes you do), then run:
```text
CGO_ENABLED=1 go build
```
nix users can alternatively run:
```text
nix build .#native
```
instructions to build a Termux build are located at the
[bridges' documentation page](onwheels/whatsapp-bridge.md#anywhere-else), however nix users can run
the following instead for a reproducible, deterministic and hermetic build command:
```text
nix build .#termux
```
the resulting build will be in `result/spow-whatsapp-bridge`
### workflow for testing the binary
- test it out, making sure that you write dummy test text to `~/.cache/s+ow/message` before running
the binary
1. run `s+ow-whatsapp-bridge login` first
2. run `s+ow-whatsapp-bridge list` if you don't already have a chat ID
to send the test message to
3. run `s+ow-whatsapp-bridge` type or copy and paste in a `wa:`-prefixed chat ID
after it logs in, and verify it sends
if the bridge behaves nominally, [bump the version](#versioning-surplus-on-wheels-whatsapp-bridge)
and commit!
## workflow for versioning and tagging releases
### versioning surplus
format: `YEAR.MAJOR.MINOR[-PRERELEASE]` ([semantic versioning](https://semver.org/))
example: `2024.0.0`, `2024.0.0-beta`
change: update the `__version__` variable in `src/surplus/surplus.py`
### versioning surplus on wheels
i've tried to make surplus on wheels as reliable as it could be given a POSIX compliant shell and
commands you'd find available on virtually every linux system, Termux included
as such, it doesn't really follow a versioning scheme as it doesn't need to. also there's no
automatic updater for it, which would be overkill anyway
### versioning surplus on wheels: Telegram Bridge
format: `REVISION.YYYY.WW[+BUILD]` ([calendar versioning](https://calver.org/))
example: `2.2024.24`, `2.2024.24+1`
change: `version` key in `src/spow-telegram-bridge/pyproject.toml`
`REVISION` here meaning any general revision/change
the Telegram Bridge relies on [Telethon](https://github.com/LonamiWebs/Telethon/), which also
follows [semantic versioning](https://semver.org/). so, as long as major isn't bumped, or
as long as Telegram doesn't become Discord, the MTProto APIs to talk to Telegram should be
stable.
however because Telethon also relies on a bunch of networking libraries, it made some sense to
still do weekly builds to bump dependencies, getting pipx to download the newest compatible
dependencies as compared to dubiously running some sort of script to `pipx inject` dependencies
under normal circumstances, a non-working version of the bridge would and **should not have a
version bump**. but for any reason if an already tagged bridge is faulty and/or erroneous in
normal/expected usage, add a revision number to the end after a period (see example above)
### versioning surplus on wheels: WhatsApp Bridge
format: `REVISION.YYYY.WW[+BUILD]` ([calendar versioning](https://calver.org/))
example: `2.2024.25`, `2.2024.25+1`
change: `version` attribute of `bridge` attribute set in `src/spow-whatsapp-bridge/flake.nix`
`REVISION` here meaning any general revision/change
the WhatsApp Bridge relies on [whatsmeow](https://github.com/tulir/whatsmeow), a rolling release
library due to the volatile, undocumented nature of WhatsApp's multidevice API and also directly
and indirectly relies on a bunch of networking libraries:
``` title="src/spow-whatsapp-bridge/go.mod"
--8<-- "src/spow-whatsapp-bridge/go.mod"
```
as such, it uses a calendar versioning scheme and is built weekly
under normal circumstances, a non-working version of the bridge would and **should not have a
version bump**. but for any reason if an already tagged bridge is faulty and/or erroneous in
normal/expected usage, add a revision number to the end after a period (see example above)
---
## i've made my changes. what now?
if you're contributing back to surplus and/or the sibling projects, firstly, thanks!
see [the contributor's handbook](contributing.md) for what's next

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/GeistVF.woff2 Normal file

Binary file not shown.

92
docs/fonts/LICENSE.txt Normal file
View file

@ -0,0 +1,92 @@
Copyright (c) 2023 Vercel, in collaboration with basement.studio
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION AND CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

42
docs/index.md Normal file
View file

@ -0,0 +1,42 @@
# surplus (s+)
surplus (s+) is a Python script to convert [Google Maps Plus Codes](https://maps.google.com/pluscodes/)
to iOS Shortcuts-like shareable text
!!! tip
termux users can consider [surplus on wheels](onwheels/index.md), a sibling project that allows
you to run surplus regularly throughout the day and send it to someone on a messaging platform
!!! important
python 3.11 or later is required due to a bug in earlier versions
[(python/cpython#88089)](https://github.com/python/cpython/issues/88089)
install surplus with pip, or [pipx](https://pipx.pypa.io/) (recommended):
```text
pipx install surplus
```
then, use the `surplus` command, or its `s+` shorthand:
```text
$ s+ 7RGX+GJ Singapore
surplus version 2024.0.0
Singapore Conference Hall
7 Shenton Way
068809
Central, Singapore
```
the types of queries you can pass in are:
- full-length Plus Codes
`6PH58QMF+FX`
- shortened Plus Codes / 'local codes'
`8QMF+FX Singapore`
- latitude and longitude coordinate pairs
`1.3336875, 103.7749375`
- string queries
`Wisma Atria`
or, alternatively pass in `-` to read from stdin

113
docs/licences.md Normal file
View file

@ -0,0 +1,113 @@
# licences
## [surplus](index.md)
**The Unlicence**
surplus is free and unencumbered software released into the public domain:
``` title="src/surplus/UNLICENCE"
--8<-- "src/surplus/UNLICENCE"
```
however, the dependencies surplus relies on are licenced under different, but still permissive
and open-source licences:
- [**geopy**](https://pypi.org/project/geopy/) —
Python Geocoding Toolbox
MIT Licence
- [**geographiclib**](https://pypi.org/project/geographiclib/) —
The geodesic routines from GeographicLib
MIT Licence
- [**pluscodes**](https://pypi.org/project/pluscodes/) —
Compute Plus Codes (Open Location Codes)
Apache 2.0
---
## [surplus on wheels](onwheels/index.md)
**The Unlicence**
surplus on wheels is free and unencumbered software released into the public domain:
``` title="src/surplus-on-wheels/UNLICENCE"
--8<-- "src/surplus-on-wheels/UNLICENCE"
```
---
## [surplus on wheels: WhatsApp Bridge](onwheels/whatsapp-bridge.md)
**Mozilla Public Licence 2.0**
the s+ow WhatsApp Bridge is based off of mdtest code from the
[whatsmeow](https://github.com/tulir/whatsmeow) project, which is licenced under the Mozilla
Public Licence 2.0:
``` title="src/spow-whatsapp-bridge/LICENCE"
--8<-- "src/spow-whatsapp-bridge/LICENCE"
```
the direct dependencies s+ow-whatsapp-bridge relies on are licenced under different, but still
permissive and open-source licences:
- [**whatsmeow**](https://github.com/tulir/whatsmeow) —
Go library for the WhatsApp web multidevice API
Mozilla Public Licence 2.0
---
## [surplus on wheels: Telegram Bridge](onwheels/telegram-bridge.md)
**The Unlicence**
the s+ow Telegram Bridge is free and unencumbered software released into the public domain:
``` title="src/spow-telegram-bridge/UNLICENCE"
--8<-- "src/spow-telegram-bridge/UNLICENCE"
```
however, the direct dependencies surplus relies on are licenced under different, but still
permissive and open-source licences:
- [**Telethon**](https://pypi.org/project/Telethon/) —
Pure Python 3 MTProto API Telegram client library, for bots too!
MIT Licence
---
## [surplus documentation](index.md)
**CC0 1.0 Universal**
the textual contents of surplus documentation by [Mark Joshwel](https://joshwel.co) is marked
with [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/).
to view a copy of this licence, visit <https://creativecommons.org/publicdomain/zero/1.0/>
``` title="docs/CC0"
--8<-- "docs/CC0"
```
the fonts the documentation website relies on are licenced under different, but still
permissive and open-source licences:
- [**Geist and Geist Mono**](https://github.com/vercel/geist-font)
SIL Open Font Licence 1.1
``` title="docs/fonts/LICENSE.txt"
--8<-- "docs/fonts/LICENSE.txt"
```
the direct software dependencies the documentation are also licenced under different, but still
permissive and open-source licences:
- [**mkdocs-material**](https://squidfunk.github.io/mkdocs-material/) —
Documentation that simply works
MIT Licence
- [**mkdocs**](https://www.mkdocs.org/) —
Project documentation with Markdown
BSD-2-Clause Licence

59
docs/links.md Normal file
View file

@ -0,0 +1,59 @@
# backup links
for when first-party links like <https://surplus.joshwel.co> and <https://forge.joshwel.co> are down:
## surplus
``` title="Primary Link"
https://forge.joshwel.co/mark/surplus.git
```
``` title="Alternative Link"
https://github.com/markjoshwel/surplus.git
```
## surplus on wheels
- shell script
``` title="Primary Link"
https://surplus.joshwel.co/spow.sh
```
``` title="Alternative Link"
https://raw.githubusercontent.com/markjoshwel/surplus/main/src/surplus-on-wheels/s+ow
```
- termux installation script
``` title="Primary Link"
https://surplus.joshwel.co/termux.sh
```
``` title="Alternative Link"
https://raw.githubusercontent.com/markjoshwel/surplus/main/src/surplus-on-wheels/install.sh
```
## surplus on wheels: Telegram Bridge
- install/update script:
``` title="Primary Link"
https://surplus.joshwel.co/telegram.sh
```
``` title="Alternative Link"
https://raw.githubusercontent.com/markjoshwel/surplus/main/src/spow-telegram-bridge/install.sh
```
## surplus on wheels: WhatsApp Bridge
- install/update script:
``` title="Primary Link"
https://surplus.joshwel.co/whatsapp.sh
```
``` title="Alternative Link"
https://raw.githubusercontent.com/markjoshwel/surplus/main/src/spow-whatsapp-bridge/install.sh
```

58
docs/onwheels/bridges.md Normal file
View file

@ -0,0 +1,58 @@
# surplus on wheel bridges
## official bridges
there are two currently “official” bridges:
- [surplus on wheels: WhatsApp Bridge](whatsapp-bridge.md)
- [surplus on wheels: Telegram Bridge](telegram-bridge.md)
## bring your own bridge
### an informal specification
s+ow bridges are relatively simple as they are:
1. an executable or script
2. that reads in `SPOW_TARGETS` given by surplus to the bridge, using the standard input (stdin)
stream
1. bridges do not need to account for the possibility of multiple lines sent to stdin
2. bridges should account for the possibility of comma and space (`", "` instead of just `","`)
delimited targets, and strip each target of preceding and trailing whitespace
3. bridges should recognise a platform based on a prefix
(e.g. `wa:` for WhatsApp, `tg:` for Telegram, etc.)
3. reads `SPOW_MESSAGE` (`~/.cache/spow/message`) for the message content
notes:
1. stderr and stdout are redirected to s+ows error and output logs respectively unless the
`-p / --private` flag is passed to surplus
2. any errors encountered by the bridge should always result in a non-zero return. error logs will
show the exact error code, so feel free to use other numbers than 1
3. persistent data such as credentials and session data storage are to be handled by the
bridge itself. consider storing them in `$HOME/.local/share/<bridge-name>/`, or wherever
appropriate
### example
if i were to recommend an example on a basic bridge implementation, it would be the
[Telegram Bridge](telegram-bridge.md):
```python title="src/spow-telegram-bridge/bridge.py"
--8<-- "src/spow-telegram-bridge/bridge.py"
```
!!! note
the feature of deleting the last sent message (`--delete-last`) is a non-standard feature for
bridges, and was simply a use case i personally needed. if you're going to implement a bridge,
all you really need is the ability to `login`, `logout`, and [send a message](#an-informal-specification)
you can add other features as per the needs of your platform, like how the WhatsApp Bridge has
a `pair-phone` subcommand, or per your use case needs, like in the Telegram Bridge's `--delete-last`.

View file

@ -0,0 +1,43 @@
# emulating `termux-location`
to bodge surplus on wheels (s+ow) on non-Termux systems
!!! note
dummy admonition for colour matching
!!! warning
dummy admonition for colour matching
`termux-location`, part of [Termux:API](https://wiki.termux.com/wiki/Termux:API), gets the device's
location via android apis and returns a json response through stdout:
```text
{
"latitude": 1.3277513,
"longitude": 103.678317,
"altitude": 51.6298828125,
"accuracy": 48.46337890625,
"vertical_accuracy": 38.4659423828125,
"bearing": 0.0,
"speed": 0.0,
"elapsedMs": 28,
"provider": "gps"
}
```
see <https://wiki.termux.com/wiki/Termux-location> for more information
## implementing for surplus on wheels (s+ow)
s+ow will call the command a total of six times, being three pairs of parallel
`$LOCATION_CMD -p "network"` and `$LOCATION_CMD -p "gps"` invocations, before deciding after
exhausting all six runs on which output to choose, if any command runs were successful
even if somewhere in the termux-location implementation fails, it always (begrudgingly) returns
zero. s+ow will treat the invocation of the command as successful if there is **any output** to
the standard output (stdout) stream
## implementing for surplus (s+)
s+, when passed `--t / --using-termux-location`, will consume stdin, parse it as json and then
attempt to retrieve the `latitude` and `longitude` keys as floating point numbers

View file

@ -0,0 +1,46 @@
# emulating `termux-notification`
to bodge surplus on wheels (s+ow) on non-Termux systems
`termux-notification`, part of [Termux:API](https://wiki.termux.com/wiki/Termux:API), sends out an
android notification
without `termux-notification`, s+ow will still run as it doesn't use `set -e` and very carefully
handles all command invocations, with `termux-notification` being the graceful exception\
however, if you would like to emulate it, make an executable globally reachable with the same name
s+ow uses the command as such:
```shell
termux-notification \
--priority "default" \
--title "surplus on wheels: No bridges" \
--content "No '$SPOW_BRIDGES' file; message is not sent."
```
```shell
termux-notification \
--priority "min" \
--ongoing \
--id "s+ow" \
--title "surplus on wheels" \
--content "s+ow has started running."
```
```shell
termux-notification \
--priority "min" \
--id "s+ow" \
--title "surplus on wheels" \
--content ...
```
```shell
termux-notification \
--priority "default" \
--title "surplus on wheels has errored" \
--content ...
```
see <https://wiki.termux.com/wiki/Termux-notification> for more information

329
docs/onwheels/index.md Normal file
View file

@ -0,0 +1,329 @@
# surplus on wheels (s+ow)
surplus on wheels is a pure shell script to get your location using
[termux-location](https://wiki.termux.com/wiki/Termux-location), process it through surplus, and
send it to messaging service or wherever using “bridges”
surplus was made to emulate sending your location through the iOS Shortcuts app, and surplus on
wheels complements it by running surplus automatically using a cron job.
(but using it manually also works!)
## installing
!!! important
s+ow is a Termux-first script, and will not work anywhere else unless you have
a utility that emulates [termux-location](https://wiki.termux.com/wiki/termux-location)
on `$PATH` alongside bridges that supports your platform
there are two notable ways to install s+ow:
1. [as a standalone script](#as-a-standalone-script)
2. or, [as a cron job](#as-a-cron-job)
there is also an [installation script](#using-installation-scripts) for quickly getting
started from a _fresh_ termux installation
### as a standalone script
1. firstly install python and termux-api if you haven't already:
```text
pkg install python termux-api
```
also install the accompanying Termux:API app from [F-Froid](https://f-droid.org/en/packages/com.termux.api/)
2. install pipx if you haven't already:
```text
pip install pipx
```
3. install surplus:
```text
pipx install surplus
```
4. install surplus on wheels:
```text
mkdir -p ~/.local/bin/
wget -O ~/.local/bin/s+ow https://surplus.joshwel.co/spow.sh
chmod +x ~/.local/bin/s+ow
```
!!! note
if `wget` throws a 404, see [backup links](../links.md)
if `~/.local/bin` is not in your `$PATH`, add the following to your shell's rc file:
```shell
export PATH="$HOME/.local/bin:$PATH"
```
et voilà! s+ow is now setup. to actually send the message to a messaging platform,
[install an appropriate bridge](bridges.md)
### as a cron job
!!! important
these instructions rely on following the [previous instructions](#as-a-standalone-script)
1. install necessary packages to run cron jobs:
```text
pkg install cronie termux-services
```
2. restart termux and start the cron service:
```text
sv-enable cron
```
3. set up the cron job:
run the following command:
```text
crontab -e
```
and add the following text:
```text
59 * * * * bash -l -c "(SPOW_TARGETS="" SPOW_CRON=y s+ow)"
```
!!! important
minimally fill in the `SPOW_TARGETS` variable before running s+ow.
[(see usage for more info)](#usage)
this will run s+ow every hour, a minute before the hour
modify the variables as per your needs.
see [usage](#usage) for more information
et voilà! s+ow will now send a message every hour. feel free to experiment with the cron
job to your liking. see [crontab.guru](https://crontab.guru/) if youre new to cron jobs
if you havent already, [install an appropriate bridge](bridges.md) to actually send a
message to a messaging platform
### using installation scripts
!!! warning
these scripts assume you're starting from a fresh base installation of Termux.
if you have already cron jobs, then manually carry out the instructions in
'[as a cron job](#as-a-cron-job)'
!!! important
if not installed already, install
[Termux:API from F-Droid](https://f-droid.org/en/packages/com.termux.api/), **not the Play Store**
1. setup s+ow:
```text
wget -O- https://surplus.joshwel.co/termux.sh | sh
```
!!! note
if `wget` throws a 404, see [backup links](../links.md)
2. restart termux!
3. and finally, [set up a cron job](#as-a-cron-job) from step 3 onwards ('set up the cron job')
## usage
### environment variables
s+ow's behaviour can be customised environment variables, with `SURPLUS_CMD` being the only
required variable:
1. `SPOW_TARGETS`
a single line of comma-delimited chat IDs with bridge prefixes
```text
wa:000000000000000000@g.us,tg:-0000000000000000000,...
```
in the example above, the WhatsApp chat ID is `wa:`-prefixed as recognised by the
[spow-whatsapp-bridge](whatsapp-bridge.md), and the
Telegram chat ID is `tg:`-prefixed as recognised by the
[spow-telegram-bridge](telegram-bridge.md)
2. `SPOW_CRON` (optional)
set as non-empty to declare that s+ow is being run as a cron job
if running as a cron job, start s+ow one minute earlier than intended to account for the time
it takes to run `termux-location` and `surplus`. s+ow assumes this and delays itself
appropriately
setting it to `n` will also be treated as if it were empty
3. `SPOW_PRIVATE` (optional)
set as non-empty to discard all logs when s+ow is done:
- `$HOME/.cache/s+ow/out.log` will be set to `/dev/null`
- `$HOME/.cache/s+ow/err.log` will be set to `/dev/null`
- `$HOME/.cache/s+ow/location.net.json` will be cleared after use locating the device
- `$HOME/.cache/s+ow/location.gps.json` will be cleared after use locating the device
- `$HOME/.cache/s+ow/location.json` will be cleared after use locating the device
- `$HOME/.cache/s+ow/surplus.out.log` will be cleared after use generating the message
- `$HOME/.cache/s+ow/surplus.err.log` will be set to `/dev/null`
- `$HOME/.cache/s+ow/message` will be cleared after all bridges has sent the message
!!! warning
the only file not cleared is s+ow's last successful message file, `$HOME/.cache/s+ow/last`,
as s+ow uses this as the first fallback message if it couldn't locate the device in time.
if you're fine with using the `LOCATION_FALLBACK` string, feel free to modify your
cron job to remove this file after running s+ow
setting it to `n` will also be treated as if it were empty
4. `SURPLUS_CMD` (optional)
the custom invocation used when calling surplus, modify this if you want to add certain flags
this defaults to `surplus -td`
!!! warning
when overriding, ensure you also have `-td` (`--using-termux-location` and `--debug`) in
your custom invocation!
5. `LOCATION_CMD` (optional)
the custom invocation used when calling `termux-location`, modify this if you want to bodge
together surplus on wheels on non-termux systems.
see ([emulating `termux-location`](emulating-termux-location.md)) for more information
this defaults to `termux-location`
6. `LOCATION_PRIORITISE_NETWORK` (optional)
set as non-empty to declare that s+ow can just use network location instead of GPS
if GPS is taking too long.
you should only turn this on if punctuality means that much to you, or youre in a
country with cell towers close by or everywhere, like Singapore
the JIDs can be obtained by sending a message to the user/group, while running
`s+ow mdtest`, and examining the output for your message. JIDs are email address-like
strings
setting it to `n` will also be treated as if it were empty
7. `LOCATION_TIMEOUT` (optional)
set as a number to override the default first location timeout of `50`
8. `LOCATION_FALLBACK` (optional)
a string that can be formatted with three numbers using `%d`:
1. s+ow's status
2. number of location attempts before giving up
3. type of message sent
see [details on notification numbers](#details-on-notification-numbers) for the meanings of
each number. 'a', 'b' and 'c' map to `A`, `B` and `C`
defaults to `%d%d%d?`
### faking locations
> sometimes you gotta do what you gotta do
you can fake your s+ow messages by either:
1. setting a dummy `last` file in s+ow cache
`$HOME/.cache/s+ow/last` is used as the fallback response when a part of s+ow (either
`termux-location` or `surplus` errors out). you can set this file to whatever you want
and just turn off location on your device
2. setting a `fake` file in s+ow cache
!!! warning
s+ow uses the `read` command to read the file. as such, it is possible for s+ow to
prematurely stop reading the file if the file does not contain a trailing newline.
you can also write text to `$HOME/.cache/s+ow/fake` to fake upcoming messages. the file
is delimited by empty lines. as such, arrange the file like so:
```text
The Clementi Mall
3155 Commonwealth Avenue West
Westpeak Terrace
129588
Southwest, Singapore
Westgate
3 Gateway Drive
Jurong East
608532
Southwest, Singapore
...
```
on every run of s+ow, the first group of lines will be consumed, and the file will be
updated with the remaining lines. if the file is empty, it will be deleted
### details on notification numbers
after each run, or if s+ow had to use a location fallback string, s+ow notifies you:
!!! abstract "surplus on wheels"
Run has finished.
Singapore Conference Hall
7 Shenton Way
068809
Central, Singapore
(A, B, C, D<E>)
[lc:W sp:X sm:Y - Z]
!!! abstract "surplus on wheels has errored"
(A, B, C, D<E>)
[lc:W sp:X sm:Y - Z]
the top line denotes general statuses:
- `A`: s+ow's status
- `0` is nominal
- `1` is a termux-location error
- `2` is a surplus error
- `3` is a bridge/message send error
- `B`: number of location attempts before giving up
- `C`: type of message sent
- `0` for freshly made sharetext
- `1` for recycling a previous successful location sharetext (`last` file)
- `2` for using fallback template
- `D`: number of bridge failures
- `E`: each bridge's return code
the bottom line details on how long s+ow spent on each stage:
- `W`: time to locate
- `X`: time to run surplus
- `Y`: time to send message(s)
- `Z`: total run time
## help! a bridge isn't working!
cool. do the following:
1. log out and log back in and try again
2. if that didn't fix it, update/reinstall the bridge and try again
3. run the bridge's executable directly to see if there's any connection issues
look at your bridge's installation instructions to find out where it's located at.
or, use the `which` command
4. if it connected successfully, or you see no errors, try typing in one of the targets you've set
in `SPOW_TARGETS` for the bridge, and then press the enter/return key
!!! failure
on the off chance you reinstalled the bridge, and it still failed either step 3 or 4, the bridge
itself is faulty. file a bug report/issue with the bridge's project page or maintainer and tell
them where it failed (was it connecting to the messaging service? or failure to send a message?)

View file

@ -0,0 +1,101 @@
# surplus on wheels: Telegram Bridge
Telegram Bridge for surplus on wheels (s+ow)
s+ow bridges are defined in a file named `$HOME/.s+ow-bridges`. each command in the file is run,
and comma-seperated target chat IDs are passed using stdin.
this bridge recognises targets prefixed with `tg:`.
```text
tg:<chat id>,...
```
## installation
!!! important
the following instructions implies that [surplus](../index.md) and [surplus on wheels](bridges.md)
have already been installed
1. install prerequisite software if not installed:
```text
pkg install git
```
```text
pip install pipx
```
2. install spow-telegram-bridge:
```text
wget -O- https://surplus.joshwel.co/telegram.sh | sh
```
!!! note
if `wget` throws a 404, see [backup links](../links.md)
3. add the following to your `$HOME/.s+ow-bridges` file:
```text
SPOW_TELEGRAM_API_HASH="" SPOW_TELEGRAM_API_ID="" s+ow-telegram-bridge
```
fill in SPOW_TELEGRAM_API_HASH and SPOW_TELEGRAM_API_ID accordingly.
see the [Telethon docs](https://docs.telethon.dev/en/stable/basic/signing-in.html) for
more information
to keep up to date, look at [updating](#updating) to set up a daily update cron job:
## updating
the installation script also sets up a shell script under the `s+ow-telegram-bridge-update` command
```text
s+ow-telegram-bridge-update
```
to do this automatically, make a cron job with `crontab -e`
and make a new line with the following text:
```text
0 0 * * * bash -l -c "s+ow-telegram-bridge-update"
```
this cron job will run the command every day at midnight
## usage
- `s+ow-telegram-bridge`
normal usage; sends latest message to tg:-prefixed targets given in stdin
- `s+ow-telegram-bridge login`
logs in to Telegram
- `s+ow-telegram-bridge logout`
logs out of Telegram
- `s+ow-telegram-bridge list`
lists all chats and their IDs
optional arguments:
- `--silent`
asks telegram to send message silently
- `--delete-last`
deletes last location message to prevent clutter
## versioning scheme
from `v2.2024.27`, the Telegram Bridge will automatically release a new version once a week if there
are updates to its dependencies
as such, the bridge is now versioned with a modified calendar versioning scheme of
`MAJOR.YEAR.ISOWEEK`, where the `MAJOR` version segment will be bumped with codebase changes, whereas
the `YEAR` and `ISOWEEK` segments will represent the time of which the release was built at
## licence
the s+ow Telegram Bridge is free and unencumbered software released into the public domain.
for more information, see [licences](../licences.md).

View file

@ -0,0 +1,210 @@
# surplus on wheels: WhatsApp Bridge
WhatsApp Bridge for surplus on wheels (s+ow)
s+ow bridges are defined in a file named `$HOME/.s+ow-bridges`. each command in the file is run,
and comma-seperated target chat IDs are passed using stdin.
this bridge recognises targets prefixed with `wa:`.
```text
wa:<chat id>,...
```
## installation
### from a pre-built binary
```text
wget -O- https://surplus.joshwel.co/whatsapp.sh | sh
```
!!! note
if `wget` throws a 404, see [backup links](../links.md)
### building from source
#### on Termux
1. clone the repository at either `https://forge.joshwel.co/mark/surplus` or
`https://github.com/markjoshwel/surplus`, and navigate to `src/spow-whatsapp-bridge` within the
cloned repository
```text
git clone https://forge.joshwel.co/mark/surplus
cd surplus/src/spow-whatsapp-bridge
```
2. build the bridge:
```text
go build
```
for compatibility with the documentations' instructions as-is, rename the built binary to
`s+ow-whatsapp-bridge`
```text
mv spow-whatsapp-bridge s+ow-whatsapp-bridge
```
3. send the built binary over to your Termux environment, and then move it into the
`$HOME/.local/bin/` folder. if it doesn't exist, make it with `mkdir` and ensure that the folder
is in your `PATH` variable either using your `.profile`, `.bashrc` or whatever file is sourced
when opening your shell
#### anywhere else
for usage on Termux, see if the [Android NDK](https://developer.android.com/ndk/downloads) supports your platform
1. grab a copy of the NDK, and extract it somewhere. navigate to
`<ndk folder>/toolchains/llvm/prebuilt/<your platform>/bin` and look for a suitable `clang`
executable, as it will be your CGO compiler
```
m@csp:~/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin$ ls *clang
aarch64-linux-android21-clang aarch64-linux-android30-clang ...
aarch64-linux-android22-clang aarch64-linux-android31-clang
aarch64-linux-android23-clang aarch64-linux-android32-clang
aarch64-linux-android24-clang aarch64-linux-android33-clang
aarch64-linux-android25-clang aarch64-linux-android34-clang
aarch64-linux-android26-clang armv7a-linux-androideabi21-clang
aarch64-linux-android27-clang armv7a-linux-androideabi22-clang
aarch64-linux-android28-clang armv7a-linux-androideabi23-clang
aarch64-linux-android29-clang armv7a-linux-androideabi24-clang
```
the example output is not exhaustive and is cut short for brevity and example, do take a look
at your downloaded NDK archive for what executables are available to you
many executables are present, so choose a) what architecture you will build for (more often
than not it's `aarch64`), and b) what target android api are you building for
if you're building for yourself, pick an api level/version that correlates to your devices'
android version. as an example, my device runs on an ARM processor (`aarch64`) and runs Android 14,
which is api level 34. (`android34`) as such, i would use the `aarch64-linux-android34-clang`
binary
2. clone the repository at either `https://forge.joshwel.co/mark/surplus` or
`https://github.com/markjoshwel/surplus`, and navigate to `src/spow-whatsapp-bridge` within the
cloned repository
```text
git clone https://forge.joshwel.co/mark/surplus
cd surplus/src/spow-whatsapp-bridge
```
3. build the bridge:
```text
CC="<path to android ndk clang executable>" GOOS=android GOARCH=arm64 CGO_ENABLED=1 go build
```
for compatibility with the documentations' instructions as-is, rename the built binary to
`s+ow-whatsapp-bridge`
```text
mv spow-whatsapp-bridge s+ow-whatsapp-bridge
```
4. send the built binary over to your Termux environment, and then move it into the
`$HOME/.local/bin/` folder. if it doesn't exist, make it with `mkdir` and ensure that the folder
is in your `PATH` variable either using your `.profile`, `.bashrc` or whatever file is sourced
when opening your shell
### post-installation setup
1. log into WhatsApp:
```text
s+ow-whatsapp-bridge login
```
give it a minute or two to sync your history. once the screen stops scrolling, you can safely
exit with Ctrl+D or Ctrl+C.
2. find out what chats you want the bridge to target:
```text
s+ow-whatsapp-bridge list
```
!!! note
for sending to individuals: their IDs are their internationalised phone numbers ending in
`@s.whatsapp.net`
example: `+65 9123 4567` is `6591234567@s.whatsapp.net`
then, note these down, prefixed with `wa:`, to them to your `SPOW_TARGETS` variable in your
s+ow cron job
3. finally, add the following to your $HOME/.s+ow-bridges file:
```text
s+ow-whatsapp-bridge
```
## updating
to keep updated as [whatsmeow](https://github.com/tulir/whatsmeow/), the library the bridge depends
on, has to keep updated with the WhatsApp web multidevice API, you can either:
1. [rebuild when a weekly release comes out](#building-from-source),
2. [or rely on the weekly continuous deployment builds](#from-a-pre-built-binary)
to use the weekly builds without building from scratch every time,
!!! note
this will pull the latest binary, around 20 megabytes in size, every day. if your network or
data plan may not take kindly to this, feel free to adjust the cron entry as you wish, or to
one that runs once a week instead:
```text
0 0 * * 0 bash -l -c "s+ow-whatsapp-bridge-update"
```
## usage
- `s+ow-whatsapp-bridge`
normal usage; sends latest message to wa:-prefixed targets given in stdin
- `s+ow-whatsapp-bridge login`
logs in to WhatsApp
- `s+ow-whatsapp-bridge pair-phone`
logs in to WhatsApp using a phone number
- `s+ow-whatsapp-bridge reconnect`
reconnects the client
- `s+ow-whatsapp-bridge logout`
logs out of WhatsApp
- `s+ow-whatsapp-bridge list`
lists all group chats and their IDs.
for sending to individuals: their IDs are their internationalised phone numbers ending in
`@s.whatsapp.net`
example: `+65 9123 4567` is `6591234567@s.whatsapp.net`
## verifying a pre-built binary
!!! note
if you installed the bridge through an installation script, it would have already
and if the script or `s+ow-whatsapp-bridge-update` throws an error about failing verification,
you can use the environment variable ``
TODO
## versioning scheme
from `v2.2024.25`, the bridge is now versioned with a modified calendar versioning scheme of
`MAJOR.YEAR.ISOWEEK`, where the `MAJOR` version segment will be bumped with codebase changes, whereas
the `YEAR` and `ISOWEEK` segments will represent the time of which the release was built at
## licence
the s+ow Telegram Bridge is free and unencumbered software released into the public domain.
for more information, see [licences](../licences.md).

212
docs/stylesheets/extra.css Normal file
View file

@ -0,0 +1,212 @@
@font-face {
font-family: "Geist";
src: url('../fonts/GeistVF.woff2') format('woff2'),
url('../fonts/Geist-Regular.ttf') format('truetype');
}
@font-face {
font-family: "Geist Mono";
src: url('../fonts/GeistMonoVF.woff2') format('woff2'),
url('../fonts/GeistMono-Regular.ttf') format('truetype');
}
:root {
--md-text-font: "Geist";
--md-code-font: "Geist Mono";
--md-hue: 180deg;
}
* {
text-rendering: geometricprecision !important;
-webkit-font-smoothing: antialiased;
}
[data-md-color-scheme="default"] {
color-scheme: light;
--md-sys-color-primary: rgb(51 71 65);
--md-sys-color-surface-tint: rgb(78 99 92);
--md-sys-color-on-primary: rgb(255 255 255);
--md-sys-color-primary-container: rgb(95 116 109);
--md-sys-color-on-primary-container: rgb(255 255 255);
--md-sys-color-secondary: rgb(61 69 66);
--md-sys-color-on-secondary: rgb(255 255 255);
--md-sys-color-secondary-container: rgb(110 118 115);
--md-sys-color-on-secondary-container: rgb(255 255 255);
--md-sys-color-tertiary: rgb(0 73 93);
--md-sys-color-on-tertiary: rgb(255 255 255);
--md-sys-color-tertiary-container: rgb(65 124 147);
--md-sys-color-on-tertiary-container: rgb(255 255 255);
--md-sys-color-error: rgb(124 37 0);
--md-sys-color-on-error: rgb(255 255 255);
--md-sys-color-error-container: rgb(200 77 28);
--md-sys-color-on-error-container: rgb(255 255 255);
--md-sys-color-background: rgb(251 249 247);
--md-sys-color-on-background: rgb(27 28 27);
--md-sys-color-surface: rgb(251 249 247);
--md-sys-color-on-surface: rgb(27 28 27);
--md-sys-color-surface-variant: rgb(222 228 224);
--md-sys-color-on-surface-variant: rgb(62 68 66);
--md-sys-color-outline: rgb(90 96 94);
--md-sys-color-outline-variant: rgb(118 124 121);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(48 49 48);
--md-sys-color-inverse-on-surface: rgb(242 240 239);
--md-sys-color-inverse-primary: rgb(181 203 195);
--md-sys-color-primary-fixed: rgb(100 121 114);
--md-sys-color-on-primary-fixed: rgb(255 255 255);
--md-sys-color-primary-fixed-dim: rgb(76 96 90);
--md-sys-color-on-primary-fixed-variant: rgb(255 255 255);
--md-sys-color-secondary-fixed: rgb(110 118 115);
--md-sys-color-on-secondary-fixed: rgb(255 255 255);
--md-sys-color-secondary-fixed-dim: rgb(86 94 90);
--md-sys-color-on-secondary-fixed-variant: rgb(255 255 255);
--md-sys-color-tertiary-fixed: rgb(65 124 147);
--md-sys-color-on-tertiary-fixed: rgb(255 255 255);
--md-sys-color-tertiary-fixed-dim: rgb(36 99 121);
--md-sys-color-on-tertiary-fixed-variant: rgb(255 255 255);
--md-sys-color-surface-dim: rgb(219 218 216);
--md-sys-color-surface-bright: rgb(251 249 247);
--md-sys-color-surface-container-lowest: rgb(255 255 255);
--md-sys-color-surface-container-low: rgb(245 243 242);
--md-sys-color-surface-container: rgb(239 238 236);
--md-sys-color-surface-container-high: rgb(233 232 230);
--md-sys-color-surface-container-highest: rgb(228 226 225);
--md-hue: 139.2deg;
--md-default-fg-color: var(--md-sys-color-primary);
--md-default-bg-color: var(--md-sys-color-surface);
/* primary colours */
--md-primary-fg-color: var(--md-sys-color-primary);
--md-primary-fg-color--light: var(--md-sys-color-inverse-primary);
--md-primary-fg-color--dark: var(--md-sys-color-primary-container);
--md-primary-bg-color: var(--md-sys-color-surface);
--md-primary-bg-color--light: var(--md-sys-color-surface-dim);
/* accent (interactable) colours */
--md-accent-fg-color: var(--md-sys-color-tertiary);
--md-accent-bg-color: var(--md-sys-color-on-tertiary);
--md-accent-bg-color--light: var(--md-sys-color-surface-dim);
/* typesetting colours */
--md-typeset-color: var(--md-sys-color-on-surface);
--md-typeset-a-color: var(--md-sys-color-tertiary);
--md-typeset-del-color: var(--md-sys-color-on-error-container);
--md-typeset-ins-color: var(--md-sys-color-on-primary-container);
--md-typeset-kbd-color: var(--md-sys-color-surface-container-lowest);
--md-typeset-kbd-accent-color: var(--md-sys-color-surface-container);
--md-typeset-kbd-border-color: var(--md-sys-color-surface-container-highest);
--md-typeset-mark-color: var(--md-sys-color-tertiary-container);
--md-typeset-table-color: var(--md-sys-color-outline);
--md-code-bg-color: var(--md-sys-color-surface-container-high);
/* admonition colours */
--md-admonition-fg-color: var(--md-sys-color-secondary);
--md-admonition-bg-color: var(--md-default-bg-color);
--md-warning-fg-color: var(--md-sys-color-on-error-container);
--md-warning-bg-color: var(--md-sys-color-error-container);
/* footer colours */
--md-footer-fg-color: var(--md-sys-color-on-surface);
--md-footer-fg-color--light: var(--md-sys-color-on-surface-variant);
--md-footer-fg-color--lighter: var(--md-sys-color-outline);
--md-footer-bg-color: var(--md-sys-color-surface-dim);
--md-footer-bg-color--dark: var(--md-sys-color-surface-container-highest);
}
[data-md-color-scheme="slate"] {
color-scheme: dark;
--md-sys-color-primary: rgb(185 208 199);
--md-sys-color-surface-tint: rgb(181 203 195);
--md-sys-color-on-primary: rgb(6 26 21);
--md-sys-color-primary-container: rgb(128 149 142);
--md-sys-color-on-primary-container: rgb(0 0 0);
--md-sys-color-secondary: rgb(196 205 200);
--md-sys-color-on-secondary: rgb(16 24 21);
--md-sys-color-secondary-container: rgb(138 147 143);
--md-sys-color-on-secondary-container: rgb(0 0 0);
--md-sys-color-tertiary: rgb(153 211 236);
--md-sys-color-on-tertiary: rgb(0 25 34);
--md-sys-color-tertiary-container: rgb(99 157 181);
--md-sys-color-on-tertiary-container: rgb(0 0 0);
--md-sys-color-error: rgb(255 187 164);
--md-sys-color-on-error: rgb(48 9 0);
--md-sys-color-error-container: rgb(237 104 54);
--md-sys-color-on-error-container: rgb(0 0 0);
--md-sys-color-background: rgb(19 20 19);
--md-sys-color-on-background: rgb(228 226 225);
--md-sys-color-surface: rgb(19 20 19);
--md-sys-color-on-surface: rgb(252 250 249);
--md-sys-color-surface-variant: rgb(66 72 70);
--md-sys-color-on-surface-variant: rgb(198 204 200);
--md-sys-color-outline: rgb(158 164 161);
--md-sys-color-outline-variant: rgb(126 132 129);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(228 226 225);
--md-sys-color-inverse-on-surface: rgb(41 42 41);
--md-sys-color-inverse-primary: rgb(56 76 70);
--md-sys-color-primary-fixed: rgb(209 232 223);
--md-sys-color-on-primary-fixed: rgb(2 20 16);
--md-sys-color-primary-fixed-dim: rgb(181 203 195);
--md-sys-color-on-primary-fixed-variant: rgb(38 58 52);
--md-sys-color-secondary-fixed: rgb(220 228 224);
--md-sys-color-on-secondary-fixed: rgb(11 19 16);
--md-sys-color-secondary-fixed-dim: rgb(192 200 196);
--md-sys-color-on-secondary-fixed-variant: rgb(48 56 53);
--md-sys-color-tertiary-fixed: rgb(186 234 255);
--md-sys-color-on-tertiary-fixed: rgb(0 20 27);
--md-sys-color-tertiary-fixed-dim: rgb(149 207 232);
--md-sys-color-on-tertiary-fixed-variant: rgb(0 59 76);
--md-sys-color-surface-dim: rgb(19 20 19);
--md-sys-color-surface-bright: rgb(57 57 56);
--md-sys-color-surface-container-lowest: rgb(13 14 14);
--md-sys-color-surface-container-low: rgb(27 28 27);
--md-sys-color-surface-container: rgb(31 32 31);
--md-sys-color-surface-container-high: rgb(41 42 41);
--md-sys-color-surface-container-highest: rgb(52 53 52);
/*--md-hue: 139.2deg;*/
--md-default-fg-color: var(--md-sys-color-primary);
--md-default-bg-color: var(--md-sys-color-surface);
/* primary colours */
--md-primary-fg-color: var(--md-sys-color-primary);
--md-primary-fg-color--light: var(--md-sys-color-inverse-primary);
--md-primary-fg-color--dark: var(--md-sys-color-primary-container);
--md-primary-bg-color: var(--md-sys-color-surface);
--md-primary-bg-color--light: var(--md-sys-color-surface-dim);
/* accent (interactable) colours */
--md-accent-fg-color: var(--md-sys-color-tertiary);
--md-accent-bg-color: var(--md-sys-color-on-tertiary);
--md-accent-bg-color--light: var(--md-sys-color-surface-dim);
/* typesetting colours */
--md-typeset-color: var(--md-sys-color-on-surface);
--md-typeset-a-color: var(--md-sys-color-tertiary);
--md-typeset-del-color: var(--md-sys-color-on-error-container);
--md-typeset-ins-color: var(--md-sys-color-on-primary-container);
--md-typeset-kbd-color: var(--md-sys-color-surface-container-lowest);
--md-typeset-kbd-accent-color: var(--md-sys-color-surface-container);
--md-typeset-kbd-border-color: var(--md-sys-color-surface-container-highest);
--md-typeset-mark-color: var(--md-sys-color-tertiary-container);
--md-typeset-table-color: var(--md-sys-color-outline);
--md-typeset-table-color--light: var(--md-sys-color-outline-variant);
--md-code-bg-color: var(--md-sys-color-surface-container-high);
/* admonition colours */
--md-admonition-fg-color: var(--md-sys-color-secondary);
--md-admonition-bg-color: var(--md-default-bg-color);
--md-warning-fg-color: var(--md-sys-color-on-error-container);
--md-warning-bg-color: var(--md-sys-color-error-container);
/* footer colours */
--md-footer-fg-color: var(--md-sys-color-on-surface);
--md-footer-fg-color--light: var(--md-sys-color-on-surface-variant);
--md-footer-fg-color--lighter: var(--md-sys-color-outline);
--md-footer-bg-color: var(--md-sys-color-surface-dim);
--md-footer-bg-color--dark: var(--md-sys-color-surface-container-highest);
}

View file

@ -0,0 +1,4 @@
@page {
size: A4;
margin: 1.25cm;
}

11
docs/using.md Normal file
View file

@ -0,0 +1,11 @@
# the user's handbook
TODO
## as a command line tool
TODO
## as a python library
TODO

114
mkdocs.yml Normal file
View file

@ -0,0 +1,114 @@
site_name: surplus Documentation
site_url: https://surplus.joshwel.co
site_author: Mark Joshwel and surplus contributors
site_description: documentation for the surplus and sibling projects
repo_name: markjoshwel/surplus
repo_url: https://github.com/markjoshwel/surplus
copyright: |
with with all our hearts, 2023-2024, mark joshwel and contributors<br>
documentation is dedicated to the public domain with <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>
nav:
- about:
- surplus: "index.md"
- licences: "licences.md"
- changelog: "changelog.md"
- handbooks:
- "using.md"
- "developing.md"
- "contributing.md"
- on wheels:
- "onwheels/index.md"
- bridges:
- about bridges: "onwheels/bridges.md"
- "onwheels/telegram-bridge.md"
- "onwheels/whatsapp-bridge.md"
- "onwheels/emulating-termux-location.md"
- "onwheels/emulating-termux-notification.md"
- backup links:
"links.md"
theme:
name: material
language: en
features:
- navigation.tabs
- navigation.tabs.sticky
- navigation.tracking
- navigation.expand
- toc.integrate
- search.suggest
- search.highlight
- content.tabs.link
- content.code.annotation
- content.code.copy
- pymdownx.snippets
font: false
palette:
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Light Theme
primary: custom
accent: custom
- media: "(prefers-color-scheme: light)"
scheme: default
toggle:
icon: material/brightness-7
name: Dark Theme
primary: custom
accent: custom
- media: "(prefers-color-scheme: dark)"
scheme: slate
toggle:
icon: material/brightness-4
name: System Theme
primary: custom
accent: custom
icon:
admonition:
abstract: material/text-box-outline
tip: material/pencil-outline
note: material/information-slab-box-outline
warning: material/alert-outline
danger: material/alert-octagon-outline
extra_css:
- stylesheets/extra.css
plugins:
- search
- privacy
#- git-revision-date-localized:
# enable_creation_date: true
- exporter:
formats:
pdf:
enabled: !ENV [MKDOCS_EXPORTER_PDF_ENABLED, true]
stylesheets:
- docs/stylesheets/pdf.scss
aggregator:
enabled: true
output: documentation.pdf
buttons:
- title: Download as PDF
icon: material-file-download-outline
enabled: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.enabled
attributes: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.attributes
markdown_extensions:
- admonition
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences

View file

@ -0,0 +1,23 @@
"""
script to copy shell scripts into the docs folder for publishing
src/surplus-on-wheels/s+ow -> docs/spow.sh
src/surplus-on-wheels/termux-s+ow-setup -> docs/termux.sh
src/spow-whatsapp-bridge/install.sh -> docs/whatsapp.sh
src/spow-telegram-bridge/install.sh -> docs/telegram.sh
"""
from pathlib import Path
from shutil import copyfile
repo_root: Path = Path(__file__).parent.parent.parent
docs_path: Path = repo_root.joinpath("docs")
copy_map: dict[Path, Path] = {
repo_root.joinpath("src/surplus-on-wheels/s+ow"): docs_path.joinpath("spow.sh"),
repo_root.joinpath("src/surplus-on-wheels/install.sh"): docs_path.joinpath("termux.sh"),
repo_root.joinpath("src/spow-whatsapp-bridge/install.sh"): docs_path.joinpath("whatsapp.sh"),
repo_root.joinpath("src/spow-telegram-bridge/install.sh"): docs_path.joinpath("telegram.sh"),
}
for target, destination in copy_map.items():
copyfile(target, destination)