1<!--
2SPDX-FileCopyrightText: 2022 Amolith <amolith@secluded.site>
3
4SPDX-License-Identifier: CC0-1.0
5-->
6
7# umu
8[![REUSE status][reuse-shield]][reuse]
9[![Donate with fosspay][fosspay-shield]][fosspay]
10![Time spent on project][wakapi-shield]
11
12Personal shortlink generator
13
14## Features
15Links are …
16- Editable
17- Removable
18- Four characters long (26 uppercase letters + 26 lowercase letters + 10 numbers
19 = 14,776,336 possible shortened URLs)
20
21Service has …
22- A simple API
23- A simple web UI
24- A simple backup procedure (database is a single directory)
25- No user management (this is a *personal* service after all)
26
27## API documentation
28
29### `/create`
30
31#### Required parameters
32- `url`: percent-encoded URL being shortened
33
34#### Optional parameters
35- `name`: percent-encoded short link the `url` will be mapped to. If this is not
36 provided, a random, 4-character code will be generated instead.
37
38#### Output
39- `401 Unauthorized: You do not have permission to create shortlinks` if access
40 token provided in `Authorization` header does not match the configured access
41 token
42- `400 Bad Request: URL parameter is required`
43- `406 Not Acceptable: A shortened URL with this name already exists` if
44 provided name already exists in the database
45- `URL mapped to $NAME` (200 OK)
46
47### `/read`
48
49#### Required parameters
50- None
51
52#### Optional parameters
53- None
54
55#### Output
56- `401 Unauthorized: You do not have permission to view shortlinks` if access
57 token provided in `Authorization` header does not match the configured access
58 token
59- JSON representation of the key/value database (200 OK)
60 ``` json
61 {
62 "6H1g": "https://git.sr.ht/~amolith/umu/tree/dev",
63 "N3yg": "https://secluded.site/"
64 }
65 ```
66
67### `/update`
68
69#### Required parameters:
70- `oldName`: percent-encoded name the URL is *currently* referred to with
71- `name`: percent-encoded name the URL *will* be referred to with
72- `url`: percent-encoded URL being shortened
73
74`name` and `url` are first set as a key/value pair. If `name` already exists,
75`url` is updated. If `name` does *not* already exist, it's created and `oldName`
76is deleted. If the user is only modifying `url`, `oldName` and `name` should
77both be submitted but their values should be identical.
78
79#### Optional parameters:
80- None
81
82#### Output:
83- `401 Unauthorized: You do not have permission to create shortlinks` if access
84 token provided in `Authorization` header does not match the configured access
85 token
86- `400 Bad Request: oldName parameter is required`
87- `400 Bad Request: name parameter is required`
88- `400 Bad Request: URL parameter is required`
89- `406 Not Acceptable: A shortened URL with this name already exists` if
90 provided name already exists in the database
91- `$URL mapped to $NAME` (200 OK)
92
93### `/delete`
94
95#### Required parameters:
96- `name`: percent-encoded short link
97
98#### Optional parameters:
99- None
100
101#### Output:
102- `401 Unauthorized: You do not have permission to create shortlinks` if access
103 token provided in `Authorization` header does not match the configured access
104 token
105- `400 Bad Request: name parameter is required`
106- `$URL has been deleted` (200 OK)
107
108## But … why?
109Good question. URL shorteners are (usually) terrible and useless. Except when
110used correctly :thinkingsmart:
111
112I take a lot of hand-written notes on things and, having both a passion for and
113job in IT, my notes would be much more useful if they included links to the
114things I'm writing about. However, there's no way I'm going to hand-write a 50+
115character URL.
116
117That's where URL shorteners come in!
118
119Most shortener services I've found that are both open source and self-hosted use
120something like 6-character-long paths for the links as they're meant for use by
121multiple people; 14.8m possible URLs (your cap with 4 character paths) aren't
122enough for public services.
123
124Now six characters is *fine* but why write six characters when you could write
125four :D
126
127And why deal with user management and a relational database when you're only
128going to have one user and a bunch of keys with values :D
129
130I was also unsatisfied with the tech stack and feature sets of the alternatives;
131they were all either a pain to set up and update or they had click counters and
132link tracking and a bunch of other crap I have no use for.
133
134So I decided to make my own that has exactly what I want and nothing more :D
135
136## Questions & Contributions
137Questions, comments, and patches can always be sent to my public inbox, but I'm
138also in my IRC channel/XMPP room pretty much 24/7. However, I might not see
139messages right away because I'm working on something else (or sleeping) so
140please stick around!
141
142If you're wanting to introduce a new feature and I don't feel like it fits with
143this project's goal, I encourage you to fork the repo and make whatever changes
144you like!
145
146- Email: [~amolith/public-inbox@lists.sr.ht][email]
147- IRC: [irc.nixnet.services/#secluded][irc]
148- XMPP: [secluded@muc.secluded.site][xmpp]
149
150*If you haven't used mailing lists before, please take a look at [SourceHut's
151documentation](https://man.sr.ht/lists.sr.ht/), especially the etiquette
152section.*
153
154[reuse]: https://api.reuse.software/info/git.sr.ht/~amolith/umu
155[reuse-shield]: https://shields.io/reuse/compliance/git.sr.ht/~amolith/umu
156
157[fosspay]: https://secluded.site/donate/
158[fosspay-shield]: https://shields.io/badge/donate-fosspay-yellow
159
160[wakapi-shield]: https://img.shields.io/endpoint?url=https://waka.secluded.site/api/compat/shields/v1/amolith/interval:any/project:umu&color=blue&label=time%20spent
161
162[email]: mailto:~amolith/public-inbox@lists.sr.ht
163[irc]: irc://irc.nixnet.services/#secluded
164[xmpp]: xmpp:secluded@muc.secluded.site?join