6
6
This script reads lines from stdin or files named as arguments, then:
7
7
8
8
1. retrieves or creates new short URLs, taking into account existing RedirectTemp
9
- directives in custom.htacess or short.htacess ;
10
- 2. appends RedirectTemp directives for newly created short URLs to short.htacess ;
9
+ directives in custom.htaccess or short.htaccess ;
10
+ 2. appends RedirectTemp directives for newly created short URLs to short.htaccess ;
11
11
3. outputs the list of (short, long) URLs retrieved or created.
12
12
13
13
"""
17
17
from collections .abc import Iterator
18
18
from time import strftime
19
19
20
+ HTACCESS_CUSTOM = 'custom.htaccess'
21
+ HTACCESS_SHORT = 'short.htaccess'
22
+ HTACCESS_FILES = (HTACCESS_CUSTOM ,HTACCESS_SHORT )
20
23
BASE_DOMAIN = 'fpy.li'
21
24
22
- def load_redirects ():
25
+
26
+ def load_redirects ()-> tuple [dict ,dict ]:
23
27
redirects = {}
24
28
targets = {}
25
- for filename in ( 'custom.htaccess' , 'short.htaccess' ) :
29
+ for filename in HTACCESS_FILES :
26
30
with open (filename )as fp :
27
31
for line in fp :
28
32
if line .startswith ('RedirectTemp' ):
29
33
_ ,short ,long = line .split ()
30
34
short = short [1 :]# Remove leading slash
31
- assert short not in redirects ,f" { filename } : duplicate redirect from{ short } "
32
- # custom is live since 2022, wecannot change it remove duplicate targets
33
- if not filename . startswith ( 'custom' ) :
34
- assert long not in targets ,f" { filename } :Duplicate redirect to{ long } "
35
+ assert short not in redirects ,f' { filename } : duplicate redirect from{ short } '
36
+ #htaccess. custom is live since 2022, wecan't change it remove duplicate targets
37
+ if filename != HTACCESS_CUSTOM :
38
+ assert long not in targets ,f' { filename } :duplicate redirect to{ long } '
35
39
redirects [short ]= long
36
40
targets [long ]= short
37
41
return redirects ,targets
@@ -41,9 +45,7 @@ def load_redirects():
41
45
42
46
43
47
def gen_short (start_len = 1 )-> Iterator [str ]:
44
- """
45
- Generate every possible sequence of SDIGITS, starting with start_len
46
- """
48
+ """Generate every possible sequence of SDIGITS, starting with start_len"""
47
49
length = start_len
48
50
while True :
49
51
for short in itertools .product (SDIGITS ,repeat = length ):
@@ -52,22 +54,20 @@ def gen_short(start_len=1) -> Iterator[str]:
52
54
53
55
54
56
def gen_unused_short (redirects :dict )-> Iterator [str ]:
55
- """
56
- Generate next available short URL of len >= 2.
57
- """
57
+ """Generate next available short URL of len >= 2."""
58
58
for short in gen_short (2 ):
59
59
if short not in redirects :
60
60
yield short
61
61
62
62
63
- def shorten (urls :list [str ],redirects :dict ,targets :dict )-> list [tuple [str ,str ]]:
64
- """return (short, long) pairs, appending directives toshort.htaccess as needed"""
63
+ def shorten (urls :list [str ],redirects :dict ,targets :dict )-> list [tuple [str ,str ]]:
64
+ """Return (short, long) pairs, appending directives toHTACCESS_SHORT as needed. """
65
65
iter_short = gen_unused_short (redirects )
66
66
pairs = []
67
67
timestamp = strftime ('%Y-%m-%d %H:%M:%S' )
68
- with open ('short.htaccess' ,'a' )as fp :
68
+ with open (HTACCESS_SHORT ,'a' )as fp :
69
69
for long in urls :
70
- assert BASE_DOMAIN not in long ,f" { long } is a{ BASE_DOMAIN } URL"
70
+ assert BASE_DOMAIN not in long ,f' { long } is a{ BASE_DOMAIN } URL'
71
71
if long in targets :
72
72
short = targets [long ]
73
73
else :
@@ -79,16 +79,16 @@ def shorten(urls: list[str], redirects: dict, targets: dict) -> list[tuple[str,s
79
79
timestamp = None
80
80
fp .write (f'RedirectTemp /{ short } { long } \n ' )
81
81
pairs .append ((short ,long ))
82
-
82
+
83
83
return pairs
84
84
85
85
86
- def main ():
86
+ def main ()-> None :
87
87
"""read URLS from filename arguments or stdin"""
88
- urls = [line .strip ()for line in fileinput .input (encoding = " utf-8" )]
88
+ urls = [line .strip ()for line in fileinput .input (encoding = ' utf-8' )]
89
89
redirects ,targets = load_redirects ()
90
90
for short ,long in shorten (urls ,redirects ,targets ):
91
- print (f'{ BASE_DOMAIN } /{ short } \t { long } ' )
91
+ print (f'{ BASE_DOMAIN } /{ short } \t { long } ' )
92
92
93
93
94
94
if __name__ == '__main__' :