gerador de URLs curtas

This commit is contained in:
Luciano Ramalho
2025-05-22 01:11:34 -03:00
parent 1bd4b1e7be
commit 3d5588b75e
5 changed files with 1051 additions and 1076 deletions

81
links/short.py Executable file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
import itertools
from collections.abc import Iterator
def load_redirects():
redirects = {}
targets = {}
for filename in ('custom.htaccess', 'short.htaccess'):
with open(filename) as fp:
for line in fp:
if line.startswith('RedirectTemp'):
_, short, long = line.split()
short = short[1:] # Remove leading slash
assert short not in redirects, f"{filename}: duplicate redirect from {short}"
# custom is live since 2022, we cannot change it remove duplicate targets
if not filename.startswith('custom'):
assert long not in targets, f"{filename}: Duplicate redirect to {long}"
redirects[short] = long
targets[long] = short
return redirects, targets
SDIGITS = '23456789abcdefghjkmnpqrstvwxyz'
def gen_short() -> Iterator[str]:
"""
Generate every possible sequence of SDIGITS.
"""
length = 1
while True:
for short in itertools.product(SDIGITS, repeat=length):
yield ''.join(short)
length += 1
def shorten(n: int) -> str:
"""
Get Nth short URL made from SDIGITS, where 0 is the first.
"""
iter_short = gen_short()
for i in range(n+1):
short = next(iter_short)
if i == n:
return short
def gen_free_short(redirects: dict) -> Iterator[str]:
"""
Generate next available short URL.
"""
for short in gen_short():
if short not in redirects:
yield short
def new_urls(urls: list[str], redirects: dict, targets: dict) -> None:
iter_short = gen_free_short(redirects)
with open('short.htaccess', 'a') as fp:
for url in urls:
assert 'fpy.li' not in url, f"{url} is a fpy.li URL"
if url in targets:
continue
short = next(iter_short)
redirects[short] = url
targets[url] = short
fp.write(f"RedirectTemp /{short} {url}\n")
def main():
from random import randrange
urls = [f'https://example.com/{randrange(100000)}.html' for n in range(7)]
redirects, targets = load_redirects()
new_urls(urls, redirects, targets)
if __name__ == '__main__':
main()